Quellcode durchsuchen

Merge branch 'main' into feature/v1.0.72

yuelujie vor 9 Monaten
Ursprung
Commit
d341d23042
73 geänderte Dateien mit 4511 neuen und 1856 gelöschten Zeilen
  1. 3 2
      apps/bigmember_pc/src/api/modules/search.js
  2. BIN
      apps/bigmember_pc/src/assets/images/channel-1.png
  3. BIN
      apps/bigmember_pc/src/assets/images/channel-2.png
  4. BIN
      apps/bigmember_pc/src/assets/images/channel-3.png
  5. BIN
      apps/bigmember_pc/src/assets/images/icon/fire-icon.png
  6. BIN
      apps/bigmember_pc/src/assets/images/icon/square-up.png
  7. BIN
      apps/bigmember_pc/src/assets/images/medical-field/content.png
  8. 3 3
      apps/bigmember_pc/src/assets/js/selector.js
  9. 7 0
      apps/bigmember_pc/src/assets/style/common.scss
  10. 26 23
      apps/bigmember_pc/src/components/article-item/ArticleItem.vue
  11. 59 36
      apps/bigmember_pc/src/components/filter-items/AmountRangeSelector.vue
  12. 3 2
      apps/bigmember_pc/src/components/filter-items/BasePowerLayout.vue
  13. 126 0
      apps/bigmember_pc/src/components/filter-items/InfoTypeSelector.vue
  14. 418 0
      apps/bigmember_pc/src/components/filter-items/InfoTypeSelectorContent.vue
  15. 48 36
      apps/bigmember_pc/src/components/filter-items/KeywordTagsSelectorContent.vue
  16. 12 1
      apps/bigmember_pc/src/components/filter-items/Layout.vue
  17. 65 6
      apps/bigmember_pc/src/components/filter-items/OnecascadeContent.vue
  18. 23 14
      apps/bigmember_pc/src/components/push-list/PushList.vue
  19. 1 4
      apps/bigmember_pc/src/composables/attachment-download/component/AttachmentDownload.vue
  20. 726 213
      apps/bigmember_pc/src/utils/format/search-bid-filter.js
  21. 0 1
      apps/bigmember_pc/src/views/article-content/components/RecommendOpportunities.vue
  22. 105 100
      apps/bigmember_pc/src/views/collection/components/search-list-table.vue
  23. 41 32
      apps/bigmember_pc/src/views/collection/index.vue
  24. 128 0
      apps/bigmember_pc/src/views/search/bidding/components/current-filter-text.vue
  25. 107 67
      apps/bigmember_pc/src/views/search/bidding/components/history-filter-dialog.vue
  26. 89 47
      apps/bigmember_pc/src/views/search/bidding/components/save-filter-dialog.vue
  27. 79 72
      apps/bigmember_pc/src/views/search/bidding/components/search-bid-filter.vue
  28. 66 15
      apps/bigmember_pc/src/views/search/bidding/components/search-bid-header.vue
  29. 121 107
      apps/bigmember_pc/src/views/search/bidding/components/search-filter-header.vue
  30. 99 100
      apps/bigmember_pc/src/views/search/bidding/components/search-list-table.vue
  31. 60 44
      apps/bigmember_pc/src/views/search/bidding/constant/search-filters.js
  32. 161 112
      apps/bigmember_pc/src/views/search/bidding/index.vue
  33. 34 16
      apps/bigmember_pc/src/views/search/bidding/model/base.js
  34. 86 54
      apps/bigmember_pc/src/views/search/bidding/model/modules/filter.js
  35. 51 50
      apps/bigmember_pc/src/views/search/bidding/model/modules/recommend-card.js
  36. 9 2
      apps/bigmember_pc/src/views/search/bidding/model/modules/save-filter-actions.js
  37. 10 8
      apps/bigmember_pc/src/views/search/bidding/model/modules/tabs.js
  38. 23 8
      apps/bigmember_pc/src/views/search/components/search-header-card.vue
  39. 9 9
      apps/bigmember_pc/src/views/search/nzj/components/nzj-article-item.vue
  40. 2 2
      apps/bigmember_pc/src/views/search/supply/model/base.js
  41. 11 0
      apps/bigmember_pc/src/views/workspace/components/AnalysisReport.vue
  42. 23 15
      apps/bigmember_pc/src/views/workspace/components/MessageTips.vue
  43. 11 0
      apps/bigmember_pc/src/views/workspace/components/NewsList.vue
  44. 3 5
      apps/bigmember_pc/src/views/workspace/components/SubscribeList.vue
  45. 7 15
      apps/bigmember_pc/src/views/workspace/ui/ListCard.vue
  46. 8 6
      apps/mobile/src/api/modules/public.js
  47. BIN
      apps/mobile/src/assets/image/icon/hot.png
  48. BIN
      apps/mobile/src/assets/image/public/logo-text-transparent-bg@2x.png
  49. 17 11
      apps/mobile/src/assets/style/_variables.scss
  50. 26 15
      apps/mobile/src/assets/style/common.scss
  51. 7 0
      apps/mobile/src/assets/style/pic-icon.scss
  52. 2 2
      apps/mobile/src/components/ad/SwipeFloor.vue
  53. 80 0
      apps/mobile/src/components/common/ScrollNav.vue
  54. 1 1
      apps/mobile/src/components/custom-report/index.vue
  55. 4 1
      apps/mobile/src/components/home/HotKeyList.vue
  56. 98 29
      apps/mobile/src/components/home/list.vue
  57. 55 20
      apps/mobile/src/components/message/message-card.vue
  58. 5 1
      apps/mobile/src/components/recommend/index.vue
  59. 488 255
      apps/mobile/src/components/search/bidding/filters.vue
  60. 6 0
      apps/mobile/src/components/selector/keyword-input-group/index.vue
  61. 18 6
      apps/mobile/src/components/selector/money-input-group/index.vue
  62. 2 5
      apps/mobile/src/composables/attachment-download/component/AttachmentDownload.vue
  63. 2 2
      apps/mobile/src/data/bidding.js
  64. 23 5
      apps/mobile/src/store/modules/user.js
  65. 1 0
      apps/mobile/src/ui/j-cell/index.vue
  66. 33 26
      apps/mobile/src/ui/project-cell/index.vue
  67. 147 74
      apps/mobile/src/utils/format/modules/filter-history-formatter.js
  68. 5 0
      apps/mobile/src/views/article/content.vue
  69. 35 26
      apps/mobile/src/views/search/middle/bidding/index.vue
  70. 551 115
      apps/mobile/src/views/search/result/bidding/index.vue
  71. 17 11
      apps/mobile/src/views/tabbar/Home.vue
  72. 23 22
      apps/mobile/vite.config.js
  73. 2 2
      data/data-models/modules/article/model/content.js

+ 3 - 2
apps/bigmember_pc/src/api/modules/search.js

@@ -18,11 +18,12 @@ export function addBiddingFilter(data) {
 }
 
 // 获取已存筛选列表
-export function getBiddingFilterList() {
+export function getBiddingFilterList(data) {
   return request({
     url: '/jyapi/jybx/base/showSearchScreen',
     method: 'post',
-    noToast: true
+    noToast: true,
+    data
   })
 }
 

BIN
apps/bigmember_pc/src/assets/images/channel-1.png


BIN
apps/bigmember_pc/src/assets/images/channel-2.png


BIN
apps/bigmember_pc/src/assets/images/channel-3.png


BIN
apps/bigmember_pc/src/assets/images/icon/fire-icon.png


BIN
apps/bigmember_pc/src/assets/images/icon/square-up.png


BIN
apps/bigmember_pc/src/assets/images/medical-field/content.png


+ 3 - 3
apps/bigmember_pc/src/assets/js/selector.js

@@ -922,11 +922,11 @@ export const biddingSearchListType = [
 // 招标搜索范围
 export const biddingSearchScope = [
   {
-    label: '标题搜索',
+    label: '标题',
     key: 'title'
   },
   {
-    label: '正文搜索',
+    label: '正文',
     key: 'content'
   },
   {
@@ -1098,4 +1098,4 @@ export const hotProvinceMap = {
   'o-32': ['香港'],
   'o-33': ['澳门'],
   'o-34': ['台湾']
-}
+}

+ 7 - 0
apps/bigmember_pc/src/assets/style/common.scss

@@ -13,6 +13,13 @@ body {
 .highlight-text {
   color: $color-text--highlight;
 }
+.highlight-text-orange {
+  color: #fa6f33;
+}
+.highlight-text-orange-bd {
+  color: #fa6f33;
+  font-weight: bold;
+}
 
 .pointer {
   cursor: pointer;

+ 26 - 23
apps/bigmember_pc/src/components/article-item/ArticleItem.vue

@@ -7,6 +7,7 @@
       'style-for-push': config.push,
       'style-for-bidding': config.bidding
     }"
+    @click="onClick"
   >
     <div class="list-item-left">
       <slot name="prefix"></slot>
@@ -28,7 +29,7 @@
               v-html="calcTitle"
               class="a-i-left visited-hd"
               :class="config.push || config.bidding ? 'ellipsis-3' : 'ellipsis'"
-              @click="onClick"
+              @click.stop="onClick"
             ></div>
           </div>
           <div class="time-container">
@@ -58,6 +59,11 @@
             "
             >业主委托项目</span
           >
+          <span
+            v-if="config.gray && (article.ca_fileExists || article.fileExists)"
+            class="haveFile"
+            >有附件</span
+          >
           <span class="tag tag-own" v-if="buySubject && article.source === 1"
             >个人订阅</span
           >
@@ -94,11 +100,6 @@
           <span class="tag dpink" v-if="calcBudget && calcBudget !== '0元'">
             {{ calcBudget }}
           </span>
-          <span
-            v-if="config.gray && (article.ca_fileExists || article.fileExists)"
-            class="haveFile"
-            >有附件</span
-          >
         </div>
 
         <div style="display: flex; align-items: center">
@@ -197,7 +198,7 @@
             <em
               v-for="(buyer, b) in formatBuyer(article.buyer)"
               :key="b"
-              @click="goPortrayal('buyerDesc', buyer)"
+              @click.stop="goPortrayal('buyerDesc', buyer)"
               class="highlight-text pointer"
             >
               {{ buyer }}
@@ -212,7 +213,7 @@
             <em
               class="more-tel"
               v-if="article.buyerTel"
-              @click="goPortrayal('buyerDesc', article.buyer, 'contact')"
+              @click.stop="goPortrayal('buyerDesc', article.buyer, 'contact')"
               >获取更多</em
             >
           </span>
@@ -241,7 +242,7 @@
             <em
               v-for="(w, i) in article.winnerInfo"
               :key="w.winnerId"
-              @click="goPortrayal('entDesc', w.winnerId)"
+              @click.stop="goPortrayal('entDesc', w.winnerId)"
               class="highlight-text pointer"
             >
               {{ w.winner }}
@@ -258,7 +259,7 @@
             <em
               class="more-tel"
               v-if="article.winnerInfo && article.winnerInfo.length === 1"
-              @click="
+              @click.stop="
                 goPortrayal(
                   'entDesc',
                   article.winnerInfo[0].winnerId,
@@ -435,7 +436,7 @@ export default {
       const hightLightedTitle = replaceKeyword(
         this.article.title,
         this.getMatchKeys,
-        ['<span class="highlight-text">', '</span>']
+        ['<span class="highlight-text-orange-bd">', '</span>']
       )
       if (this.article.filetext_search) {
         return `${this.index}. ${hightLightedTitle}${this.calcFileText}`
@@ -451,7 +452,7 @@ export default {
       )
       if (extractDetail) {
         return replaceKeyword(extractDetail, this.getMatchKeys, [
-          '<span class="highlight-text">',
+          '<span class="highlight-text-orange-bd">',
           '</span>'
         ])
       } else {
@@ -468,12 +469,12 @@ export default {
       if (inFile) {
         const keyword = keywords[0]
         if (keyword?.length > 3) {
-          return `(<span class="highlight-text">${keyword.substring(
+          return `(<span class="highlight-text-orange-bd">${keyword.substring(
             0,
             3
           )}</span>...在附件中)`
         } else {
-          return `(<span class="highlight-text">${keyword}</span>在附件中)`
+          return `(<span class="highlight-text-orange-bd">${keyword}</span>在附件中)`
         }
       } else {
         return ''
@@ -486,7 +487,7 @@ export default {
         this.getMatchKeys
       )
       return replaceKeyword(extractFiletext, this.getMatchKeys, [
-        '<span class="highlight-text">',
+        '<span class="highlight-text-orange-bd">',
         '</span>'
       ])
     },
@@ -640,15 +641,15 @@ export default {
   flex-shrink: 0;
   display: inline-block;
   padding: 0 8px;
-  // margin: 0 8px 0 12px;
+  background: #eaf9fb;
   height: 20px;
   border-radius: 4px;
-  border: 1px solid #2cb7ca;
   font-size: 12px;
   font-weight: 400;
   color: #2cb7ca;
   line-height: 18px;
   flex-shrink: 0;
+  margin-right: 8px;
 }
 </style>
 <style lang="scss" scoped>
@@ -717,13 +718,13 @@ $border-color: #ececec;
       text-align: center;
       color: #686868;
       line-height: 20px;
-      height: 22px;
+      height: 20px;
       padding: 0 8px;
       flex-shrink: 0;
     }
     .tag-ent {
-      background: #fff9f0;
-      color: #b1700e;
+      background: #eaf9fb;
+      color: #2abed1;
       border: 0;
     }
     .tag-own {
@@ -732,9 +733,10 @@ $border-color: #ececec;
       border: 0;
     }
     .tag-user {
-      background-color: rgba(254, 115, 122, 0.16);
+      background-color: #fff1eb;
+      border: 0;
       border-radius: 4px;
-      color: #ff3a20;
+      color: #fa6f33;
       margin-right: 10px;
     }
   }
@@ -760,7 +762,8 @@ $border-color: #ececec;
   }
   .a-i-left {
     // display: inline-block;
-    font-size: 16px;
+    font-size: 15px;
+    line-height: 24px;
     margin-right: 60px;
     cursor: pointer;
     // max-width: 650px;

+ 59 - 36
apps/bigmember_pc/src/components/filter-items/AmountRangeSelector.vue

@@ -10,7 +10,10 @@
     <div class="filter-list" slot="empty">
       <div
         class="filter-item"
-        :class="{'active': item.value === activeValue, 'highlight': item.disabled && isCustom }"
+        :class="{
+          active: item.value === activeValue,
+          highlight: item.disabled && isCustom
+        }"
         v-for="item in options"
         :key="item.label"
         :label="item.label"
@@ -29,13 +32,29 @@
         >
           <div class="custom-money">
             <div class="custom-money-item">
-              从<el-input class="price-input" :class="{'focus': price.min}" v-model="price.min" oninput="value=value.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/,'$1')" maxlength="9"></el-input>万
+              从<el-input
+                class="price-input"
+                :class="{ focus: price.min }"
+                v-model="price.min"
+                oninput="value=value.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/,'$1')"
+                maxlength="9"
+              ></el-input
+              >万
             </div>
             <div class="custom-money-item">
-              至<el-input class="price-input" :class="{'focus': price.max}" v-model="price.max" oninput="value=value.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/,'$1')" maxlength="9"></el-input>万
+              至<el-input
+                class="price-input"
+                :class="{ focus: price.max }"
+                v-model="price.max"
+                oninput="value=value.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/,'$1')"
+                maxlength="9"
+              ></el-input
+              >万
             </div>
             <div class="custom-money-button">
-              <el-button type="primary" @click.stop="onSubmitPrice">确定</el-button>
+              <el-button type="primary" @click.stop="onSubmitPrice"
+                >确定</el-button
+              >
             </div>
           </div>
           <div slot="reference" class="custom-label">
@@ -88,7 +107,7 @@ export default {
     prop: 'value',
     event: 'change'
   },
-  data () {
+  data() {
     return {
       options: amountRangeData,
       activeValue: this.value,
@@ -101,11 +120,11 @@ export default {
     }
   },
   computed: {
-    activeLabel () {
+    activeLabel() {
       const price = this.activeValue
       if (price) {
         const priceArr = price.split('-')
-        if (priceArr.length > 1) {
+        if (priceArr.length > 0) {
           const min = priceArr[0]
           const max = priceArr[1]
           if (min && max) {
@@ -134,7 +153,7 @@ export default {
     }
   },
   methods: {
-    onVisibleChange (flag) {
+    onVisibleChange(flag) {
       this.isFocus = flag
       if (flag) {
         this.setState(this.activeValue)
@@ -143,14 +162,16 @@ export default {
             setTimeout(() => {
               // popover在下拉框展示时需要重新计算位置,通过先将popover弹框透明度将为0等位置计算完成后再恢复
               this.$refs.customPricePopover[0].updatePopper()
-              const $popover = this.$root.$el.querySelector('.amount-range-popover > .el-popover')
+              const $popover = this.$root.$el.querySelector(
+                '.amount-range-popover > .el-popover'
+              )
               $popover.style.opacity = '1'
             }, 300)
           }
         })
       }
     },
-    compareMinMax () {
+    compareMinMax() {
       const { min, max } = this.price
       const hasMinAndMax = String(min).length && String(max).length
       if (hasMinAndMax && Number(min) > Number(max)) {
@@ -158,12 +179,12 @@ export default {
         this.price.min = max
       }
     },
-    onSubmitPrice () {
+    onSubmitPrice() {
       this.compareMinMax()
       const { min, max } = this.price
       if (!min && !max) return
       this.activeValue = `${min}-${max}`
-      this.options.forEach(item => {
+      this.options.forEach((item) => {
         if (item.label === '自定义') {
           item.value = `${min}-${max}`
         }
@@ -173,7 +194,7 @@ export default {
       this.$refs.customPricePopover[0].doClose()
       this.$emit('change', this.activeValue)
     },
-    handleChange (item) {
+    handleChange(item) {
       if (item.label !== '自定义') {
         this.activeValue = item.value
         this.isCustom = false
@@ -186,17 +207,19 @@ export default {
         this.isCustom = true
       }
     },
-    getState () {
+    getState() {
       return {
         label: this.activeLabel,
         value: this.activeValue,
         isCustom: this.isCustom
       }
     },
-    setState (data) {
+    setState(data) {
       this.isCustom = false
       if (data) {
-        const valueArr = this.options.filter(v => !v.disabled).map(t => t.value)
+        const valueArr = this.options
+          .filter((v) => !v.disabled)
+          .map((t) => t.value)
         if (valueArr.includes(data)) {
           this.activeValue = data
           this.showPopover = false
@@ -226,82 +249,82 @@ export default {
 </script>
 
 <style lang="scss" scoped>
-.filter-list{
+.filter-list {
   min-width: 140px;
   padding: 8px 0;
   border: 1px solid $color_main;
   background: #fff;
   border-radius: 5px;
   margin-top: 2px;
-  .filter-item{
+  .filter-item {
     padding: 4px 16px;
     font-size: 14px;
     line-height: 22px;
     color: #1d1d1d;
     text-align: left;
     cursor: pointer;
-    &:hover{
-      background: #ECECEC;
+    &:hover {
+      background: #ececec;
     }
-    &.active{
-      background: #ECECEC;
+    &.active {
+      background: #ececec;
     }
     &.highlight {
       color: $color_main;
     }
-    span{
+    span {
       display: inline-block;
       width: 100%;
     }
   }
-  .custom-label{
+  .custom-label {
     display: flex;
     align-items: center;
     justify-content: space-between;
-    .el-icon-arrow-right{
+    .el-icon-arrow-right {
       margin-right: -8px;
     }
   }
-  .custom-popover{
-    .custom-money{
+  .custom-popover {
+    .custom-money {
       padding: 12px;
       margin-left: 4px;
       border: 1px solid $color_main;
       background: #fff;
       border-radius: 4px;
-      &-item{
+      &-item {
         display: flex;
         align-items: center;
         margin-bottom: 12px;
       }
-      &-button{
+      &-button {
         display: flex;
         justify-content: flex-end;
-        .el-button{
+        .el-button {
           width: 60px;
           height: 28px;
           padding: 0;
         }
       }
     }
-    ::v-deep{
-      .el-popover{
+    ::v-deep {
+      .el-popover {
         margin-left: 16px;
         border-color: $color_main;
         padding: 0;
         border: 0;
         background: transparent;
       }
-      .price-input{
+      .price-input {
         width: 88px;
         height: 24px;
         margin: 0 4px;
-        .el-input__inner{
+        .el-input__inner {
           height: 100%;
           padding: 0 8px;
         }
-        &.focus{
-          .el-input__inner{
+        &.focus {
+          .el-input__inner {
             border-color: $color_main;
           }
         }

+ 3 - 2
apps/bigmember_pc/src/components/filter-items/BasePowerLayout.vue

@@ -60,8 +60,9 @@ $gold: #c98f37;
 .vip-module {
   border: 1px dashed $gold;
   padding: 1px 12px 1px 8px;
-  height: 32px;
-  background: linear-gradient(90deg, #fff7dC 0%, rgba(255, 247, 220, 0) 100%);
+  //height: 32px;
+  min-height: 32px;
+  background: linear-gradient(90deg, #fff7dc 0%, rgba(255, 247, 220, 0) 100%);
   &::after {
     content: '';
     position: absolute;

+ 126 - 0
apps/bigmember_pc/src/components/filter-items/InfoTypeSelector.vue

@@ -0,0 +1,126 @@
+<template>
+  <!--  信息类型组件:一级平铺、二级下拉展示组件-->
+  <selector-card
+    class="info-type-selector"
+    :cardType="selectorType"
+    @onConfirm="onConfirm"
+    @onCancel="onCancel"
+  >
+    <div
+      v-if="showLabel"
+      slot="header"
+      :class="{ 's-header': selectorType === 'line' }"
+    >
+      <slot name="header">选择信息类型</slot>
+    </div>
+    <InfoTypeSelectorContent
+      ref="content"
+      :selectorType="selectorType"
+      :initInfoType="initInfoType"
+      :beforeChange="beforeChange"
+      :oneLevelSelected="oneLevelSelected"
+      :showDataType="showDataType"
+      :options="options"
+      :disabledDropdown="disabledDropdown"
+      @onChange="onChange"
+    />
+  </selector-card>
+</template>
+
+<script>
+import SelectorCard from '@/components/selector/SelectorCard.vue'
+import InfoTypeSelectorContent from '@/components/filter-items/InfoTypeSelectorContent.vue'
+export default {
+  name: 'info-type-selector',
+  components: {
+    SelectorCard,
+    InfoTypeSelectorContent
+  },
+  props: {
+    showLabel: {
+      type: Boolean,
+      default: true
+    },
+    selectorType: {
+      type: String,
+      default: 'card' // card/line
+    },
+    beforeChange: Function,
+    initInfoType: {
+      type: Array,
+      default() {
+        return []
+      }
+    },
+    // 二级分类全部选中是否提交一级分类(P490新增需求:订阅列表如果二级分类都选中,则提交一级分类名,不提交二级分类)
+    oneLevelSelected: {
+      type: Boolean,
+      default: false
+    },
+    value: {
+      type: Array,
+      default: () => []
+    },
+    // all 是所有数据, advance 仅仅超前项目数据,base 信息类型数据(除了超前项目外数据)
+    showDataType: {
+      type: String,
+      default: 'all'
+    },
+    options: {
+      type: Array,
+      default() {
+        return []
+      }
+    },
+    // 是否禁用下拉
+    disabledDropdown: {
+      type: Boolean,
+      default: false
+    }
+  },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
+  watch: {
+    showDataType(newVal, oldVal) {
+      this.initList([], newVal)
+    },
+    value(val) {
+      if (!val || val?.length === 0) {
+        this.initList([], this.showDataType)
+      } else {
+        this.setInfoTypeState(val)
+      }
+    }
+  },
+  data() {
+    return {}
+  },
+  created() {},
+  methods: {
+    initList(data = [], type) {
+      return this.$refs.content.initInfoTypeFn(data, type)
+    },
+    setInfoTypeState(data) {
+      return this.$refs.content.setInfoTypeState(data)
+    },
+    getSelected() {
+      return this.$refs.content.getSelected()
+    },
+    onCancel() {
+      this.$emit('onCancel')
+    },
+    onConfirm() {
+      const selected = this.getSelected()
+      this.$emit('onConfirm', selected)
+    },
+    onChange(selected) {
+      this.$emit('onChange', selected)
+      this.$emit('change', selected)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

Datei-Diff unterdrückt, da er zu groß ist
+ 418 - 0
apps/bigmember_pc/src/components/filter-items/InfoTypeSelectorContent.vue


+ 48 - 36
apps/bigmember_pc/src/components/filter-items/KeywordTagsSelectorContent.vue

@@ -1,6 +1,6 @@
 <template>
-  <div class='add-keyword-container'>
-    <div style="margin-top:6px;">
+  <div class="add-keyword-container">
+    <div style="margin-top: 6px">
       <el-input
         class="add-keyword-input"
         type="text"
@@ -12,7 +12,12 @@
         @focus="onKeydown"
         @keydown.native="onKeydown"
       ></el-input>
-      <span class="add-keyword-btn" :class="{'focus': addKeywordVal}" @click="addKeyTags">添加</span>
+      <span
+        class="add-keyword-btn"
+        :class="{ focus: addKeywordVal }"
+        @click="addKeyTags"
+        >添加</span
+      >
     </div>
     <div class="add-keyword-tags">
       <el-tag
@@ -20,8 +25,9 @@
         v-for="(tag, index) in list"
         closable
         :disable-transitions="false"
-        @close="removeTag(tag)">
-        {{tag}}
+        @close="removeTag(tag)"
+      >
+        {{ tag }}
       </el-tag>
     </div>
     <slot name="radio"></slot>
@@ -67,7 +73,7 @@ export default {
       default: false
     }
   },
-  data () {
+  data() {
     return {
       addKeywordVal: ''
     }
@@ -75,23 +81,26 @@ export default {
   methods: {
     addKeyTags() {
       if (!this.addKeywordVal) return
-      this.list.push(this.addKeywordVal.replace(/,/g, ' ').replace(/\s*$/g,''))
+      this.list.push(this.addKeywordVal.replace(/,/g, ' ').replace(/\s*$/g, ''))
       this.$emit('change', this.list)
       this.addKeywordVal = ''
     },
     onKeyup() {
-      if(this.$parent.$parent) {
+      if (this.$parent.$parent) {
         this.$parent.$parent.visible = true
       }
-      this.addKeywordVal = this.addKeywordVal.replace(/,/g, ' ').trim().replace(/^\s*/g, '')
+      this.addKeywordVal = this.addKeywordVal
+        .replace(/,/g, ' ')
+        .trim()
+        .replace(/^\s*/g, '')
     },
-    removeTag (tag) {
+    removeTag(tag) {
       this.list.splice(this.list.indexOf(tag), 1)
       this.$emit('change', this.list)
     },
     // dropdown的坑点,微软输入法,input输入的时候会失去焦,dropdown会收起,暂且如此处理
-    onKeydown () {
-      if(this.$parent.$parent) {
+    onKeydown() {
+      if (this.$parent.$parent) {
         this.$parent.$parent.visible = true
       }
     }
@@ -99,60 +108,63 @@ export default {
 }
 </script>
 
-<style lang='scss' scoped>
-.add-keyword-container{
+<style lang="scss" scoped>
+.add-keyword-container {
   display: flex;
   align-items: center;
   flex-wrap: wrap;
   padding-top: 12px;
   margin-left: 16px;
-  box-sizing:border-box;
+  box-sizing: border-box;
   ::v-deep {
-    .add-keyword-input{
-      width:auto;
-      .el-input__inner{
+    .add-keyword-input {
+      width: auto;
+      .el-input__inner {
         width: 368px;
         height: 36px;
         line-height: 30px;
         font-size: 14px !important;
-        border: 1px solid #E0E0E0;
+        border: 1px solid #e0e0e0;
         border-radius: 4px;
-        color: #1D1D1D !important;
+        color: #1d1d1d !important;
       }
     }
     .el-tag {
+      white-space: normal;
       .el-tag__close {
         color: #aaa;
         font-weight: 700;
-        background-color:rgba(255, 255, 255, 0);
+        background-color: rgba(255, 255, 255, 0);
       }
       &:hover {
         .el-tag__close {
           background-color: transparent;
-          color: #2CB7CA;
+          color: #2cb7ca;
         }
       }
     }
   }
   .el-tag {
+    max-width: 408px;
     margin-top: 6px;
-    height: 24px;
+    height: unset;
+    min-height: 24px;
     line-height: 22px;
     padding: 0 8px;
-    background: #F5F6F7;
-    border: 1px solid #ECECEC;
+    background: #f5f6f7;
+    border: 1px solid #ececec;
     border-radius: 4px;
     margin-right: 16px;
-    color: #1D1D1D;
+    color: #1d1d1d;
     font-size: 14px;
     margin-left: 0;
-    &:hover{
-      color: #2CB7CA;
-      border: 1px solid #2ABED1;
+    &:hover {
+      color: #2cb7ca;
+      border: 1px solid #2abed1;
       background: #fff;
     }
-    .el-icon-close{
-     background: transparent;
+    .el-icon-close {
+      background: transparent;
       text-align: center;
       position: relative;
       cursor: pointer;
@@ -166,19 +178,19 @@ export default {
     }
     .el-icon-close::before {
       display: block;
-      content: "\e6db";
+      content: '\e6db';
     }
   }
   .el-icon-close:before {
-    content: "\e6db";
+    content: '\e6db';
   }
-  .add-keyword-tags{
-    max-width:440px;
+  .add-keyword-tags {
+    max-width: 440px;
     width: 100%;
     margin-top: 10px;
     margin-bottom: 16px;
   }
-  .add-keyword-btn{
+  .add-keyword-btn {
     margin-left: 8px;
     font-size: 14px;
     line-height: 22px;

+ 12 - 1
apps/bigmember_pc/src/components/filter-items/Layout.vue

@@ -7,6 +7,7 @@
     <el-dropdown
       :trigger="trigger"
       :placement="placement"
+      :disabled="disabled"
       @visible-change="onVisibleChange"
       ref="dropdownRef"
     >
@@ -85,6 +86,11 @@ export default {
     onlyBottom: {
       type: Boolean,
       default: true
+    },
+    // 是否禁用下拉
+    disabled: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -95,7 +101,12 @@ export default {
   mounted() {
     // 修改dropdown挂载位置
     this.$nextTick(() => {
-      if (this.dropdownMenu) {
+      if (
+        this.dropdownMenu &&
+        this.$refs.layout &&
+        this.$refs.dropdownRef &&
+        this.$refs?.dropdownMenu
+      ) {
         this.$refs.layout.appendChild(this.$refs?.dropdownMenu.popperElm)
       }
     })

+ 65 - 6
apps/bigmember_pc/src/components/filter-items/OnecascadeContent.vue

@@ -4,6 +4,9 @@
     :placeholder="placeholder"
     :trigger="trigger"
     :value="computedVal"
+    :class="{ 'placeholder-high': placeholderHighClass }"
+    :disabled="disabled"
+    @onClick="placeholderClickHandle"
   >
     <div class="cascade-content" slot="empty">
       <div class="cascade-content-module">
@@ -23,8 +26,8 @@
                 :indeterminate="first.indeterminate"
                 @change="onFirstChange($event, first, fIndex)"
               >
+                <span class="item-name">{{ first.label }}</span>
               </el-checkbox>
-              <span class="item-name">{{ first.label }}</span>
             </li>
           </ul>
         </div>
@@ -68,6 +71,21 @@ export default {
     showHeader: {
       type: Boolean,
       default: false
+    },
+    // 下拉标题文案是否可以点击
+    placeholderClick: {
+      type: Boolean,
+      default: false
+    },
+    // 下拉标题文案是否可以高亮
+    placeholderNeedHigh: {
+      type: Boolean,
+      default: false
+    },
+    // 是否禁用下拉
+    disabled: {
+      type: Boolean,
+      default: false
     }
   },
   data() {
@@ -76,7 +94,8 @@ export default {
       fActive: -1,
       sActive: -1,
       fTimer: null,
-      sTimer: null
+      sTimer: null,
+      placeholderActive: false
     }
   },
   model: {
@@ -108,10 +127,25 @@ export default {
         if (this.hadAllValue && value.includes(this.hadAllValue)) {
           result = ''
         } else {
-          result = `${this.placeholder}${value.length}个`
+          if (
+            value.length === this.options.length &&
+            this.placeholderNeedHigh
+          ) {
+            result = `${this.placeholder}`
+          } else {
+            result = `${this.placeholder}${value.length}个`
+          }
         }
       }
       return result
+    },
+    placeholderHighClass() {
+      return (
+        this.placeholderNeedHigh &&
+        this.computedVal &&
+        this.value &&
+        (this.value.length === 0 || this.value.length === this.options.length)
+      )
     }
   },
   watch: {
@@ -175,7 +209,14 @@ export default {
       if (first.all) {
         this.$emit('change', first.checked ? this.getState() : null)
       } else {
-        this.$emit('change', this.getState())
+        const result = this.getState()
+        // 此处,非全部选项最后一个取消选中时候返回null(即不选中状态)
+        if (this.placeholderClick && result.length === 0 && !first.checked) {
+          this.$emit('change', null)
+        } else {
+          // 正常勾选处理
+          this.$emit('change', this.getState())
+        }
       }
     },
     restState() {
@@ -229,7 +270,8 @@ export default {
       if (Array.isArray(value)) {
         if (
           value.length === 0 ||
-          (value.length === 1 && value[0] === this.hadAllValue)
+          (value.length === 1 && value[0] === this.hadAllValue) ||
+          value.length === this.options.length
         ) {
           this.firstList.forEach((item) => {
             item.checked = true
@@ -245,6 +287,15 @@ export default {
         }
       }
       this.checkFirstAllStatus()
+    },
+    // 下拉值是否可点击,点击即为全部选中
+    placeholderClickHandle() {
+      if (!this.placeholderClick) {
+        return
+      }
+      this.placeholderActive = !this.placeholderActive
+      const allItem = this.firstList.filter((item) => item.value === '全部')
+      this.onFirstChange(this.placeholderActive, allItem[0])
     }
   }
 }
@@ -281,7 +332,7 @@ export default {
 
     .module-main {
       flex: 1;
-      overflow-y: scroll;
+      overflow-y: auto;
     }
 
     .module-item {
@@ -311,4 +362,12 @@ export default {
     }
   }
 }
+::v-deep {
+  .el-checkbox {
+    width: 100%;
+  }
+  .el-checkbox__label {
+    padding-left: 0;
+  }
+}
 </style>

+ 23 - 14
apps/bigmember_pc/src/components/push-list/PushList.vue

@@ -559,7 +559,7 @@ export default {
       }
       const { projectName, matchKeys } = item
       const hightLightedTitle = replaceKeyword(projectName, matchKeys, [
-        '<span class="highlight-text">',
+        '<span class="highlight-text-orange-bd">',
         '</span>'
       ])
       return `${hightLightedTitle}`
@@ -868,17 +868,22 @@ export default {
         Object.keys(this.getFilters).forEach((v) => {
           if (typeof this.getFilters[v] !== 'undefined') {
             if (v === 'industry' && typeof filters[v] === 'object') {
-              if(Object.keys(this.getFilters[v]).length > 0) {
+              if (Object.keys(this.getFilters[v]).length > 0) {
                 query[v] = this.formatIndustryMap(this.getFilters[v]).join(',')
               }
             } else if (v === 'buyerClass' && typeof filters[v] === 'object') {
-              if(Object.keys(this.getFilters[v]).length > 0) {
-                query[v] = this.formatIndustryMap(this.getFilters[v]).map((v) => v.split('_')[1]).join(',')
+              if (Object.keys(this.getFilters[v]).length > 0) {
+                query[v] = this.formatIndustryMap(this.getFilters[v])
+                  .map((v) => v.split('_')[1])
+                  .join(',')
               }
             } else if (v === 'subtype' && typeof filters[v] === 'object') {
-              const filterSubtype = InfoTypeTransform.mapToList(this.getFilters[v])
-              if(Object.keys(this.getFilters[v]).length > 0) {
-                query[v] = filterSubtype.length > 0 ? filterSubtype.join(',') : ''
+              const filterSubtype = InfoTypeTransform.mapToList(
+                this.getFilters[v]
+              )
+              if (Object.keys(this.getFilters[v]).length > 0) {
+                query[v] =
+                  filterSubtype.length > 0 ? filterSubtype.join(',') : ''
               }
             } else {
               query[v] = this.getFilters[v]
@@ -891,17 +896,20 @@ export default {
         Object.keys(filters).forEach((v) => {
           if (typeof filters[v] !== 'undefined') {
             if (v === 'industry' && typeof filters[v] === 'object') {
-              if(Object.keys(filters[v]).length > 0) {
+              if (Object.keys(filters[v]).length > 0) {
                 query[v] = this.formatIndustryMap(filters[v]).join(',')
               }
             } else if (v === 'buyerClass' && typeof filters[v] === 'object') {
-              if(Object.keys(filters[v]).length > 0) {
-                query[v] = this.formatIndustryMap(filters[v]).map((v) => v.split('_')[1]).join(',')
+              if (Object.keys(filters[v]).length > 0) {
+                query[v] = this.formatIndustryMap(filters[v])
+                  .map((v) => v.split('_')[1])
+                  .join(',')
               }
             } else if (v === 'subtype' && typeof filters[v] === 'object') {
               const filterSubtype = InfoTypeTransform.mapToList(filters[v])
-              if(Object.keys(filters[v]).length > 0) {
-                query[v] = filterSubtype.length > 0 ? filterSubtype.join(',') : ''
+              if (Object.keys(filters[v]).length > 0) {
+                query[v] =
+                  filterSubtype.length > 0 ? filterSubtype.join(',') : ''
               }
             } else {
               query[v] = filters[v]
@@ -1958,7 +1966,8 @@ export default {
     height: 18px;
     top: 14px;
     right: -12px;
-    background: url('~@/assets/images/icon/v-vip-icon.png') no-repeat right center;
+    background: url('~@/assets/images/icon/v-vip-icon.png') no-repeat right
+      center;
     background-size: contain;
   }
 }
@@ -2359,8 +2368,8 @@ export default {
 <style lang="scss" scoped>
 @include diy-icon('edit', 20, 20);
 
-// card样式重置
 ::v-deep {
+  // card样式重置
   .el-card__header {
     margin: 0 40px;
     padding-left: 0;

+ 1 - 4
apps/bigmember_pc/src/composables/attachment-download/component/AttachmentDownload.vue

@@ -139,10 +139,7 @@ export default {
       }
     },
     fileNum() {
-      if (this.resourcePack.number > 0) {
-        return this.resourcePack.number
-      }
-      return this.power?.fileNum || 0
+      return this.resourcePack.number
     },
     isNewSuper() {
       return this.power.viper && this.isSuper

Datei-Diff unterdrückt, da er zu groß ist
+ 726 - 213
apps/bigmember_pc/src/utils/format/search-bid-filter.js


+ 0 - 1
apps/bigmember_pc/src/views/article-content/components/RecommendOpportunities.vue

@@ -340,7 +340,6 @@ const recommendMaskConfig = {
       display: flex;
       flex-direction: row;
       justify-content: space-between;
-      padding: 16px 0;
       &:hover {
         color: $color-main;
       }

+ 105 - 100
apps/bigmember_pc/src/views/collection/components/search-list-table.vue

@@ -34,141 +34,140 @@ const props = defineProps({
   }
 })
 
-const  showTableMore = computed(() => {
+const showTableMore = computed(() => {
   return props.list.length >= 20 && props.listState.total > 20
 })
 
-function calcTitle (item)  {
-    if (!item.projectName) {
-      item.projectName = item.title
-    }
-    const { projectName, matchKeys } = item
-    const highKeys = getMatchKeys(matchKeys || [])
-    const hightLightedTitle = replaceKeyword(projectName, highKeys, [
-      '<span class="highlight-text">',
-      '</span>'
-    ])
-    return `${hightLightedTitle}`
+function calcTitle(item) {
+  if (!item.projectName) {
+    item.projectName = item.title
+  }
+  const { projectName, matchKeys } = item
+  const highKeys = getMatchKeys(matchKeys || [])
+  const hightLightedTitle = replaceKeyword(projectName, highKeys, [
+    '<span class="highlight-text-orange-bd">',
+    '</span>'
+  ])
+  return `${hightLightedTitle}`
 }
 
 function calcMoney(budget) {
-  if(budget && isNaN(budget)) {
+  if (budget && isNaN(budget)) {
     return budget
   } else if (budget && !isNaN(budget) && budget !== '0') {
-    return ( budget / 10000).toFixed(2).replace(
-      '.00',
-      ''
-    )
+    return (budget / 10000).toFixed(2).replace('.00', '')
   } else {
     return ''
   }
 }
-function  getMatchKeys(matchKeys) {
+function getMatchKeys(matchKeys) {
   return props.matchKeys.concat(matchKeys)
 }
 
 const emit = defineEmits(['before-close'])
-function toDetail (item) {
+function toDetail(item) {
   emit('to-detail', item)
 }
 </script>
 
 <template>
   <div
-      class="info-list search-table-list"
-      element-loading-background="rgba(255,255,255, .4)"
-      element-loading-custom-class="self-export-loading"
-    >
-    <div class='fixed-table' v-if='tableFixedTop'>
-      <table class="table" >
-        <thead class="thead fixed-head" >
-        <tr>
-          <td width="49.7">序号</td>
-          <td width="326.4" class="deep-border">项目名称</td>
-          <td width="87">公告类型</td>
-          <td width="75.6" class="deep-border">预算<br />(万元)</td>
-          <td width="187">招标单位</td>
-          <td width="106.7" class="deep-border">开标日期</td>
-          <td width="180.3">中标单位</td>
-          <td width="78.7" class="deep-border">中标金额<br />(万元)</td>
-          <td width="106.8">发布日期</td>
-        </tr>
-        </thead>
-      </table>
-    </div>
-      <table class="table" v-show="list.length">
-        <thead class="thead">
+    class="info-list search-table-list"
+    element-loading-background="rgba(255,255,255, .4)"
+    element-loading-custom-class="self-export-loading"
+  >
+    <div class="fixed-table" v-if="tableFixedTop">
+      <table class="table">
+        <thead class="thead fixed-head">
           <tr>
-            <td width="48">序号</td>
-            <td width="315" class="deep-border">项目名称</td>
-            <td width="84">公告类型</td>
-            <td width="73" class="deep-border">预算<br />(万元)</td>
-            <td width="181">招标单位</td>
-            <td width="103" class="deep-border">开标日期</td>
-            <td width="174">中标单位</td>
-            <td width="76" class="deep-border">中标金额<br />(万元)</td>
-            <td width="103">发布日期</td>
+            <td width="49.7">序号</td>
+            <td width="326.4" class="deep-border">项目名称</td>
+            <td width="87">公告类型</td>
+            <td width="75.6" class="deep-border">预算<br />(万元)</td>
+            <td width="187">招标单位</td>
+            <td width="106.7" class="deep-border">开标日期</td>
+            <td width="180.3">中标单位</td>
+            <td width="78.7" class="deep-border">中标金额<br />(万元)</td>
+            <td width="106.8">发布日期</td>
           </tr>
         </thead>
-        <tbody>
-          <tr
-            v-for="(item, index) in list"
-            :class="{ visited: item.visited }"
-            :key="index + '_' + item.id"
-            @click="toDetail(item)"
-            v-visited:articleContent="item.id"
-          >
-            <td width="48">{{ index + 1 }}</td>
-            <td width="315" class="tt-l" v-html="calcTitle(item, index)"></td>
-            <td width="84">{{ item.subtype ? item.subtype + '公告' : ''}}</td>
-            <td width="73" class="tt-r">{{ calcMoney(item.budget) }}</td>
-            <td width="181" class="tt-l">{{ item.buyer }}</td>
-            <td width="103">
-              {{
-                dateFromNow(
-                  item.bidOpenTime ? item.bidOpenTime * 1000 : null,
-                  'yyyy-MM-dd HH:mm'
-                )
-              }}
-            </td>
-            <td width="174" class="tt-l">{{ item.winner }}</td>
-            <td width="76" class="tt-r">{{ calcMoney(item.bidAmount) }}</td>
-            <td width="103">{{ dateFromNow(item.publishTime * 1000) }}</td>
-          </tr>
-        </tbody>
       </table>
-      <div class="shade_table" v-if="showTableMore">
-        <div class="more" data-need-bind-phone="" @click="onClickDataExport('table')">
-          查看更多&gt;
-        </div>
+    </div>
+    <table class="table" v-show="list.length">
+      <thead class="thead">
+        <tr>
+          <td width="48">序号</td>
+          <td width="315" class="deep-border">项目名称</td>
+          <td width="84">公告类型</td>
+          <td width="73" class="deep-border">预算<br />(万元)</td>
+          <td width="181">招标单位</td>
+          <td width="103" class="deep-border">开标日期</td>
+          <td width="174">中标单位</td>
+          <td width="76" class="deep-border">中标金额<br />(万元)</td>
+          <td width="103">发布日期</td>
+        </tr>
+      </thead>
+      <tbody>
+        <tr
+          v-for="(item, index) in list"
+          :class="{ visited: item.visited }"
+          :key="index + '_' + item.id"
+          @click="toDetail(item)"
+          v-visited:articleContent="item.id"
+        >
+          <td width="48">{{ index + 1 }}</td>
+          <td width="315" class="tt-l" v-html="calcTitle(item, index)"></td>
+          <td width="84">{{ item.subtype ? item.subtype + '公告' : '' }}</td>
+          <td width="73" class="tt-r">{{ calcMoney(item.budget) }}</td>
+          <td width="181" class="tt-l">{{ item.buyer }}</td>
+          <td width="103">
+            {{
+              dateFromNow(
+                item.bidOpenTime ? item.bidOpenTime * 1000 : null,
+                'yyyy-MM-dd HH:mm'
+              )
+            }}
+          </td>
+          <td width="174" class="tt-l">{{ item.winner }}</td>
+          <td width="76" class="tt-r">{{ calcMoney(item.bidAmount) }}</td>
+          <td width="103">{{ dateFromNow(item.publishTime * 1000) }}</td>
+        </tr>
+      </tbody>
+    </table>
+    <div class="shade_table" v-if="showTableMore">
+      <div
+        class="more"
+        data-need-bind-phone=""
+        @click="onClickDataExport('table')"
+      >
+        查看更多&gt;
       </div>
-      <div class="shade_table_blank" v-if="list.length"></div>
     </div>
+    <div class="shade_table_blank" v-if="list.length"></div>
+  </div>
 </template>
 
 <style lang="scss" scoped>
 /* table */
-.in-app{
-  .search-table-list{
-    .fixed-table{
-      width:100%;
+.in-app {
+  .search-table-list {
+    .fixed-table {
+      width: 100%;
       background: #fff;
-      top:48px;
-      left:0;
+      top: 48px;
+      left: 0;
       padding: 0 24px;
       box-sizing: border-box;
     }
   }
 }
 
-
 .search-table-list {
   /*全文搜索 表格*/
-  width:100%;
+  width: 100%;
   position: relative;
   //border-bottom: 1px solid #e0e0e0;
   table {
-
     width: 100%;
     border-collapse: collapse;
     table-layout: fixed;
@@ -226,10 +225,10 @@ function toDetail (item) {
     margin-top: -110px;
     height: 150px;
     background: linear-gradient(
-        to bottom,
-        rgba(255, 255, 255, 0),
-        rgba(255, 255, 255, 0.8),
-        rgba(255, 255, 255, 1)
+      to bottom,
+      rgba(255, 255, 255, 0),
+      rgba(255, 255, 255, 0.8),
+      rgba(255, 255, 255, 1)
     );
     .more {
       position: absolute;
@@ -246,16 +245,22 @@ function toDetail (item) {
       cursor: pointer;
     }
   }
-  .shade_table_blank{
-    height:50px;
+  .shade_table_blank {
+    height: 50px;
   }
-  .fixed-table{
+  .fixed-table {
     position: fixed;
     top: 100px;
-    width:1200px;
-    table{
+    width: 1200px;
+    table {
       margin-bottom: 0;
     }
   }
 }
+::v-deep {
+  .daxue {
+    color: #fa6f33;
+    font-weight: bold;
+  }
+}
 </style>

+ 41 - 32
apps/bigmember_pc/src/views/collection/index.vue

@@ -49,16 +49,20 @@ const {
 } = SearchBidModel
 
 // 开通超级订阅
-function toBuySvip () {
+function toBuySvip() {
   window.open('/swordfish/page_big_pc/free/svip/buy?type=buy')
 }
 
 // 前往收藏
 function goCollect() {
   location.href = '/jylab/supsearch/index.html?publishtime=thisyear'
-} 
+}
 
-const { show: showVipDialog, text: vipDialogText, type: vipDialogType } = vipDialogConf
+const {
+  show: showVipDialog,
+  text: vipDialogText,
+  type: vipDialogType
+} = vipDialogConf
 
 // 列表-单条-配置
 const articleRef = ref({
@@ -70,7 +74,6 @@ const articleRef = ref({
   collect: !isInBI.value,
   push: false
 })
-
 </script>
 <template>
   <div class="collection-page">
@@ -87,10 +90,12 @@ const articleRef = ref({
         @doChangeSelect="doChangeSelect"
         :show-pagination="activeItemStyleType !== 'T'"
         :is-table="activeItemStyleType === 'T'"
-        :table-fixed-top='tableFixedTop'
+        :table-fixed-top="tableFixedTop"
       >
         <template #other-action-item v-if="isInBI">
-          <div class="all-add bi-batch-add-button" @click="onAddInfoOfBI()">批量添加</div>
+          <div class="all-add bi-batch-add-button" @click="onAddInfoOfBI()">
+            批量添加
+          </div>
         </template>
         <!--      <template #list-before v-if="listState.pageNum === 1">-->
         <!--        <span>如对搜索结果满意,可直接订阅及时接收项目信息。</span>-->
@@ -98,15 +103,19 @@ const articleRef = ref({
         <template #item-checkbox v-if="activeItemStyleType === 'T'">
           <span></span>
         </template>
-        <template v-slot:table='{ list }' v-if="activeItemStyleType === 'T'">
+        <template v-slot:table="{ list }" v-if="activeItemStyleType === 'T'">
           <search-list-table
             :list="tableList"
-            :list-state='listState'
-            @to-detail='toDetail'
-            :table-fixed-top='tableFixedTop'
+            :list-state="listState"
+            @to-detail="toDetail"
+            :table-fixed-top="tableFixedTop"
+            :matchKeys="[filterState.keyWords]"
           ></search-list-table>
         </template>
-        <template v-slot:item="{ item, index }" v-if="activeItemStyleType !== 'T'">
+        <template
+          v-slot:item="{ item, index }"
+          v-if="activeItemStyleType !== 'T'"
+        >
           <div>
             <article-item
               class="list-item"
@@ -122,9 +131,7 @@ const articleRef = ref({
               @onJoinBid="onJoinBid"
               :config="articleRef"
             >
-              <template #bi-slot=" { item }">
-
-              </template>
+              <template #bi-slot="{ item }"> </template>
               <template #right-handle-container>
                 <div
                   v-if="inInjectBI"
@@ -138,7 +145,7 @@ const articleRef = ref({
           </div>
         </template>
         <template #empty>
-          <empty :mtb60="false"  images="jy-back.png">
+          <empty :mtb60="false" images="jy-back.png">
             <div v-if="isDefaultParams" class="no-data-container">
               <p>暂未收藏标讯</p>
               <button class="collect-btn" @click="goCollect">前往收藏</button>
@@ -186,7 +193,7 @@ const articleRef = ref({
         </div>
       </div>
     </div>
-     <!--数据导出提示框-->
+    <!--数据导出提示框-->
     <custom-dialog
       @close="showDataExportDialog = false"
       customClass="export-class-dialog"
@@ -208,10 +215,12 @@ const articleRef = ref({
       center
       :visible.sync="showVipDialog"
     >
-      {{ vipDialogText}}
+      {{ vipDialogText }}
       <template #footer>
         <button class="action-button confirm" @click="toBuySvip">去开通</button>
-        <button class="action-button cancel" @click="closeVipDialog">取消</button>
+        <button class="action-button cancel" @click="closeVipDialog">
+          取消
+        </button>
       </template>
     </CustomDialog>
     <!-- 参标更新状态弹窗 -->
@@ -245,25 +254,25 @@ const articleRef = ref({
 </style>
 <style scoped lang="scss">
 .in-app {
-  .collection-page{
+  .collection-page {
     width: 100%;
     padding: 24px;
   }
 }
-.collection-page{
+.collection-page {
   width: 1200px;
   margin: 0 auto;
   padding: 24px 0;
-  .page-title{
+  .page-title {
     padding-bottom: 24px;
     font-size: 24px;
     line-height: 36px;
     color: #1d1d1d;
   }
-  .page-filter-container{
+  .page-filter-container {
     background: #fff;
   }
-  .page-list-container{
+  .page-list-container {
     position: relative;
     margin-top: 20px;
   }
@@ -283,7 +292,7 @@ const articleRef = ref({
     box-sizing: content-box;
     min-width: 42px;
   }
-  .bi-batch-add-button{
+  .bi-batch-add-button {
     &.all-add {
       margin-right: 16px;
       font-size: 14px;
@@ -291,31 +300,31 @@ const articleRef = ref({
       cursor: pointer;
     }
   }
-  .no-data-container{
+  .no-data-container {
     padding-bottom: 40px;
     text-align: center;
     font-size: 16px;
   }
-  .collect-btn{
+  .collect-btn {
     width: 108px;
     height: 30px;
     margin-top: 24px;
-    background: #2ABED1;
+    background: #2abed1;
     color: #fff;
     font-size: 14px;
-    border-radius: 4px
+    border-radius: 4px;
   }
-  ::v-deep{
-    .search-header-container{
+  ::v-deep {
+    .search-header-container {
       border-bottom: 1px solid #ececec;
     }
     .search-schema-filter-item:nth-child(2) {
       margin-top: 0;
     }
-    .a-i-detail{
+    .a-i-detail {
       padding-left: 0;
     }
-    .vip-module{
+    .vip-module {
       padding-left: 10px;
       padding-right: 0;
     }

+ 128 - 0
apps/bigmember_pc/src/views/search/bidding/components/current-filter-text.vue

@@ -0,0 +1,128 @@
+<script setup>
+import { computed, nextTick, ref } from 'vue'
+const props = defineProps({
+  data: {
+    type: Object,
+    default: {}
+  }
+})
+
+const emit = defineEmits(['closeCallBack'])
+
+function closeCallBack(key) {
+  emit('closeCallBack', key)
+}
+
+// 计算最大宽度
+// function calcItemWidth() {
+//   const ele = document.querySelector('.current-filter-text-box')
+//   if (ele) {
+//     const width = ele.clientWidth
+//     const childrenLen = ele.children.length || 0
+//     const maxWidth = Math.floor(width / 6)
+//     const fValueNode = document.querySelectorAll(
+//       '.current-filter-text-box .f-value'
+//     )
+//     if (childrenLen > 0) {
+//       Array.from(fValueNode).forEach((fNode) => {
+//         fNode.style.maxWidth = maxWidth + 'px'
+//       })
+//     }
+//   }
+// }
+// nextTick(() => {
+//   // calcItemWidth()
+// })
+
+const textKeyObj = computed(() => {
+  return {
+    publishTime: props.data.publishTimeText,
+    selectType: props.data.scopeText,
+    subtype: props.data.infoTypeText,
+    regionMap: props.data.regionMapText,
+    industry: props.data.industryText ? `行业:${props.data.industryText}` : '',
+    fileExists: props.data.fileExistsText,
+    price: props.data.priceText,
+    mobileTag:
+      props.data.mobileTagText && props.data.mobileTagText !== 'all'
+        ? props.data.mobileTagText
+        : '',
+    buyerclass: props.data.buyerClassText
+      ? `采购单位类型:${props.data.buyerClassText}`
+      : '',
+    buyertel: props.data.buyerTelText,
+    winnertel: props.data.winnerTelText,
+    notkey: props.data.notkey ? `排除词:${props.data.notkey}` : '',
+    buyer: props.data.buyer ? `采购单位:${props.data.buyer}` : '',
+    winner: props.data.winner ? `中标企业:${props.data.winner}` : '',
+    agency: props.data.agency ? `招标代理:${props.data.agency}` : ''
+  }
+})
+</script>
+
+<template>
+  <ul class="current-filter-text-box">
+    <template v-for="(value, key) in textKeyObj">
+      <el-tooltip
+        class="f-text-tip"
+        effect="dark"
+        placement="top"
+        :content="value"
+        popper-class="f-text-tip"
+        v-if="value"
+      >
+        <li>
+          <span class="f-value">{{ value }}</span>
+          <i
+            class="iconfont icon-close"
+            @click="closeCallBack(key)"
+            v-if="key !== 'publishTime' && key !== 'selectType'"
+          ></i>
+        </li>
+      </el-tooltip>
+    </template>
+  </ul>
+</template>
+
+<style lang="scss">
+.f-text-tip {
+  max-width: 300px;
+  &.el-tooltip__popper[x-placement^='top'] .popper__arrow {
+    bottom: -5px !important;
+  }
+}
+</style>
+
+<style lang="scss" scoped>
+.current-filter-text-box {
+  max-height: 102px;
+  overflow: hidden;
+  margin-bottom: 4px;
+  li {
+    padding: 0 8px;
+    border-radius: 12px;
+    border: 1px solid #2abed1;
+    background: linear-gradient(90deg, #eaf8fa 0%, #ffffff 100%);
+    color: #2abed1;
+    font-size: 14px;
+    line-height: 22px;
+    margin: 0 12px 12px 0;
+    display: flex;
+    align-items: center;
+    max-width: 223px;
+    .f-value {
+      display: inline-block;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      text-align: justify;
+      max-width: 180px;
+    }
+  }
+  .icon-close {
+    font-size: 16px;
+    margin-left: 10px;
+    cursor: pointer;
+  }
+}
+</style>

+ 107 - 67
apps/bigmember_pc/src/views/search/bidding/components/history-filter-dialog.vue

@@ -1,41 +1,37 @@
 <script setup>
 import { SearchBidModel } from '../model'
 
-const {
-  onSelectedFilter,
-  disposeFilterActionModel
-} = SearchBidModel
+const { onSelectedFilter, disposeFilterActionModel } = SearchBidModel
 
 const {
   filterHistoryList: filterData,
   onHasToggle, // 展开收起
-  onDeleteFilter, // 删除单条已存筛选条件
+  onDeleteFilter // 删除单条已存筛选条件
 } = disposeFilterActionModel
 
- const props = defineProps({
-   visible: {
-     type: Boolean,
-     default: false
-    }
- })
+const props = defineProps({
+  visible: {
+    type: Boolean,
+    default: false
+  }
+})
 
 // 关键词
-function formatToSpace (keywords, additionalWords, wordsModeText) {
+function formatToSpace(keywords, additionalWords, wordsModeText) {
   let str = ''
   if (additionalWords) {
-    if(keywords) {
+    if (keywords) {
       str += ','
     }
-    str += additionalWords.replace(/,/g, ",")  +'(' + wordsModeText + ')'
+    str += additionalWords.replace(/,/g, ',') + '(' + wordsModeText + ')'
   }
   return str
 }
 
 const emit = defineEmits(['before-close'])
-function beforeClose () {
+function beforeClose() {
   emit('before-close')
 }
-
 </script>
 
 <template>
@@ -48,42 +44,88 @@ function beforeClose () {
     width="750"
     :center="true"
     :visible.sync="visible"
-    :before-close='beforeClose'
+    :before-close="beforeClose"
   >
     <div class="filter-data-container">
       <div v-for="item in filterData" class="filter-data-list">
         <div class="f-l-title">
-          <div style="display: flex;align-items: center;flex:1;">
-            <i class="iconfont icon-xiala" :class="{ 'is-reverse': item.open}" @click="onHasToggle(item)"></i>
+          <div style="display: flex; align-items: center; flex: 1">
+            <i
+              class="iconfont icon-xiala"
+              :class="{ 'is-reverse': item.open }"
+              @click="onHasToggle(item)"
+            ></i>
             <span class="f-l-title-text" @click="onSelectedFilter(item)">
               {{ item.keywords }}
-              <span v-if="item.additionalWords">{{ formatToSpace(item.keywords, item.additionalWords, item.wordsModeText) }}</span>
+              <span v-if="item.additionalWords">{{
+                formatToSpace(
+                  item.keywords,
+                  item.additionalWords,
+                  item.wordsModeText
+                )
+              }}</span>
             </span>
           </div>
           <i class="iconfont icon-delete" @click="onDeleteFilter(item)"></i>
         </div>
-        <div class="has-search-model">搜索模式:{{ item.searchModeText}}</div>
+        <div class="has-search-model">搜索模式:{{ item.searchModeText }}</div>
         <el-collapse-transition :collapse-transition="false">
           <div v-show="item.open">
             <div class="f-l-content" @click="onSelectedFilter(item)">
-              <p class="f-l-c-item">搜索范围:<em class="i-value">{{ item.scopeText }}</em></p>
-              <p class="f-l-c-item" v-if="item.industry">行业:<em class="i-value">{{ item.industryText }}</em></p>
               <p class="f-l-c-item">
-                <span v-if="item.price">价格区间:<em class="i-value">{{ item.priceText }}</em></span>
-                <span v-if="item.publishTimeText">发布时间:<em class="i-value">{{ item.publishTimeText }}</em></span>
-                <span v-if="item.fileExistsText != '全部'">附件:<em class="i-value">{{ item.fileExistsText }}</em></span>
+                搜索范围:<em class="i-value">{{ item.scopeText }}</em>
+              </p>
+              <p class="f-l-c-item" v-if="item.industry">
+                行业:<em class="i-value">{{ item.industryText }}</em>
               </p>
-              <p class="f-l-c-item" v-if="item.regionMapText">项目地区:<em class="i-value">{{ item.regionMapText }}</em></p>
-              <p class="f-l-c-item" v-if="item.infoTypeText">信息类型:<em class="i-value">{{ item.infoTypeText }}</em></p>
-              <p class="f-l-c-item" v-if="item.buyerClassText">采购单位类型:<em class="i-value">{{ item.buyerClassText }}</em></p>
               <p class="f-l-c-item">
-                <span v-if="item.buyerTel === 'y'">采购单位联系方式:<em class="i-value">{{ item.buyerTelText }}</em></span>
-                <span v-if="item.winnerTel === 'y'">中标单位联系方式:<em class="i-value">{{ item.winnerTelText }}</em></span>
-                <span v-if="item.notkey">排除词:<em class="i-value">{{ item.notkey }}</em></span>
+                <span v-if="item.price"
+                  >金额:<em class="i-value">{{ item.priceText }}</em></span
+                >
+                <span v-if="item.publishTimeText"
+                  >发布时间:<em class="i-value">{{
+                    item.publishTimeText
+                  }}</em></span
+                >
+                <span v-if="item.fileExistsText != '全部'"
+                  >附件:<em class="i-value">{{
+                    item.fileExistsText
+                  }}</em></span
+                >
+              </p>
+              <p class="f-l-c-item" v-if="item.regionMapText">
+                地区:<em class="i-value">{{ item.regionMapText }}</em>
+              </p>
+              <p class="f-l-c-item" v-if="item.infoTypeText">
+                信息类型:<em class="i-value">{{ item.infoTypeText }}</em>
+              </p>
+              <p class="f-l-c-item" v-if="item.buyerClassText">
+                采购单位类型:<em class="i-value">{{ item.buyerClassText }}</em>
+              </p>
+              <p class="f-l-c-item">
+                <span v-if="item.buyerTel === 'y'"
+                  >采购单位联系方式:<em class="i-value">{{
+                    item.buyerTelText
+                  }}</em></span
+                >
+                <span v-if="item.winnerTel === 'y'"
+                  >中标单位联系方式:<em class="i-value">{{
+                    item.winnerTelText
+                  }}</em></span
+                >
+                <span v-if="item.notkey"
+                  >排除词:<em class="i-value">{{ item.notkey }}</em></span
+                >
+              </p>
+              <p class="f-l-c-item" v-if="item.buyer">
+                采购单位:<em class="i-value">{{ item.buyer }}</em>
+              </p>
+              <p class="f-l-c-item" v-if="item.winner">
+                中标企业:<em class="i-value">{{ item.winner }}</em>
+              </p>
+              <p class="f-l-c-item" v-if="item.agency">
+                招标代理:<em class="i-value">{{ item.agency }}</em>
               </p>
-              <p class="f-l-c-item" v-if="item.buyer">采购单位:<em class="i-value">{{ item.buyer }}</em></p>
-              <p class="f-l-c-item" v-if="item.winner">中标企业:<em class="i-value">{{ item.winner }}</em></p>
-              <p class="f-l-c-item" v-if="item.agency">招标代理机构:<em class="i-value">{{ item.agency }}</em></p>
             </div>
           </div>
         </el-collapse-transition>
@@ -92,32 +134,31 @@ function beforeClose () {
   </el-dialog>
 </template>
 
-<style lang='scss' scoped>
-
+<style lang="scss" scoped>
 ::v-deep {
-  .filter-dialog{
+  .filter-dialog {
     padding: 32px;
-    border-radius: 8px!important;
+    border-radius: 8px !important;
     & ::-webkit-scrollbar {
       /*滚动条整体样式*/
-      width: 2px!important;
+      width: 2px !important;
     }
   }
-  .el-dialog{
+  .el-dialog {
     width: 750px !important;
   }
-  .el-dialog__body{
+  .el-dialog__body {
     padding: 0;
   }
 }
-.filter-dialog{
+.filter-dialog {
   .el-dialog__header {
     padding: 0;
-    .el-dialog__title{
-      color: #1D1D1D;
+    .el-dialog__title {
+      color: #1d1d1d;
     }
   }
-  .el-dialog__body{
+  .el-dialog__body {
     width: 686px;
     overflow: hidden;
   }
@@ -126,7 +167,7 @@ function beforeClose () {
     overflow-y: scroll;
     //width: 694px;
 
-    .f-l-title{
+    .f-l-title {
       padding: 8px 0 2px;
     }
     .f-l-content {
@@ -137,25 +178,25 @@ function beforeClose () {
       cursor: pointer;
     }
 
-    .filter-data-list{
+    .filter-data-list {
       margin-top: 12px;
       padding: 0 16px;
-      background: #F5F6F7;
+      background: #f5f6f7;
       border-radius: 4px;
-      .has-search-model{
-        padding:0 0 8px 22px;
+      .has-search-model {
+        padding: 0 0 8px 22px;
         font-size: 12px;
         line-height: 18px;
       }
-      .f-l-title{
+      .f-l-title {
         display: flex;
         align-items: center;
         justify-content: space-between;
         cursor: pointer;
         font-size: 14px;
         min-height: 22px;
-        color: #1D1D1D;
-        .f-l-title-text{
+        color: #1d1d1d;
+        .f-l-title-text {
           flex: 1;
           text-align: justify;
           font-size: 14px;
@@ -164,55 +205,54 @@ function beforeClose () {
         }
       }
       .f-l-title:hover {
-        .f-l-title-text{
+        .f-l-title-text {
           color: #2cb7ca;
         }
-        .icon-xiala{
+        .icon-xiala {
           color: #2cb7ca;
         }
-        .icon-delete{
+        .icon-delete {
           font-size: 18px;
           color: #2cb7ca;
         }
       }
-      .f-l-c-item{
+      .f-l-c-item {
         margin-top: 8px;
         line-height: 18px;
         span {
           margin-right: 16px;
         }
         .i-value {
-          color: #1D1D1D;
+          color: #1d1d1d;
         }
       }
     }
   }
 }
-.has-filter-dialog{
-  .el-dialog__headerbtn{
+.has-filter-dialog {
+  .el-dialog__headerbtn {
     font-size: 18px;
     top: 34px;
     right: 32px;
   }
 }
 
-.icon-xiala{
+.icon-xiala {
   display: inline-block;
   font-size: 18px;
   flex-shrink: 0;
   transform: rotate(0deg);
-  transition: transform .5s;
+  transition: transform 0.5s;
   margin-right: 4px;
   cursor: pointer;
-  &.is-reverse{
+  &.is-reverse {
     transform: rotate(180deg);
   }
 }
 .icon-delete {
   display: inline-block;
-  font-size:22px;
-  color:#aeaeae;
+  font-size: 22px;
+  color: #aeaeae;
   cursor: pointer;
 }
-
 </style>

+ 89 - 47
apps/bigmember_pc/src/views/search/bidding/components/save-filter-dialog.vue

@@ -11,28 +11,32 @@ const props = defineProps({
   }
 })
 // 关键词
-const additionalWordsCon = computed (() => {
+const additionalWordsCon = computed(() => {
   let str = ''
   if (currentFilter.value.additionalWords) {
-    if(currentFilter.value.keywords) {
+    if (currentFilter.value.keywords) {
       str += ','
     }
-    str += currentFilter.value.additionalWords.replace(/,/g, ",")  +'(' + currentFilter.value.wordsModeText + ')'
+    str +=
+      currentFilter.value.additionalWords.replace(/,/g, ',') +
+      '(' +
+      currentFilter.value.wordsModeText +
+      ')'
   }
   return str
 })
 
 // 处理筛选数据-英文逗号转空格
-function formatToSpace (val) {
+function formatToSpace(val) {
   if (!val) return
-  return val.replace(/,/g, " ")
+  return val.replace(/,/g, ' ')
 }
 
 const emit = defineEmits(['cancel', 'confirm'])
-function cancelHandle () {
+function cancelHandle() {
   emit('cancel')
 }
-function confirmHandle () {
+function confirmHandle() {
   emit('confirm')
 }
 </script>
@@ -45,8 +49,10 @@ function confirmHandle () {
     :show-close="false"
     :close-on-click-modal="false"
     :close-on-press-escape="false"
-    width="750" :center="true"
-    :visible.sync="visible">
+    width="750"
+    :center="true"
+    :visible.sync="visible"
+  >
     <div class="filter-save-item">
       <div class="save-label">关键词:</div>
       <div class="save-value">
@@ -60,57 +66,93 @@ function confirmHandle () {
     <div class="filter-save-item">
       <div class="save-label">筛选条件:</div>
       <div class="save-value">
-        <div class="save-value-bg"><span>搜索范围:</span>{{ currentFilter.scopeText }}</div>
-        <div class="save-value-bg" v-if="currentFilter.industry"><span>行业:</span>{{ currentFilter.industryText }}</div>
-        <div style="display: flex;">
-          <div class="save-value-bg" v-if="currentFilter.priceText"><span>价格区间:</span>{{ currentFilter.priceText }}</div>
-          <div class="save-value-bg" v-if="currentFilter.publishTime"><span>发布时间:</span>{{ currentFilter.publishTimeText }}</div>
-          <div class="save-value-bg" v-if="currentFilter.fileExistsText != '全部'"><span>附件:</span>{{ currentFilter.fileExistsText }}</div>
+        <div class="save-value-bg">
+          <span>搜索范围:</span>{{ currentFilter.scopeText }}
         </div>
-        <div class="save-value-bg" v-if="currentFilter.regionMapText"><span>项目地区:</span>{{ currentFilter.regionMapText }}</div>
-        <div class="save-value-bg" v-if="currentFilter.infoType"><span>信息类型:</span>{{ currentFilter.infoTypeText }}</div>
-        <div class="save-value-bg" v-if="currentFilter.buyerClass"><span>采购单位类型:</span>{{ currentFilter.buyerClassText }}</div>
-        <div style="display: flex;">
-          <div class="save-value-bg" v-if="currentFilter.buyerTel"><span>采购单位联系方式:</span>{{ currentFilter.buyerTelText }}</div>
-          <div class="save-value-bg" v-if="currentFilter.winnerTel"><span>中标单位联系方式:</span>{{ currentFilter.winnerTelText }}</div>
-          <div class="save-value-bg" v-if="currentFilter.notkey"><span>排除词:</span>{{ formatToSpace(currentFilter.notkey) }}</div>
+        <div class="save-value-bg" v-if="currentFilter.industry">
+          <span>行业:</span>{{ currentFilter.industryText }}
+        </div>
+        <div style="display: flex">
+          <div class="save-value-bg" v-if="currentFilter.priceText">
+            <span>金额:</span>{{ currentFilter.priceText }}
+          </div>
+          <div class="save-value-bg" v-if="currentFilter.publishTime">
+            <span>发布时间:</span>{{ currentFilter.publishTimeText }}
+          </div>
+          <div
+            class="save-value-bg"
+            v-if="currentFilter.fileExistsText != '全部'"
+          >
+            <span>附件:</span>{{ currentFilter.fileExistsText }}
+          </div>
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.regionMapText">
+          <span>地区:</span>{{ currentFilter.regionMapText }}
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.infoType">
+          <span>信息类型:</span>{{ currentFilter.infoTypeText }}
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.buyerClass">
+          <span>采购单位类型:</span>{{ currentFilter.buyerClassText }}
+        </div>
+        <div style="display: flex">
+          <div class="save-value-bg" v-if="currentFilter.buyerTel">
+            <span>采购单位联系方式:</span>{{ currentFilter.buyerTelText }}
+          </div>
+          <div class="save-value-bg" v-if="currentFilter.winnerTel">
+            <span>中标单位联系方式:</span>{{ currentFilter.winnerTelText }}
+          </div>
+          <div class="save-value-bg" v-if="currentFilter.notkey">
+            <span>排除词:</span>{{ formatToSpace(currentFilter.notkey) }}
+          </div>
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.buyer">
+          <span>采购单位:</span>{{ formatToSpace(currentFilter.buyer) }}
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.winner">
+          <span>中标企业:</span>{{ formatToSpace(currentFilter.winner) }}
+        </div>
+        <div class="save-value-bg" v-if="currentFilter.agency">
+          <span>招标代理:</span>{{ formatToSpace(currentFilter.agency) }}
         </div>
-        <div class="save-value-bg" v-if="currentFilter.buyer"><span>采购单位:</span>{{ formatToSpace(currentFilter.buyer) }}</div>
-        <div class="save-value-bg" v-if="currentFilter.winner"><span>中标企业:</span>{{ formatToSpace(currentFilter.winner) }}</div>
-        <div class="save-value-bg" v-if="currentFilter.agency"><span>招标代理机构:</span>{{ formatToSpace(currentFilter.agency) }}</div>
       </div>
     </div>
     <span slot="footer" class="dialog-footer">
-        <el-button type="primary" class="btn-group confirm-btn" @click="confirmHandle">确 定</el-button>
-        <el-button class="btn-group cancel-btn" @click="cancelHandle">取 消</el-button>
-      </span>
+      <el-button
+        type="primary"
+        class="btn-group confirm-btn"
+        @click="confirmHandle"
+        >确 定</el-button
+      >
+      <el-button class="btn-group cancel-btn" @click="cancelHandle"
+        >取 消</el-button
+      >
+    </span>
   </el-dialog>
 </template>
 
-
 <style lang="scss" scoped>
-
 ::v-deep {
-  .filter-dialog{
+  .filter-dialog {
     padding: 32px;
-    border-radius: 8px!important;
+    border-radius: 8px !important;
   }
-  .el-dialog{
+  .el-dialog {
     width: 750px !important;
   }
 }
 
-.filter-dialog{
+.filter-dialog {
   width: 750px;
   .el-dialog__header {
     padding: 0;
-    .el-dialog__title{
-      color: #1D1D1D;
+    .el-dialog__title {
+      color: #1d1d1d;
     }
   }
   &.save-filter-dialog {
     .el-dialog__body {
-      padding: 0 0 32px!important;
+      padding: 0 0 32px !important;
     }
   }
   .btn-group {
@@ -130,17 +172,17 @@ function confirmHandle () {
   .btn-group.confirm-btn:focus {
     color: #fff;
   }
-  .btn-group.cancel-btn:hover{
+  .btn-group.cancel-btn:hover {
     background: unset;
-    border-color: #DCDFE6;
+    border-color: #dcdfe6;
     color: #606266;
   }
-  .filter-save-item{
+  .filter-save-item {
     display: flex;
     margin-top: 20px;
     line-height: 18px;
 
-    .save-label{
+    .save-label {
       min-width: 60px;
       text-align: right;
       color: #636467;
@@ -150,27 +192,27 @@ function confirmHandle () {
     .save-value {
       margin-left: 8px;
       flex: 1;
-      color: #1D1D1D;
+      color: #1d1d1d;
       text-align: left;
       font-size: 12px;
     }
 
-    .save-value-bg{
+    .save-value-bg {
       margin-bottom: 8px;
       margin-right: 8px;
       padding: 6px 8px;
-      background: #F5F6F7;
+      background: #f5f6f7;
       border-radius: 4px;
       font-size: 12px;
-      color: #1D1D1D;
+      color: #1d1d1d;
       line-height: 18px;
 
-      & > span{
+      & > span {
         color: #636467;
       }
     }
 
-    .search_model{
+    .search_model {
       margin-top: 4px;
       font-size: 12px;
       line-height: 18px;

+ 79 - 72
apps/bigmember_pc/src/views/search/bidding/components/search-bid-filter.vue

@@ -19,32 +19,31 @@ const {
   filterState,
   updateFilterBase,
   doQuery,
-  showFilter,
   goLogin,
   disposeFilterSchema,
-  onChangeTab,
+  onChangeTab
 } = SearchBidModel
 
-const  {
+const {
   SearchBidBaseSchema,
   SearchBidMoreSchema,
   searchBidMoreFreeSchema,
   searchBidMoreVipSchema,
   doUpdateData
-} =  disposeFilterSchema()
+} = disposeFilterSchema()
 
 watch(activeTab, (newVal) => {
   doUpdateData()
 })
 
 // 物业专版获取筛选条件,更新视图
-async function getBiPropertyFilters () {
-  const { error_code: code, data} = await getPropertyFilters()
-  if(code === 0) {
+async function getBiPropertyFilters() {
+  const { error_code: code, data } = await getPropertyFilters()
+  if (code === 0) {
     let newData = {}
-    Object.keys(data).forEach(v => {
+    Object.keys(data).forEach((v) => {
       newData[v] = []
-      data[v].forEach(s => {
+      data[v].forEach((s) => {
         let sArr = s.split('#')
         s = {
           label: sArr[0],
@@ -56,26 +55,26 @@ async function getBiPropertyFilters () {
     doUpdateData(newData)
   }
 }
-if(inBIPropertyIframe) {
+if (inBIPropertyIframe) {
   getBiPropertyFilters()
 }
 
 // 中国移动定制搜索条件-融创
-async function getCustomInfo () {
+async function getCustomInfo() {
   const _storageKey = 'search_bidding_expandSearchParams'
   localStorage.removeItem(_storageKey)
-  const { error_code:code, data = [] } = await getCMCustomInfo()
-  if(code === 0) {
+  const { error_code: code, data = [] } = await getCMCustomInfo()
+  if (code === 0) {
     if (data) {
       const expandSearchParams = {}
-      data.forEach(item => {
-        if(item.key && item.defaultVal) {
+      data.forEach((item) => {
+        if (item.key && item.defaultVal) {
           const par = {
             key: item.key,
             value: item.defaultVal
           }
           expandSearchParams[item.key] = item.defaultVal
-          updateFilterBase(par)
+          updateFilterBase(par, 'expand')
         }
       })
       localStorage.setItem(_storageKey, JSON.stringify(expandSearchParams))
@@ -84,7 +83,7 @@ async function getCustomInfo () {
     }
   }
 }
-if(!inBIPropertyIframe) {
+if (!inBIPropertyIframe) {
   getCustomInfo()
 }
 
@@ -117,66 +116,61 @@ function toLogin() {
 function doChangeFilter() {
   doQuery()
 }
-
 </script>
 
 <template>
-  <el-collapse-transition>
-    <div class="search-bid-filter" v-show="showFilter">
-      <div class="guide-go-workspace" v-if="isInWeb">
-        最近五年数据查询以及更多筛选条件请
-        <span class="highlight-text">"</span>
-        <span class="cursor-button highlight-text" @click="guideGoWorkSpace">{{ isLogin ? '' : '登录后' }}进入工作台</span>
-        <span class="highlight-text">"</span>
-        检索
-      </div>
-      <!--  标准筛选  -->
+  <div class="search-bid-filter">
+    <div class="guide-go-workspace" v-if="isInWeb">
+      最近五年数据查询以及更多筛选条件请
+      <span class="highlight-text">"</span>
+      <span class="cursor-button highlight-text" @click="guideGoWorkSpace"
+        >{{ isLogin ? '' : '登录后' }}进入工作台</span
+      >
+      <span class="highlight-text">"</span>
+      检索
+    </div>
+    <!--  标准筛选  -->
+    <search-schema-filter
+      v-model="filterState"
+      :schema="SearchBidBaseSchema"
+      @change="doChangeFilter"
+    ></search-schema-filter>
+
+    <!--  更多筛选  -->
+    <div class="more-filters-container" :class="{ 'wrap-line': !isVip }">
       <search-schema-filter
+        v-if="isVip && isInApp"
         v-model="filterState"
-        :schema="SearchBidBaseSchema"
+        :schema="SearchBidMoreSchema"
+        :show-label="false"
+        showRowLabel
+        style-type="row"
         @change="doChangeFilter"
-      ></search-schema-filter>
-
-      <!--  更多筛选  -->
-      <div
-        class="more-filters-container"
-        :class="{ 'wrap-line': !isVip }"
       >
-        <search-schema-filter
-          v-if="isVip && isInApp"
+        <span slot="row-label-text">更多筛选:</span>
+      </search-schema-filter>
+      <template v-else>
+        <SelectorWithBasePower
+          :component="SearchSchemaFilter"
+          :commonConf="customMoreSchema.commonConf"
+          :freeConf="customMoreSchema.freeConf"
+          :vipConf="customMoreSchema.vipConf"
           v-model="filterState"
-          :schema="SearchBidMoreSchema"
-          :show-label="false"
-          showRowLabel
-          style-type="row"
+          vipMaskShow
+          :baseMaskShow="!isLogin"
+          :vipModuleShow="isInApp && !inBIPropertyIframe"
+          @clickVipMask="noPower"
+          @clickBaseMask="toLogin"
           @change="doChangeFilter"
-        >
-          <span slot="row-label-text">更多筛选:</span>
-        </search-schema-filter>
-        <template v-else>
-          <SelectorWithBasePower
-            :component="SearchSchemaFilter"
-            :commonConf="customMoreSchema.commonConf"
-            :freeConf="customMoreSchema.freeConf"
-            :vipConf="customMoreSchema.vipConf"
-            v-model="filterState"
-            vipMaskShow
-            :baseMaskShow="!isLogin"
-            :vipModuleShow="isInApp && !inBIPropertyIframe"
-            @clickVipMask="noPower"
-            @clickBaseMask="toLogin"
-            @change="doChangeFilter"
-          ></SelectorWithBasePower>
-        </template>
-      </div>
+        ></SelectorWithBasePower>
+      </template>
     </div>
-  </el-collapse-transition>
+  </div>
 </template>
 
 <style lang="scss" scoped>
-
 @media (min-width: 1456px) {
-  .in-app{
+  .in-app {
     .search-bid-filter {
       .wrap-line {
         ::v-deep {
@@ -203,32 +197,45 @@ function doChangeFilter() {
       }
     }
   }
-  .guide-go-workspace{
+  .guide-go-workspace {
     left: 345px;
     position: absolute;
     border-radius: 4px;
-    background: linear-gradient(270deg, rgba(42, 190, 209, 0.24) 1.5%, rgba(42, 190, 209, 0.12) 97.45%);
+    background: linear-gradient(
+      270deg,
+      rgba(42, 190, 209, 0.24) 1.5%,
+      rgba(42, 190, 209, 0.12) 97.45%
+    );
     padding: 2px 8px;
-    color: #1D1D1D;
+    color: #1d1d1d;
     font-size: 16px;
     font-style: normal;
     font-weight: 400;
     line-height: 22px;
 
-    .highlight-text{
-      color: #2ABED1;
+    .highlight-text {
+      color: #2abed1;
       font-weight: 700;
-      font-family: -apple-system, system-ui, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+      font-family:
+        -apple-system,
+        system-ui,
+        BlinkMacSystemFont,
+        Helvetica Neue,
+        PingFang SC,
+        Hiragino Sans GB,
+        Microsoft YaHei,
+        Arial,
+        sans-serif;
     }
-    .cursor-button{
+    .cursor-button {
       text-decoration-line: underline;
       background: transparent;
       padding: 0;
       cursor: pointer;
     }
   }
-  .more-filters-container{
-    margin-top:6px;
+  .more-filters-container {
+    margin-top: 6px;
     margin-right: 38px;
   }
 }

+ 66 - 15
apps/bigmember_pc/src/views/search/bidding/components/search-bid-header.vue

@@ -22,7 +22,9 @@ const {
   SearchTabsModel,
   goWorkSpace,
   clearHistoryQuery,
-  searchHistoryList
+  searchHistoryList,
+  toggleFilter,
+  showFilter
 } = SearchBidModel
 
 const { searchTabs } = SearchTabsModel
@@ -35,8 +37,8 @@ function doSearch($event) {
   return doQuery({}, firstSearch)
 }
 // 跳转信息发布
-function goToPublish () {
-  if(!isLogin.value){
+function goToPublish() {
+  if (!isLogin.value) {
     location.href = '/swordfish/frontPage/InformationDistribution/free/index'
     return
   }
@@ -53,8 +55,8 @@ function goToPublish () {
   }
 }
 
-function checkPower ($event) {
-  if(!isLogin.value) {
+function checkPower($event) {
+  if (!isLogin.value) {
     $bus.$emit('bidding:goLogin')
     return false
   } else {
@@ -62,8 +64,8 @@ function checkPower ($event) {
   }
 }
 // 未登录--多个关键词切换处理
-function onSelectMoreKey () {
-  if(!isLogin.value) {
+function onSelectMoreKey() {
+  if (!isLogin.value) {
     inputKeywordsState.value.selectMoreKey = false
     $bus.$emit('bidding:goLogin')
   }
@@ -73,11 +75,10 @@ const showNewPublish = computed(() => {
   return !isInBI.value && !isBidField
 })
 
-function onClearSearchHistory () {
-  if(!searchHistoryList.value || searchHistoryList.value.length === 0) return
+function onClearSearchHistory() {
+  if (!searchHistoryList.value || searchHistoryList.value.length === 0) return
   clearHistoryQuery({ type: 1 })
 }
-
 </script>
 
 <template>
@@ -96,6 +97,20 @@ function onClearSearchHistory () {
       @clearSearch="onClearSearchHistory"
       :immediateSearch="false"
     >
+      <template slot="tab-other" v-if="showNewPublish">
+        <!-- 工作台内外样式不同-->
+        <div class="search-tab-right news-publish-btn">
+          <el-button
+            class="use-badge"
+            data-badge="限免"
+            :class="{ outside: !isInApp }"
+            type="primary"
+            @click="goToPublish"
+          >
+            {{ isLogin ? '信息发布' : '免费发布信息' }}
+          </el-button>
+        </div>
+      </template>
       <div class="flex flex-(row items-center)">
         <div class="flex flex-(row items-center)">
           <common-single-choice
@@ -136,10 +151,12 @@ function onClearSearchHistory () {
         >
           多个关键词
         </el-checkbox>
-        <div class="m-l-24px" v-if="showNewPublish">
-          <el-button class="use-badge" data-badge="限免" type="primary" @click='goToPublish'>
-            {{ isLogin ? '信息发布': '免费发布信息'}}
-          </el-button>
+        <div class="show-filter-handle m-l-16px" @click="toggleFilter">
+          <span>筛选</span>
+          <i
+            class="iconfont"
+            :class="showFilter ? 'icon-a-zhankai1' : 'icon-shouqi1'"
+          ></i>
         </div>
       </div>
     </search-header-card>
@@ -170,6 +187,40 @@ function onClearSearchHistory () {
 
 <style lang="scss" scoped>
 .search-bid-header {
-  //
+  .show-filter-handle {
+    font-size: 14px;
+    line-height: 22px;
+    color: #1d1d1d;
+    cursor: pointer;
+    .iconfont {
+      color: #686868;
+      font-size: 16px;
+      margin-left: 4px;
+    }
+    &::before {
+      content: '';
+      display: inline-block;
+      height: 14px;
+      width: 1px;
+      background: #ececec;
+      margin-right: 16px;
+      vertical-align: middle;
+    }
+  }
+  .news-publish-btn {
+    .el-button.outside {
+      font-size: 16px;
+      line-height: 24px;
+      border-radius: 4px;
+      padding: 4px 8px;
+      margin-left: 12px;
+    }
+    .el-button {
+      border-radius: 8px;
+      font-size: 14px;
+      line-height: 22px;
+      padding: 7px 24px;
+    }
+  }
 }
 </style>

+ 121 - 107
apps/bigmember_pc/src/views/search/bidding/components/search-filter-header.vue

@@ -2,6 +2,7 @@
 import { ref } from 'vue'
 import SaveFilterDialog from '../components/save-filter-dialog.vue'
 import HistoryFilterDialog from '../components/history-filter-dialog.vue'
+import CurrentFilterText from '../components/current-filter-text'
 import { SearchBidModel } from '../model/index'
 const {
   isLogin,
@@ -11,8 +12,10 @@ const {
   onSaveFilter,
   onResetFilter,
   toggleFilter,
-  showFilter,
-  fixedTop
+  fixedTop,
+  showCurrentFilterText: filterText,
+  doQuery,
+  updateFilterBase
 } = SearchBidModel
 
 const {
@@ -21,143 +24,154 @@ const {
   historyFilterDialogVisible, //已存筛选条件弹窗
   saveFilterConfirm, // 确认保存筛选条件
   saveFilterCancel, // 取消保存筛选条件
-  onHasFilter, // 已存筛选条件操作
+  onHasFilter // 已存筛选条件操作
 } = disposeFilterActionModel
 
-function closeHistoryFilterDialog () {
+function closeHistoryFilterDialog() {
   historyFilterDialogVisible.value = false
 }
+
+// 已选筛选,删除某一项筛选项
+function resetFilterItem(key) {
+  updateFilterBase({ key }, 'resetItem')
+  doQuery({})
+}
 </script>
 
 <template>
-  <div class='searchTender'>
-    <div class="filter-header-container" :class="{'header-fixed': fixedTop}">
-      <div class="filter-header" :class="{'fixed-top': fixedTop}">
-        <div
-          class="f-h-label"
-          @click="toggleFilter"
-        >
-          <span>筛选条件</span>
-          <i class="iconfont icon-xiala highlight-text" :class="{ 'is-reverse': showFilter}"></i>
-        </div>
-        <div class="f-h-action" v-if="isLogin && isInApp && !inBIPropertyIframe">
-          <span class="action-item reset-item" @click="onResetFilter">重置筛选</span>
-          <span class="action-item has-item" @click="onHasFilter">已存筛选 {{ historyFilterCount || ''}}</span>
-          <span class="action-item save-item" @click="onSaveFilter">保存筛选</span>
-        </div>
+  <div class="searchTender">
+    <div class="filter-header-container" :class="{ 'header-fixed': fixedTop }">
+      <div class="filter-header" :class="{ 'fixed-top': fixedTop }">
+        <!--        已选条件-->
+        <section v-if="isLogin && isInApp && !inBIPropertyIframe">
+          <div class="f-h-current">
+            <span class="f-h-c-label">
+              <span>已选条件:</span>
+            </span>
+            <div class="f-h-c-container">
+              <current-filter-text
+                :data="filterText"
+                @closeCallBack="resetFilterItem"
+              ></current-filter-text>
+            </div>
+          </div>
+          <div class="f-h-action">
+            <span class="action-item save-item" @click="onSaveFilter">
+              <i class="icon-square-up"></i>保存
+            </span>
+            <span class="action-item reset-item" @click="onResetFilter">
+              <i class="iconfont icon-delete"></i>清空
+            </span>
+            <span class="action-item has-item" @click="onHasFilter">
+              <i class="icon-square-up"></i>已存{{ historyFilterCount || '' }}
+            </span>
+          </div>
+        </section>
       </div>
     </div>
     <save-filter-dialog
-      v-if='saveFilterDialogVisible'
+      v-if="saveFilterDialogVisible"
       :visible="saveFilterDialogVisible"
-      @cancel='saveFilterCancel'
-      @confirm='saveFilterConfirm'
+      @cancel="saveFilterCancel"
+      @confirm="saveFilterConfirm"
     ></save-filter-dialog>
     <history-filter-dialog
-      v-if='historyFilterDialogVisible'
+      v-if="historyFilterDialogVisible"
       :visible="historyFilterDialogVisible"
-      @before-close='closeHistoryFilterDialog'
+      @before-close="closeHistoryFilterDialog"
     >
     </history-filter-dialog>
   </div>
 </template>
 
 <style lang="scss" scoped>
+$mainColor: #2abed1;
+//.in-app {
+//  .filter-header-container.header-fixed {
+//    position: fixed;
+//    top: 0;
+//    left: 0;
+//    width: 100%;
+//    padding: 0 24px;
+//    box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.05);
+//    background: #ffffff;
+//    z-index: 99;
+//  }
+//  .filter-header-container.header-fixed .fixed-top {
+//    position: relative;
+//    width: auto;
+//    top: unset;
+//    border-bottom: unset;
+//  }
+//}
+.filter-header {
+  width: 100%;
+  padding: 0 32px;
+  background: #fff;
+
+  //&.fixed-top {
+  //  position: fixed;
+  //  top: 52px;
+  //  width: 1200px;
+  //  z-index: 99;
+  //}
+  section {
+    display: flex;
+    border-bottom: 1px solid #ececec;
+  }
 
-  .in-app{
-    .filter-header-container.header-fixed {
-      position: fixed;
-      top: 0;
-      left: 0;
-      width: 100%;
-      padding: 0 24px;
-      box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.05);
-      background: #FFFFFF;
-      z-index: 99;
+  .f-h-current {
+    flex: 1;
+    display: flex;
+    margin-bottom: 4px;
+    .f-h-c-label {
+      font-size: 14px;
+      line-height: 22px;
+      color: #686868;
+      margin-right: 12px;
     }
-    .filter-header-container.header-fixed .fixed-top {
-      position: relative;
-      width: auto;
-      top: unset;
-      border-bottom: unset;
+    .f-h-c-container {
+      flex: 1;
     }
   }
-  .filter-header{
-    width:100%;
+  .f-h-action {
     display: flex;
-    justify-content: space-between;
     align-items: center;
-    padding: 0 16px 0 22px;
-    height: 50px;
-    line-height: 50px;
-    background: #fff;
-    border-bottom: 1px solid #ECECEC;
-    border-top-left-radius: 8px;
-    border-top-right-radius: 8px;
-
-    &.fixed-top{
-      position: fixed;
-      top: 52px;
-      width: 1200px;
-      z-index: 99;
-    }
-
+    width: 186px;
+    margin-left: 13px;
+    align-self: flex-start;
 
-    .f-h-label{
-      width: 100px;
-      padding-left: 10px;
-      background-repeat: no-repeat;
-      background-position: right center;
-      background-size: 16px 16px;
+    .action-item {
       cursor: pointer;
-      & > span{
-        display: inline-block;
-        height: 100%;
-        font-size: 16px;
-        color: #2cb7ca;
-        border-bottom: 2px solid #2cb7ca;
-      }
-    }
-    .f-h-action{
+      font-size: 14px;
+      line-height: 22px;
+      color: #2abed1;
       display: flex;
       align-items: center;
-
-      .action-item{
-        width: 90px;
-        height: 30px;
-        line-height: 30px;
-        border-radius: 4px;
-        font-size: 14px;
-        text-align: center;
-        cursor: pointer;
-      }
-      .reset-item{
-        margin-right: 16px;
-        border: 1px solid #2cb7ca;
-        color: #2cb7ca;
-        background-color: #fff;
-      }
-      .has-item{
-        margin-right: 16px;
-        border: 1px solid #E0E0E0;
-        color: #1D1D1D;
-        background-color: #fff;
+      &:not(:last-of-type) {
+        margin-right: 12px;
       }
-      .save-item{
-        background: #2CB7CA;
-        border: 1px solid #2cb7ca;
-        color: #fff;
-      }
-    }
-    .icon-xiala{
-      display: inline-block;
-      font-size: 16px;
-      flex-shrink: 0;
-      transform: rotate(0deg);
-      transition: transform .5s;
-      &.is-reverse{
-        transform: rotate(180deg);
+      i {
+        margin-right: 4px;
       }
     }
   }
+  .icon-square-up {
+    display: inline-block;
+    width: 16px;
+    height: 16px;
+    background: url(@/assets/images/icon/square-up.png) no-repeat center;
+    background-size: contain;
+  }
+  //.icon-xiala {
+  //  display: inline-block;
+  //  font-size: 16px;
+  //  flex-shrink: 0;
+  //  transform: rotate(0deg);
+  //  transition: transform 0.5s;
+  //  &.is-reverse {
+  //    transform: rotate(180deg);
+  //  }
+  //}
+}
 </style>

+ 99 - 100
apps/bigmember_pc/src/views/search/bidding/components/search-list-table.vue

@@ -34,141 +34,140 @@ const props = defineProps({
   }
 })
 
-const  showTableMore = computed(() => {
+const showTableMore = computed(() => {
   return props.list.length >= 20 && props.listState.total > 20
 })
 
-function calcTitle (item)  {
-    if (!item.projectName) {
-      item.projectName = item.title
-    }
-    const { projectName, matchKeys } = item
-    const highKeys = getMatchKeys(matchKeys || [])
-    const hightLightedTitle = replaceKeyword(projectName, highKeys, [
-      '<span class="highlight-text">',
-      '</span>'
-    ])
-    return `${hightLightedTitle}`
+function calcTitle(item) {
+  if (!item.projectName) {
+    item.projectName = item.title
+  }
+  const { projectName, matchKeys } = item
+  const highKeys = getMatchKeys(matchKeys || [])
+  const hightLightedTitle = replaceKeyword(projectName, highKeys, [
+    '<span class="highlight-text-orange-bd">',
+    '</span>'
+  ])
+  return `${hightLightedTitle}`
 }
 
 function calcMoney(budget) {
-  if(budget && isNaN(budget)) {
+  if (budget && isNaN(budget)) {
     return budget
   } else if (budget && !isNaN(budget) && budget !== '0') {
-    return ( budget / 10000).toFixed(2).replace(
-      '.00',
-      ''
-    )
+    return (budget / 10000).toFixed(2).replace('.00', '')
   } else {
     return ''
   }
 }
-function  getMatchKeys(matchKeys) {
+function getMatchKeys(matchKeys) {
   return props.matchKeys.concat(matchKeys)
 }
 
 const emit = defineEmits(['before-close'])
-function toDetail (item) {
+function toDetail(item) {
   emit('to-detail', item)
 }
 </script>
 
 <template>
   <div
-      class="info-list search-table-list"
-      element-loading-background="rgba(255,255,255, .4)"
-      element-loading-custom-class="self-export-loading"
-    >
-    <div class='fixed-table' v-if='tableFixedTop'>
-      <table class="table" >
-        <thead class="thead fixed-head" >
-        <tr>
-          <td width="49.7">序号</td>
-          <td width="326.4" class="deep-border">项目名称</td>
-          <td width="87">公告类型</td>
-          <td width="75.6" class="deep-border">预算<br />(万元)</td>
-          <td width="187">招标单位</td>
-          <td width="106.7" class="deep-border">开标日期</td>
-          <td width="180.3">中标单位</td>
-          <td width="78.7" class="deep-border">中标金额<br />(万元)</td>
-          <td width="106.8">发布日期</td>
-        </tr>
-        </thead>
-      </table>
-    </div>
-      <table class="table" v-show="list.length">
-        <thead class="thead">
+    class="info-list search-table-list"
+    element-loading-background="rgba(255,255,255, .4)"
+    element-loading-custom-class="self-export-loading"
+  >
+    <div class="fixed-table" v-if="tableFixedTop">
+      <table class="table">
+        <thead class="thead fixed-head">
           <tr>
-            <td width="48">序号</td>
-            <td width="315" class="deep-border">项目名称</td>
-            <td width="84">公告类型</td>
-            <td width="73" class="deep-border">预算<br />(万元)</td>
-            <td width="181">招标单位</td>
-            <td width="103" class="deep-border">开标日期</td>
-            <td width="174">中标单位</td>
-            <td width="76" class="deep-border">中标金额<br />(万元)</td>
-            <td width="103">发布日期</td>
+            <td width="49.7">序号</td>
+            <td width="326.4" class="deep-border">项目名称</td>
+            <td width="87">公告类型</td>
+            <td width="75.6" class="deep-border">预算<br />(万元)</td>
+            <td width="187">招标单位</td>
+            <td width="106.7" class="deep-border">开标日期</td>
+            <td width="180.3">中标单位</td>
+            <td width="78.7" class="deep-border">中标金额<br />(万元)</td>
+            <td width="106.8">发布日期</td>
           </tr>
         </thead>
-        <tbody>
-          <tr
-            v-for="(item, index) in list"
-            :class="{ visited: item.visited }"
-            :key="index + '_' + item.id"
-            @click="toDetail(item)"
-            v-visited:articleContent="item.id"
-          >
-            <td width="48">{{ index + 1 }}</td>
-            <td width="315" class="tt-l" v-html="calcTitle(item, index)"></td>
-            <td width="84">{{ item.subtype ? item.subtype + '公告' : ''}}</td>
-            <td width="73" class="tt-r">{{ calcMoney(item.budget) }}</td>
-            <td width="181" class="tt-l">{{ item.buyer }}</td>
-            <td width="103">
-              {{
-                dateFromNow(
-                  item.bidOpenTime ? item.bidOpenTime * 1000 : null,
-                  'yyyy-MM-dd HH:mm'
-                )
-              }}
-            </td>
-            <td width="174" class="tt-l">{{ item.winner }}</td>
-            <td width="76" class="tt-r">{{ calcMoney(item.bidAmount) }}</td>
-            <td width="103">{{ dateFromNow(item.publishTime * 1000) }}</td>
-          </tr>
-        </tbody>
       </table>
-      <div class="shade_table" v-if="showTableMore">
-        <div class="more" data-need-bind-phone="" @click="onClickDataExport('table')">
-          查看更多&gt;
-        </div>
+    </div>
+    <table class="table" v-show="list.length">
+      <thead class="thead">
+        <tr>
+          <td width="48">序号</td>
+          <td width="315" class="deep-border">项目名称</td>
+          <td width="84">公告类型</td>
+          <td width="73" class="deep-border">预算<br />(万元)</td>
+          <td width="181">招标单位</td>
+          <td width="103" class="deep-border">开标日期</td>
+          <td width="174">中标单位</td>
+          <td width="76" class="deep-border">中标金额<br />(万元)</td>
+          <td width="103">发布日期</td>
+        </tr>
+      </thead>
+      <tbody>
+        <tr
+          v-for="(item, index) in list"
+          :class="{ visited: item.visited }"
+          :key="index + '_' + item.id"
+          @click="toDetail(item)"
+          v-visited:articleContent="item.id"
+        >
+          <td width="48">{{ index + 1 }}</td>
+          <td width="315" class="tt-l" v-html="calcTitle(item, index)"></td>
+          <td width="84">{{ item.subtype ? item.subtype + '公告' : '' }}</td>
+          <td width="73" class="tt-r">{{ calcMoney(item.budget) }}</td>
+          <td width="181" class="tt-l">{{ item.buyer }}</td>
+          <td width="103">
+            {{
+              dateFromNow(
+                item.bidOpenTime ? item.bidOpenTime * 1000 : null,
+                'yyyy-MM-dd HH:mm'
+              )
+            }}
+          </td>
+          <td width="174" class="tt-l">{{ item.winner }}</td>
+          <td width="76" class="tt-r">{{ calcMoney(item.bidAmount) }}</td>
+          <td width="103">{{ dateFromNow(item.publishTime * 1000) }}</td>
+        </tr>
+      </tbody>
+    </table>
+    <div class="shade_table" v-if="showTableMore">
+      <div
+        class="more"
+        data-need-bind-phone=""
+        @click="onClickDataExport('table')"
+      >
+        查看更多&gt;
       </div>
-      <div class="shade_table_blank" v-if="list.length"></div>
     </div>
+    <div class="shade_table_blank" v-if="list.length"></div>
+  </div>
 </template>
 
 <style lang="scss" scoped>
 /* table */
-.in-app{
-  .search-table-list{
-    .fixed-table{
-      width:100%;
+.in-app {
+  .search-table-list {
+    .fixed-table {
+      width: 100%;
       background: #fff;
-      top:48px;
-      left:0;
+      top: 48px;
+      left: 0;
       padding: 0 24px;
       box-sizing: border-box;
     }
   }
 }
 
-
 .search-table-list {
   /*全文搜索 表格*/
-  width:100%;
+  width: 100%;
   position: relative;
   //border-bottom: 1px solid #e0e0e0;
   table {
-
     width: 100%;
     border-collapse: collapse;
     table-layout: fixed;
@@ -226,10 +225,10 @@ function toDetail (item) {
     margin-top: -110px;
     height: 150px;
     background: linear-gradient(
-        to bottom,
-        rgba(255, 255, 255, 0),
-        rgba(255, 255, 255, 0.8),
-        rgba(255, 255, 255, 1)
+      to bottom,
+      rgba(255, 255, 255, 0),
+      rgba(255, 255, 255, 0.8),
+      rgba(255, 255, 255, 1)
     );
     .more {
       position: absolute;
@@ -246,14 +245,14 @@ function toDetail (item) {
       cursor: pointer;
     }
   }
-  .shade_table_blank{
-    height:50px;
+  .shade_table_blank {
+    height: 50px;
   }
-  .fixed-table{
+  .fixed-table {
     position: fixed;
     top: 100px;
-    width:1200px;
-    table{
+    width: 1200px;
+    table {
       margin-bottom: 0;
     }
   }

+ 60 - 44
apps/bigmember_pc/src/views/search/bidding/constant/search-filters.js

@@ -1,4 +1,8 @@
-import InfoTypeSelector from '@/components/selector/InfoTypeSelector.vue'
+import { findIndex } from 'lodash'
+// 信息类型:一二级都平铺展示组件
+// import InfoTypeSelector from '@/components/selector/InfoTypeSelector.vue'
+// 信息类型:一级平铺、二级下拉展示组件
+import InfoTypeSelector from '@/components/filter-items/InfoTypeSelector.vue'
 import SearchScopeSelector from '@/components/filter-items/SearchScopeSelector.vue'
 import SearchTimeScopeSelector from '@/components/selector/SearchTimeScopeSelector.vue'
 import BuyerTypeSelector from '@/components/filter-items/BuyerTypeSelector.vue'
@@ -12,41 +16,44 @@ import SelectorWithBasePower from '@/components/filter-items/SelectorWithBasePow
 import OnecascadeContent from '@/components/filter-items/OnecascadeContent.vue'
 import { calcSearchScope } from '@/assets/js/selector/scope.js'
 import $bus from '@/utils/bus'
-import { findIndex } from 'lodash'
 
 function noPower() {
   $bus.$emit('search:filter:no-power')
 }
 
-function beforeChangeHandle ($event, char, isLogin) {
-  if(isLogin) {
+function beforeChangeHandle($event, char, isLogin) {
+  if (isLogin) {
     return true
   }
   // 发布时间
-  if(char === 'publishTime') {
-    if($event.value === 'sinceLastYear') {
+  if (char === 'publishTime') {
+    if ($event.value === 'sinceLastYear') {
       return true
-    } else {
+    }
+    else {
       $bus.$emit('bidding:goLogin')
       return false
     }
-  } else if(char === 'selectType') {
-    if($event.value === 'file') {
+  }
+  else if (char === 'selectType') {
+    if ($event.value === 'file') {
       $bus.$emit('bidding:goLogin')
       return false
-    } else {
+    }
+    else {
       return true
     }
-  } else if (char === 'subtype') {
-    if($event.value) {
+  }
+  else if (char === 'subtype') {
+    if ($event.value) {
       $bus.$emit('bidding:goLogin')
-    } else {
+    }
+    else {
       return true
     }
   }
 }
 
-
 // 更多筛选中需要vip的筛选项
 const moreFiltersNeedVipKeyList = [
   'buyerclass',
@@ -55,7 +62,7 @@ const moreFiltersNeedVipKeyList = [
   'notkey',
   'buyer',
   'winner',
-  'agency',
+  'agency'
 ]
 
 const BIInfoTypeOptions = [
@@ -130,7 +137,7 @@ function createSearchBidBaseSchema(conf = {}) {
       freeConf: {
         exactCanHalf: true,
         showConfirmButton: true,
-        beforeChange ($event) {
+        beforeChange($event) {
           return beforeChangeHandle($event, 'publishTime', isLogin)
         },
         options: ['lately7', 'lately30', 'sinceLastYear'],
@@ -158,8 +165,8 @@ function createSearchBidBaseSchema(conf = {}) {
   }
   // 搜索范围
   const defaultScopeOptions = calcSearchScope({ vipUser, oldUser })
-  const freeOptions = defaultScopeOptions.filter((s) => !s.power)
-  const vipOptions = defaultScopeOptions.filter((s) => s.power)
+  const freeOptions = defaultScopeOptions.filter(s => !s.power)
+  const vipOptions = defaultScopeOptions.filter(s => s.power)
 
   const searchScopeExpandFree = {
     component: SelectorWithBasePower,
@@ -199,7 +206,7 @@ function createSearchBidBaseSchema(conf = {}) {
     {
       key: 'publishTime',
       label: '发布时间:',
-      labelHeight: isVip || !isInApp  ? '22px': '32px',
+      labelHeight: isVip || !isInApp ? '22px' : '32px',
       defaultVal: 'thisyear',
       _name: 'time',
       _type: 'component',
@@ -228,9 +235,11 @@ function createSearchBidBaseSchema(conf = {}) {
           showLabel: false,
           selectorType: 'line',
           showDataType: infoType,
-          beforeChange ($event) {
+          oneLevelSelected: true,
+          disabledDropdown: !isLogin,
+          beforeChange($event) {
             return beforeChangeHandle($event, 'subtype', isLogin)
-          },
+          }
         },
         hooks: {}
       }
@@ -256,7 +265,8 @@ function createSearchBidMoreSchema(filterItems, conf) {
         component: RegionSelector,
         props: {
           vip: isVip && isLogin,
-          showCount: false
+          showCount: false,
+          placeholder: '地区'
         },
         hooks: {
           limit: noPower
@@ -287,12 +297,15 @@ function createSearchBidMoreSchema(filterItems, conf) {
     },
     {
       key: 'price',
-      label: '金额区间',
+      label: '金额',
       defaultVal: '',
       _name: 'type',
       _type: 'component',
       expand: {
         component: AmountRangeSelector,
+        props: {
+          placeholder: '金额'
+        },
         hooks: {}
       }
     },
@@ -361,6 +374,7 @@ function createSearchBidMoreSchema(filterItems, conf) {
         component: KeywordTagsSelector,
         props: {
           maxListLength: 15,
+          maxLength: 30,
           placeholder: '采购单位',
           inputPlaceholder: '输入采购单位名称关键词,可找到目标单位的招标项目',
           maxTip: '采购单位个数已达上限'
@@ -378,6 +392,7 @@ function createSearchBidMoreSchema(filterItems, conf) {
         component: KeywordTagsSelector,
         props: {
           maxListLength: 15,
+          maxLength: 30,
           placeholder: '中标企业',
           inputPlaceholder: '输入中标企业名称关键词,可找到目标企业的中标项目',
           maxTip: '中标企业个数已达上限'
@@ -387,7 +402,7 @@ function createSearchBidMoreSchema(filterItems, conf) {
     },
     {
       key: 'agency',
-      label: '招标代理机构',
+      label: '招标代理',
       defaultVal: '',
       _name: 'agencyComponent',
       _type: 'component',
@@ -395,7 +410,8 @@ function createSearchBidMoreSchema(filterItems, conf) {
         component: KeywordTagsSelector,
         props: {
           maxListLength: 15,
-          placeholder: '招标代理机构',
+          maxLength: 30,
+          placeholder: '招标代理',
           inputPlaceholder: '输入代理机构名称关键词,可找到目标企业的代理项目',
           maxTip: '代理机构个数已达上限'
         },
@@ -405,29 +421,29 @@ function createSearchBidMoreSchema(filterItems, conf) {
   ]
 
   // 移动端融创,动态添加筛选条件(支持多个筛选条件插入)
-  if(filterItems && Array.isArray(filterItems)) {
+  if (filterItems && Array.isArray(filterItems)) {
     const resultFilter = []
-    filterItems.forEach(fTemp => {
+    filterItems.forEach((fTemp) => {
       const { key, defaultVal, label, options, type } = fTemp
-      let obj  = {}
-      if(type === 'multiple') {
-       const formatOptions = options.map(o => {
-         return {
-           ...o,
-           label: o.label,
-           value: o.key,
-         }
-       })
+      let obj = {}
+      if (type === 'multiple') {
+        const formatOptions = options.map((o) => {
+          return {
+            ...o,
+            label: o.label,
+            value: o.key
+          }
+        })
         obj = {
-          key: key,
-          label: label,
-          defaultVal: defaultVal,
+          key,
+          label,
+          defaultVal,
           _name: 'type',
           _type: 'component',
           expand: {
-          component: OnecascadeContent,
+            component: OnecascadeContent,
             props: {
-            options: formatOptions,
+              options: formatOptions,
               placeholder: label
             },
             hooks: {}
@@ -436,14 +452,14 @@ function createSearchBidMoreSchema(filterItems, conf) {
       }
       resultFilter.push(obj)
     })
-    const index = findIndex(SearchBidMoreSchema, function (o) {
+    const index = findIndex(SearchBidMoreSchema, (o) => {
       return o.label === '采购单位类型'
     })
     SearchBidMoreSchema.splice(index, 0, ...resultFilter)
   }
   // 医械通--不展示行业以及采购单位类型
-  if(isBidField) {
-   const newArr = SearchBidMoreSchema.filter(item => {
+  if (isBidField) {
+    const newArr = SearchBidMoreSchema.filter((item) => {
       return item.key !== 'industry' && item.key !== 'buyerclass'
     })
     SearchBidMoreSchema = newArr

+ 161 - 112
apps/bigmember_pc/src/views/search/bidding/index.vue

@@ -69,7 +69,8 @@ const {
   onFreeTaste,
   interceptKeywords,
   toggleBlurModeTip,
-  doToggleSearchBlurMode
+  doToggleSearchBlurMode,
+  showFilter
 } = SearchBidModel
 
 const {
@@ -78,9 +79,8 @@ const {
   type: vipDialogType
 } = vipDialogConf
 
-
 // 开通超级订阅
-function toBuySvip () {
+function toBuySvip() {
   window.open('/swordfish/page_big_pc/free/svip/buy?type=buy')
 }
 
@@ -98,21 +98,35 @@ const articleRef = ref({
 
 <template>
   <div class="search-bidding-page">
-    <div class="search-bidding-header-container b-rd-8px">
+    <div
+      class="search-bidding-header-container"
+      :class="{ 'b-rd-self': !showFilter }"
+    >
       <search-bid-header></search-bid-header>
     </div>
-    <div class="search-bidding-keywords-tip intercept" v-if="interceptKeywords.interceptOtherWords">
-      <img src="@/assets/images/icon/tip2.png" alt="">
-      “<span>{{interceptKeywords.interceptOtherWords}}</span>“及其后面的字词均被忽略,因为剑鱼标讯的查询限制在<span class="interceptLimit">{{interceptKeywords.interceptLimit}}</span>个汉字以内。
+    <div
+      class="search-bidding-keywords-tip intercept"
+      v-if="interceptKeywords.interceptOtherWords"
+    >
+      <img src="@/assets/images/icon/tip2.png" alt="" />
+      “<span>{{ interceptKeywords.interceptOtherWords }}</span
+      >“及其后面的字词均被忽略,因为剑鱼标讯的查询限制在<span
+        class="interceptLimit"
+        >{{ interceptKeywords.interceptLimit }}</span
+      >个汉字以内。
     </div>
-    <div class="search-bidding-filter-container b-rd-8px">
-      <search-filter-header></search-filter-header>
-      <search-bid-filter></search-bid-filter>
+    <div class="search-bidding-filter-container">
+      <el-collapse-transition>
+        <div v-show="showFilter">
+          <search-filter-header></search-filter-header>
+          <search-bid-filter></search-bid-filter>
+        </div>
+      </el-collapse-transition>
     </div>
-    <div >
+    <div>
       <recommend-card></recommend-card>
     </div>
-    <div class='search-bidding-list-container'>
+    <div class="search-bidding-list-container">
       <search-list
         class="b-rd-8px"
         v-bind="searchListProps"
@@ -121,9 +135,8 @@ const articleRef = ref({
         @doChangeSelect="doChangeSelect"
         :show-pagination="activeItemStyleType !== 'T'"
         :is-table="activeItemStyleType === 'T'"
-        :table-fixed-top='tableFixedTop'
+        :table-fixed-top="tableFixedTop"
       >
-
         <template #other-action-item v-if="inInjectBI">
           <div class="all-add bi-add-button" @click="onAddInfoOfBI()">添加</div>
         </template>
@@ -133,16 +146,19 @@ const articleRef = ref({
         <template #item-checkbox v-if="activeItemStyleType === 'T'">
           <span></span>
         </template>
-        <template v-slot:table='{ list }' v-if="activeItemStyleType === 'T'">
+        <template v-slot:table="{ list }" v-if="activeItemStyleType === 'T'">
           <search-list-table
             :list="tableList"
-            :list-state='listState'
+            :list-state="listState"
             :match-keys="inputKeywordsState.matchKeys"
-            @to-detail='toDetail'
-            :table-fixed-top='tableFixedTop'
+            @to-detail="toDetail"
+            :table-fixed-top="tableFixedTop"
           ></search-list-table>
         </template>
-        <template v-slot:item="{ item, index }" v-if="activeItemStyleType !== 'T'">
+        <template
+          v-slot:item="{ item, index }"
+          v-if="activeItemStyleType !== 'T'"
+        >
           <div>
             <article-item
               class="list-item"
@@ -158,18 +174,22 @@ const articleRef = ref({
               @onJoinBid="onJoinBid"
               :config="articleRef"
             >
-              <template #bi-slot=" { item }">
-
-              </template>
+              <template #bi-slot="{ item }"> </template>
               <template #right-handle-container>
                 <div
-                  v-if="(inBIPropertyIframe || inResourceBIIframe) && !inBITopNet"
+                  v-if="
+                    (inBIPropertyIframe || inResourceBIIframe) && !inBITopNet
+                  "
                   class="bi-employ-bid"
                   @click.prevent.stop="onSingleEmploy(item)"
                 >
                   <i
-                    class="iconfont "
-                    :class="item.isEmploy ? 'icon-a-Property1yishoulu':  'icon-a-Property1shoulu'"
+                    class="iconfont"
+                    :class="
+                      item.isEmploy
+                        ? 'icon-a-Property1yishoulu'
+                        : 'icon-a-Property1shoulu'
+                    "
                   ></i>
                   <span>{{ item.isEmploy ? '已收录' : '收录' }}</span>
                 </div>
@@ -185,19 +205,36 @@ const articleRef = ref({
           </div>
         </template>
         <template #empty>
-          <empty :mtb60="false"  images="jy-back.png">
+          <empty :mtb60="false" images="jy-back.png">
             <div class="hasNoData_tiptext">
-              <p>对不起,没有找到 <span class="highlight-text">{{ timeSelectorText }}</span> 相关匹配的信息,</p>
+              <p>
+                对不起,没有找到
+                <span class="highlight-text">{{ timeSelectorText }}</span>
+                相关匹配的信息,
+              </p>
               <p>修改时间范围或换个搜索词试试吧</p>
             </div>
           </empty>
         </template>
-        <template #list-after v-if="listState.finished && activeItemStyleType !== 'T' && isLogin">
-          <div class="p-16px text-right over-run-tips" v-if="isFree && listState.total >= 500">
+        <template
+          #list-after
+          v-if="listState.finished && activeItemStyleType !== 'T' && isLogin"
+        >
+          <div
+            class="p-16px text-right over-run-tips"
+            v-if="isFree && listState.total >= 500"
+          >
             为您展示前500条,
-            <span class="highlight-text" @click="onFreeTaste">点击免费查看更多信息</span>
+            <span class="highlight-text" @click="onFreeTaste"
+              >点击免费查看更多信息</span
+            >
+          </div>
+          <div
+            class="text-right over-run-tips"
+            v-if="isVip && listState.total >= 5000"
+          >
+            为您展示前5000条,可细化筛选条件查看更多信息
           </div>
-          <div class="text-right over-run-tips" v-if="isVip && listState.total >= 5000">为您展示前5000条,可细化筛选条件查看更多信息</div>
         </template>
         <template #pagination>
           <el-pagination
@@ -216,19 +253,28 @@ const articleRef = ref({
         </template>
       </search-list>
       <!-- 手动切换筛选模式提示 -->
-      <div class="tip-toggle-search-mode-container"  v-show="toggleBlurModeTip.show">
+      <div
+        class="tip-toggle-search-mode-container"
+        v-show="toggleBlurModeTip.show"
+      >
         <div>
           如需查看更多相关信息,建议您将搜索模式切换为
           <div class="tip-action highlight-text">
             “模糊搜索”
-            <el-tooltip popper-class="tooltip-help-class" effect="dark" placement="bottom">
-              <i class="iconfont icon-help" style="font-size:18px;"></i>
+            <el-tooltip
+              popper-class="tooltip-help-class"
+              effect="dark"
+              placement="bottom"
+            >
+              <i class="iconfont icon-help" style="font-size: 18px"></i>
               <template slot="content">
                 <div class="tooltip-slot-content w-360px">
-                  精准搜索: 搜索结果必须完全包含完整的关键词。如搜索"医疗设备" ,搜索结果一定完整包含“医疗设备”才能被搜索到,而“医疗的设备”或“设备医疗”的项目不会被搜索到。
-                  <br>
-                  <br>
-                  模糊搜索: 系统会先自动智能分词然后再进行搜索。如搜索"医疗设备" ,系统会自动分成“医疗”“设备”然后进行搜索,只要项目中出现“医疗”和“设备”都会被搜索到,前提是两个词必须一同出现在一则公告内,不分先后顺序。
+                  精准搜索: 搜索结果必须完全包含完整的关键词。如搜索"医疗设备"
+                  ,搜索结果一定完整包含“医疗设备”才能被搜索到,而“医疗的设备”或“设备医疗”的项目不会被搜索到。
+                  <br />
+                  <br />
+                  模糊搜索: 系统会先自动智能分词然后再进行搜索。如搜索"医疗设备"
+                  ,系统会自动分成“医疗”“设备”然后进行搜索,只要项目中出现“医疗”和“设备”都会被搜索到,前提是两个词必须一同出现在一则公告内,不分先后顺序。
                 </div>
               </template>
             </el-tooltip>
@@ -286,10 +332,12 @@ const articleRef = ref({
       center
       :visible.sync="showVipDialog"
     >
-      {{ vipDialogText}}
+      {{ vipDialogText }}
       <template #footer>
         <button class="action-button confirm" @click="toBuySvip">去开通</button>
-        <button class="action-button cancel" @click="closeVipDialog">取消</button>
+        <button class="action-button cancel" @click="closeVipDialog">
+          取消
+        </button>
       </template>
     </CustomDialog>
     <!-- 分发企业选择, 只有企业展示,默认vt为企业-->
@@ -300,11 +348,9 @@ const articleRef = ref({
       ref="usePowerRef"
     ></power-person>
     <!-- 参标更新状态弹窗 -->
-    <bidrenewal-dialog
-      ref="BidrenewalDialogRef">
-    </bidrenewal-dialog>
+    <bidrenewal-dialog ref="BidrenewalDialogRef"> </bidrenewal-dialog>
 
-<!--    物业专版收录-->
+    <!--    物业专版收录-->
     <el-dialog
       custom-class="property-employ-dialog"
       :visible.sync="showPropertyDialog"
@@ -319,7 +365,7 @@ const articleRef = ref({
   </div>
 </template>
 
-<style lang='scss'>
+<style lang="scss">
 .open-vip-dialog {
   width: 380px !important;
 
@@ -394,8 +440,8 @@ const articleRef = ref({
   .tags-item.tags-active {
     padding: 0 8px 0 24px !important;
     background: #2cb7ca
-    url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADPSURBVHgB7ZNREcIwDIYjYRImYRLmZHPAHAwHlUAdIAEJSKiESgjpEY7Qg7uFdXnKd5eXdMmfpX8BHMdxDEDEgSJQ9GANiU4UGZ9cwBISXPFNGWIAKyrxZLr+suq/xdkwV4oFlFBNR3ET4veS0zaJosGoqOtZ8EVUi4tGWbM+rklC/Ax7KH++dY18ZbmZuGi8iKbhxzdTJT5DSyo/LNXZSZxljV80A3T4aayR86vIJTzyjX8xZTATF0NIU24y5xFDSFNGU3ExxNzsmTmO4zAPYEiZdz83IV0AAAAASUVORK5CYII=)
-    no-repeat 6px center !important;
+      url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAABYlAAAWJQFJUiTwAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADPSURBVHgB7ZNREcIwDIYjYRImYRLmZHPAHAwHlUAdIAEJSKiESgjpEY7Qg7uFdXnKd5eXdMmfpX8BHMdxDEDEgSJQ9GANiU4UGZ9cwBISXPFNGWIAKyrxZLr+suq/xdkwV4oFlFBNR3ET4veS0zaJosGoqOtZ8EVUi4tGWbM+rklC/Ax7KH++dY18ZbmZuGi8iKbhxzdTJT5DSyo/LNXZSZxljV80A3T4aayR86vIJTzyjX8xZTATF0NIU24y5xFDSFNGU3ExxNzsmTmO4zAPYEiZdz83IV0AAAAASUVORK5CYII=)
+      no-repeat 6px center !important;
     color: #fff !important;
     background-size: 16px !important;
     border: 0 !important;
@@ -486,70 +532,69 @@ const articleRef = ref({
         font-size: 14px;
         color: #1d1d1d;
       }
-      }
-  }
-
-    .tags-list {
-      margin-top: 12px;
-      overflow-y: auto;
-      flex: 1;
     }
+  }
 
+  .tags-list {
+    margin-top: 12px;
+    overflow-y: auto;
+    flex: 1;
+  }
 
-    .add-tag-button {
-      margin-left: 16px;
-      color: #2cb7ca;
-      font-size: 14px;
-      line-height: 22px;
-      white-space: nowrap;
-      cursor: pointer;
-    }
+  .add-tag-button {
+    margin-left: 16px;
+    color: #2cb7ca;
+    font-size: 14px;
+    line-height: 22px;
+    white-space: nowrap;
+    cursor: pointer;
+  }
 
-    .tags-footer {
-      margin-top: 20px;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-    }
+  .tags-footer {
+    margin-top: 20px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
 
-    .tags-button {
-      padding: 3px 17px;
-      color: #1d1d1d;
-      font-size: 14px;
-      line-height: 22px;
-      border-radius: 4px;
-      border: 1px solid #e0e0e0;
-      text-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.08);
-      cursor: pointer;
-    }
+  .tags-button {
+    padding: 3px 17px;
+    color: #1d1d1d;
+    font-size: 14px;
+    line-height: 22px;
+    border-radius: 4px;
+    border: 1px solid #e0e0e0;
+    text-shadow: 0px 0px 28px 0px rgba(0, 0, 0, 0.08);
+    cursor: pointer;
+  }
 
-    .button-confirm {
-      margin-right: 16px;
-      color: #fff;
-      background: #2cb7ca;
-      border-color: #2cb7ca;
-    }
+  .button-confirm {
+    margin-right: 16px;
+    color: #fff;
+    background: #2cb7ca;
+    border-color: #2cb7ca;
+  }
 
-    .tag-placeholder {
-      position: absolute;
-      top: 12px;
-      left: 16px;
-      color: #bbb;
-      font-size: 14px;
-    }
+  .tag-placeholder {
+    position: absolute;
+    top: 12px;
+    left: 16px;
+    color: #bbb;
+    font-size: 14px;
+  }
 }
 </style>
 
 <style lang="scss" scoped>
 .in-app {
-  .search-bidding-page{
-    margin-top:0;
+  .search-bidding-page {
+    margin-top: 0;
     width: 100%;
-    padding:24px;
+    padding: 24px;
   }
 }
-.in-web{
-  .search-bidding-page{
+.in-web {
+  .search-bidding-page {
     margin-top: 24px;
   }
 }
@@ -559,11 +604,16 @@ const articleRef = ref({
 
   .search-bidding-header-container {
     background-color: #fff;
+    border-radius: 8px 8px 0 0;
+    &.b-rd-self {
+      border-radius: 8px;
+    }
   }
   .search-bidding-filter-container {
     width: 100%;
     background-color: #fff;
-    margin: 16px 0;
+    margin-bottom: 16px;
+    border-radius: 0 0 8px 8px;
   }
 
   .search-bidding-list-container {
@@ -589,16 +639,16 @@ const articleRef = ref({
       font-size: 20px !important;
       vertical-align: top;
     }
-    .icon-a-Property1shoulu{
+    .icon-a-Property1shoulu {
       color: #afafaf;
     }
-    .icon-a-Property1yishoulu{
-      color: #2ABED1;
+    .icon-a-Property1yishoulu {
+      color: #2abed1;
     }
   }
   .bi-add-button {
     &.all-add {
-      margin-right:8px;
+      margin-right: 8px;
     }
     display: inline-block;
     margin-left: 16px;
@@ -615,23 +665,22 @@ const articleRef = ref({
     box-sizing: content-box;
     min-width: 42px;
   }
-  ::v-deep{
-    .a-i-detail{
+  ::v-deep {
+    .a-i-detail {
       padding-left: 0;
     }
-    .keyword-tags-container{
+    .keyword-tags-container {
       margin-top: -6px;
       .el-tag,
       .add-keyword-actions,
-      .keyword-radio-group
-      {
+      .keyword-radio-group {
         margin-top: 6px;
       }
     }
     //.filter-layout{
     //  position: unset!important;
     //}
-    .hasNoData_tiptext{
+    .hasNoData_tiptext {
       font-size: 14px;
 
       text-align: center;
@@ -639,7 +688,7 @@ const articleRef = ref({
       line-height: 22px;
     }
     .el-date-editor.el-input,
-    .el-date-editor.el-input__inner{
+    .el-date-editor.el-input__inner {
       width: unset;
       background: transparent;
       padding: 0;
@@ -655,9 +704,9 @@ const articleRef = ref({
   }
 }
 .search-bidding-keywords-tip {
-  margin-top: 25px;
+  background: #fff;
+  padding: 0 0 10px 30px;
   font-size: 14px;
-  margin-bottom: -10px;
   img {
     vertical-align: middle;
     width: 15px;
@@ -667,7 +716,7 @@ const articleRef = ref({
   }
 }
 .tip-toggle-search-mode-container {
-  border-top: 1px solid #0000000D;
+  border-top: 1px solid #0000000d;
   display: flex;
   flex-direction: row;
   align-items: center;
@@ -677,7 +726,7 @@ const articleRef = ref({
   color: #5f5e64;
   font-size: 13px;
   line-height: 20px;
-  background: linear-gradient(90deg, #EDFDFF 0.51%, #FFFFFF 100%);
+  background: linear-gradient(90deg, #edfdff 0.51%, #ffffff 100%);
   .tip-action {
     display: inline-flex;
     align-items: center;

+ 34 - 16
apps/bigmember_pc/src/views/search/bidding/model/base.js

@@ -6,6 +6,7 @@ import { MessageBox } from 'element-ui'
 import  {
   FilterHistoryAjaxModelRestore,
   FilterHistoryAjaxModel2ViewModel,
+  FilterModel2ViewModel,
   getParam,
   openLinkInWorkspace,
   InContainer
@@ -88,7 +89,6 @@ export default function () {
   // 跨组件通信 将历史搜索列表数据注入 在SearchHeader子组件中引用
   provide('searchHistoryList', bidHistoryList)
 
-
   // 是否在工作台内
   // 本地调试,可改为工作台内isInApp = ref(true),  isInWeb = ref(false)   提交记得改回!
   const isInApp = ref(InContainer.inApp) // InContainer.inApp
@@ -122,7 +122,7 @@ export default function () {
    // 是否是领域化页面(医械通)
   const isBidField =  location.href.includes('/jylab/medical/index')
 
-  const  { goback, keywords: urlKeywords,  selectType: urlSelectType } = useRoute().query
+  const { goback, keywords: urlKeywords, selectType: urlSelectType } = useRoute().query
 
   // 缓存存储配置
   const storageConfig = {
@@ -270,8 +270,8 @@ export default function () {
         oldUser: isOld.value && isInApp.value,
         showVip: isLogin.value && isInApp.value,
         infoType: infoTypeDataType.value,
-        isBidField: isBidField,
-        inInjectBI: inInjectBI,
+        isBidField,
+        inInjectBI,
         isVip: isVip.value
       }
     })
@@ -396,7 +396,7 @@ export default function () {
       searchResultCount: searchResultCount.value,
       headerActions: limitFilterHeaderActions.value,
       list: activeList.value,
-      listState: listState
+      listState
     }
   })
 
@@ -478,8 +478,8 @@ export default function () {
       }
     }
   }
-  function detailListClick (key) {
-    if(isFree.value) {
+  function detailListClick(key) {
+    if (isFree.value) {
       openListVipDialog()
       return
     }
@@ -508,14 +508,15 @@ export default function () {
   }
   // 登录
   $bus.$on('bidding:goLogin', goLogin)
-  function goLogin () {
+  function goLogin() {
     that.$showLoginDialog()
   }
   // 跳转详情页
   function toDetail(item) {
     let aHref = ".html"
-    if (inputKeywordsState.value.input){
-      aHref+= '?kds=' + encodeURIComponent(inputKeywordsState.value.input)
+    if (inputKeywordsState.value.matchKeys && inputKeywordsState.value.matchKeys.length > 0){
+      const kds = inputKeywordsState.value.matchKeys.join(' ')
+      aHref+= '?kds=' + encodeURIComponent(kds)
     }
     if (getParam('resource') === 'BI') {
       if (getParam('property') === 'BIProperty') {
@@ -672,7 +673,7 @@ export default function () {
     return true
   }
   // 搜索前 处理一些事情
-  function beforeSearchSomthing (pageNum) {
+  function beforeSearchSomething (pageNum) {
     // 列表清空
     list.value = []
     listState.total = 0
@@ -702,10 +703,10 @@ export default function () {
    */
   function doQuery(params = {}, searchType, pageNum) {
     const bSearch = beforeSearchCheck(searchType)
-    if(!bSearch) {
+    if (!bSearch) {
       return
     }
-    beforeSearchSomthing (pageNum)
+    beforeSearchSomething (pageNum)
     // Ajax请求
     return doRunQuery(getParams(params)).then((res) => {
       // 搜索重新获取搜索历史
@@ -820,6 +821,21 @@ export default function () {
     return originParams
   }
 
+  // 格式化当前已选筛选条件
+  // P611需求,展示当前已选条件文案
+  const showCurrentFilterText = computed(() => {
+    if(!(isLogin.value && isInApp.value && !inBIPropertyIframe)) {
+      return {}
+    }
+    const originParams = packageFilter()
+    const text = FilterModel2ViewModel.formatAll(originParams)
+    // 融创
+    if (originParams.mobileTag) {
+      text.mobileTagText = originParams.mobileTag.includes('all') ? '' : originParams.mobileTag.join(',')
+    }
+    return text
+  })
+
 // P271需求,潜客圈进,展示超前项目or分析报告引流
   const recommendCardCircleModel = recommendCardModel({ that })
   const {
@@ -863,7 +879,7 @@ export default function () {
 
   /** 保存、重置筛选条件部分 start ****/
 
-  const disposeFilterActionModel = saveFilterActionsModel()
+  const disposeFilterActionModel = saveFilterActionsModel({ isBidField })
   const {
     historyFilterDialogVisible, //已存筛选条件弹窗
     getFilterHistoryList, // 已存筛选条件列表
@@ -906,7 +922,7 @@ export default function () {
           const params = Object.assign(item,{
             bidField: isBidField ? 'medical' : '',
             publishTime: 'thisyear',
-            selectType: ['title'],
+            selectType: ['title', 'content'],
             subtype: item.subtype,
             regionMap: {},
             industry: item.industry,
@@ -964,6 +980,7 @@ export default function () {
       input: resultFilter.input,
       // 关键词筛选模式
       searchMode: resultFilter.searchMode,
+      // 接口返回的关键词,如果模糊搜索,服务端会根据一定规则切割多个词
       matchKeys: resultFilter.matchKeys,
       // 附加关键词筛选模式
       wordsMode: resultFilter.wordsMode,
@@ -1587,6 +1604,7 @@ export default function () {
     getWhiteList,
     storageConfig,
     clearHistoryQuery,
-    searchHistoryList
+    searchHistoryList,
+    showCurrentFilterText
   }
 }

+ 86 - 54
apps/bigmember_pc/src/views/search/bidding/model/modules/filter.js

@@ -1,4 +1,4 @@
-import { ref, computed } from 'vue'
+import { ref, readonly } from 'vue'
 import  {
   FilterHistoryViewModel2AjaxModel,
   areaObjTwoToSingle,
@@ -7,13 +7,47 @@ import  {
 
 export function useSearchFilterModel(conf) {
   const { inBIPropertyIframe, isFree,isInApp, isBidField } = conf
+  const initBase = {
+    bidField: isBidField ? 'medical' : '',
+    // 发布时间
+    publishTime: (isFree.value || !isInApp.value) ? 'thisyear' : 'fiveyear',
+    // 搜索范围
+    selectType: ['title', 'content'],
+    // 信息类型
+    subtype: [],
+    // 地区
+    regionMap: {},
+    // 行业
+    industry: {},
+    // 附件
+    fileExists: '',
+    // 金额区间
+    price: '',
+    // 采购单位类型
+    buyerclass: {},
+    // 采购单位联系方式
+    buyertel: '',
+    // 中标企业联系方式
+    winnertel: '',
+    // 排除词
+    notkey: [],
+    // 采购单位
+    buyer: [],
+    // 中标企业
+    winner: [],
+    // 招标代理机构
+    agency: [],
+    // 其它动态获取的筛选条件
+    _expand: {}
+  }
+
   // 筛选组件状态
   const filterBase = ref({
     bidField: isBidField ? 'medical' : '',
     // 发布时间
     publishTime: (isFree.value || !isInApp.value) ? 'thisyear' : 'fiveyear',
     // 搜索范围
-    selectType: ['title'],
+    selectType: ['title', 'content'],
     // 信息类型
     subtype: [],
     // 地区
@@ -87,7 +121,7 @@ export function useSearchFilterModel(conf) {
    }
  }
   // 格式化招标采购基础筛选条件
-  function getFormatApiBaseParams (expendObj = {}) {
+  function getFormatApiBaseParams () {
     const { publishTime, regionMap, industry, notkey, buyerclass, subtype, _expand } = filterState.value
     const { area, city, district } = FilterHistoryViewModel2AjaxModel.formatAreaCity(regionMap)
     const rPublishTime = publishTime?.indexOf('_') > -1 ? FilterHistoryViewModel2AjaxModel.formatExactTime(publishTime, '-') :  FilterHistoryViewModel2AjaxModel.formatTime(publishTime, true, '-')
@@ -111,11 +145,11 @@ export function useSearchFilterModel(conf) {
       buyer: filterState.value.buyer.join(','),
       winner: filterState.value.winner.join(','),
       agency: filterState.value.agency.join(','),
-      industry: rIndustry,
+      industry: !isBidField ? rIndustry : '',
       province: area,
       city,
       district,
-      buyerClass: rBuyerClass,
+      buyerClass: !isBidField ? rBuyerClass : '',
       fileExists: filterState.value.fileExists,
       price: filterState.value.price,
       buyerTel: filterState.value.buyertel,
@@ -176,25 +210,48 @@ export function useSearchFilterModel(conf) {
     return params
   }
   // 动态更新筛选条件
-  function updateFilterBase (keyObj = {}) {
+  function updateFilterBase (keyObj = {}, type) {
     const {key, value } = keyObj
-    const _expand = filterState.value._expand || {}
+    const initParams = JSON.parse(JSON.stringify(initBase))
     if(keyObj && Object.keys(keyObj).length > 0) {
-      filterBase.value = Object.assign(filterBase.value, {
-        [key]: value
-      })
-      let _expandResult = {
-        _expand: {}
-      }
-      if(Object.keys(_expand).length  > 0 || filterState.value[key]) {
-        _expandResult._expand =  Object.assign(_expand, { [key]: value })
-      } else {
-        _expandResult._expand =  {
-          [key]: value
+      // 重置单个筛选条件
+      if(type === 'resetItem') {
+        // 动态组件重置
+        if(filterState.value._expand[key]) {
+          const expandSearchParams = localStorage.getItem('search_bidding_expandSearchParams')
+          let _expand = {}
+          if(expandSearchParams) {
+            _expand = JSON.parse(expandSearchParams)
+          }
+          filterBase.value[key] = _expand[key]
+          filterBase.value._expand[key] = _expand[key]
+          filterState.value[key] = _expand[key]
+          filterState.value._expand[key] = _expand[key]
+        } else {
+          // 普通组件重置
+          filterBase.value[key] = initParams[key]
+          filterState.value[key] = initParams[key]
         }
-      }
-      if(!inBIPropertyIframe) {
-        filterState.value = Object.assign(filterBase.value, filterState.value, _expandResult)
+
+      } else if(type === 'expand') {
+        // 动态拓展筛选条件
+        const _expand = filterState.value._expand || {}
+        let _expandResult = {
+          _expand: {}
+        }
+        if(Object.keys(_expand).length  > 0 && filterState.value[key]) {
+          _expandResult._expand =  Object.assign(_expand, { [key]: value })
+        } else {
+          _expandResult._expand =  {
+            [key]: value
+          }
+        }
+        if(!inBIPropertyIframe) {
+          filterState.value = Object.assign(filterBase.value, filterState.value, _expandResult)
+        }
+      } else {
+        filterBase.value[key] = value
+        filterState.value[key] = value
       }
     } else {
       // 动态获取存储的筛选条件
@@ -203,40 +260,15 @@ export function useSearchFilterModel(conf) {
       if(expandSearchParams) {
         _expand = JSON.parse(expandSearchParams)
       }
-      filterBase.value = Object.assign(filterBase.value, {
-        bidField: isBidField ? 'medical' : '',
-        // 发布时间
-        publishTime: (isFree.value || !isInApp.value) ? 'thisyear' : 'fiveyear',
-        // 搜索范围
-        selectType: ['title'],
-        // 信息类型
-        subtype: [],
-        // 地区
-        regionMap: null,
-        // 行业
-        industry: null,
-        // 附件
-        fileExists: '',
-        // 金额区间
-        price: '',
-        // 采购单位类型
-        buyerclass: null,
-        // 采购单位联系方式
-        buyertel: '',
-        // 中标企业联系方式
-        winnertel: '',
-        // 排除词
-        notkey: [],
-        // 采购单位
-        buyer: [],
-        // 中标企业
-        winner: [],
-        // 招标代理机构
-        agency: [],
-        ..._expand
-      })
+      // 重置所有筛选项
+      filterBase.value = {
+        ...initParams,
+        ..._expand,
+        expand: _expand
+      }
+      //
       if(!inBIPropertyIframe) {
-        filterState.value = filterBase.value
+        filterState.value =  filterBase.value
       }
     }
 

+ 51 - 50
apps/bigmember_pc/src/views/search/bidding/model/modules/recommend-card.js

@@ -1,19 +1,16 @@
-import { reactive, ref, toRefs, computed } from 'vue'
-import { leadGetDate, ajaxSetLeadGetDateRecord } from '@/api/modules/'
+import { computed, reactive, ref } from 'vue'
+import { tryCallHooks } from '@jianyu/easy-inject-qiankun'
+import { difference } from 'lodash'
+import { ajaxSetLeadGetDateRecord, leadGetDate } from '@/api/modules/'
 import {
-  dateFormatter,
-  openSelfLink,
-  replaceKeyword,
   formatPrice,
+  replaceKeyword
 } from '@/utils/'
-import { tryCallHooks } from '@jianyu/easy-inject-qiankun'
-import { difference } from 'lodash'
-
 
-export function recommendCardModel (modelConfig) {
+export function recommendCardModel(modelConfig) {
   const { that } = modelConfig
 
-  const advancedInfo = reactive( {
+  const advancedInfo = reactive({
     show: false,
     showContent: false,
     showDialog: false,
@@ -34,22 +31,20 @@ export function recommendCardModel (modelConfig) {
 
   const chartCustomData = ref({})
 
-  const chart = reactive( {
-      treeMapKey: 1,
-      treeMapData: [],
-      buyLineKey: 1,
-      buyLineData: {},
-      winnerLineKey: 1,
-      winnerLineData: {}
+  const chart = reactive({
+    treeMapKey: 1,
+    treeMapData: [],
+    buyLineKey: 1,
+    buyLineData: {},
+    winnerLineKey: 1,
+    winnerLineData: {}
   })
 
   const nowModuleName = computed(() => {
-    if (
-      advancedInfo.briefList.length ||
-      advancedInfo.projectList.length
-    ) {
+    if (advancedInfo.briefList.length || advancedInfo.projectList.length) {
       return '超前项目推荐'
-    } else {
+    }
+    else {
       return '市场分析报告'
     }
   })
@@ -62,7 +57,8 @@ export function recommendCardModel (modelConfig) {
   const getNotModuleDataStatus = computed(() => {
     if (nowModuleName.value === '超前项目推荐') {
       return !advancedInfo.briefList.length
-    } else {
+    }
+    else {
       return true
     }
   })
@@ -85,26 +81,23 @@ export function recommendCardModel (modelConfig) {
       dType: 0,
       keyWords: keywords
     }
-    leadGetDate(params).then(res => {
-      const { error_code: code = 0, data } =  res
+    leadGetDate(params).then((res) => {
+      const { error_code: code = 0, data } = res
       if (code === 0 && data && Object.keys(data).length > 0) {
-        advancedInfo.briefList = (data?.ahead?.subTypeCount || []).map(
-          (v) => {
-            v.value = v.doc_count
-            return v
-          }
-        )
+        advancedInfo.briefList = (data?.ahead?.subTypeCount || []).map((v) => {
+          v.value = v.doc_count
+          return v
+        })
 
         advancedInfo.projectList = data?.ahead?.projectTop2 || []
 
         chartCustomData.value = data.custom || {}
 
         if (
-          advancedInfo.briefList.length ||
-          advancedInfo.projectList.length ||
-          Object.keys(chartCustomData.value).length
+          advancedInfo.briefList.length
+          || advancedInfo.projectList.length
+          || Object.keys(chartCustomData.value).length
         ) {
-
           advancedInfo.show = true
           advancedInfo.showContent = false
 
@@ -131,7 +124,8 @@ export function recommendCardModel (modelConfig) {
         })
         chart.treeMapData = data
         chart.treeMapKey = new Date().getTime()
-      } else if (item === 'winner_time_distribution') {
+      }
+      else if (item === 'winner_time_distribution') {
         const data = {
           columns: ['采购规模分布', '采购总金额占比', '采购单位总数占比'],
           rows: []
@@ -148,12 +142,13 @@ export function recommendCardModel (modelConfig) {
             const row = {}
             data.columns.forEach((column) => {
               if (
-                field[column] === 'total_amount' ||
-                field[column] === 'total_number'
+                field[column] === 'total_amount'
+                || field[column] === 'total_number'
               ) {
                 row[column] = (item[field[column]] * 100).toFixed(2)
                 total += item[field[column]] - 0
-              } else {
+              }
+              else {
                 row[column] = item[field[column]]
               }
             })
@@ -165,7 +160,8 @@ export function recommendCardModel (modelConfig) {
           chart.buyLineData = data
           chart.buyLineKey = new Date().getTime()
         }
-      } else if (item === 'buyer_time_distribution') {
+      }
+      else if (item === 'buyer_time_distribution') {
         const data = {
           columns: ['中标规模分布', '中标总金额占比', '中标单位总数占比'],
           rows: []
@@ -182,12 +178,13 @@ export function recommendCardModel (modelConfig) {
             const row = {}
             data.columns.forEach((column) => {
               if (
-                field[column] === 'total_amount' ||
-                field[column] === 'total_number'
+                field[column] === 'total_amount'
+                || field[column] === 'total_number'
               ) {
                 row[column] = (item[field[column]] * 100).toFixed(2)
                 total += item[field[column]] - 0
-              } else {
+              }
+              else {
                 row[column] = item[field[column]]
               }
             })
@@ -218,11 +215,13 @@ export function recommendCardModel (modelConfig) {
 
   // 点击感兴趣
   function onClickInterested(type) {
-    const title = type === 'A' ? '体验超前项目推荐服务!' : '为您量身定制个性化报告!'
+    const title
+      = type === 'A' ? '体验超前项目推荐服务!' : '为您量身定制个性化报告!'
     showAdvancedDialog(title)
     try {
       ajaxSetLeadGetDateRecord({ type })
-    } catch (e) {
+    }
+    catch (e) {
       console.warn(e)
     }
   }
@@ -230,7 +229,8 @@ export function recommendCardModel (modelConfig) {
   async function goToReport() {
     try {
       await ajaxSetLeadGetDateRecord({ type: 'B' })
-    } catch (e) {
+    }
+    catch (e) {
       console.warn(e)
     }
     tryCallHooks({
@@ -254,19 +254,20 @@ export function recommendCardModel (modelConfig) {
   function goToContent(item) {
     try {
       ajaxSetLeadGetDateRecord({ type: 'A' })
-    } catch (e) {
+    }
+    catch (e) {
       console.warn(e)
     }
-    let goURL = '/article/content/' + item._id + '.html'
+    let goURL = `/article/content/${item._id}.html`
     if (Array.isArray(item.keyWord)) {
-      goURL += '?kds=' + encodeURIComponent(item.keyWord.join('+'))
+      goURL += `?kds=${encodeURIComponent(item.keyWord.join('+'))}`
     }
     window.open(goURL)
   }
   // 匹配高亮文本信息
   function getProjectTitle({ title, keyWord }) {
     return replaceKeyword(title, keyWord, [
-      '<span class="highlight-text">',
+      '<span class="highlight-text-orange-bd">',
       '</span>'
     ])
   }

+ 9 - 2
apps/bigmember_pc/src/views/search/bidding/model/modules/save-filter-actions.js

@@ -9,8 +9,12 @@ const saveConfig = {
   savedFilterListMaxCount: 10 //筛选条件保存条数最大值
 }
 
-export function saveFilterActionsModel () {
+// P611医械通:要处理参数 bidField: isBidField ? 'medical' : '',
+
+export function saveFilterActionsModel (conf) {
    const { savedFilterListMaxCount: maxCount } = saveConfig
+  // 是否是医械通
+  const { isBidField }  = conf
    // 已存筛选列表
    let filterHistoryList = ref([])
    // 保存筛选条件框展示与否
@@ -85,7 +89,10 @@ export function saveFilterActionsModel () {
   // 获取已存筛选条件
   async function  getFilterHistoryList(type, callback) {
     try {
-        const { data, error_code: code, error_msg: msg } = await getBiddingFilterList()
+        const par = {
+          bidField: isBidField ? 'medical' : ''
+        }
+        const { data, error_code: code, error_msg: msg } = await getBiddingFilterList(par)
       if (code === 0) {
         const resData = data || []
         const arr = resData.map((item, index) => {

+ 10 - 8
apps/bigmember_pc/src/views/search/bidding/model/modules/tabs.js

@@ -15,7 +15,8 @@ export function useSearchTabsModel(conf) {
     },
     {
       label: '超前项目',
-      badge: '推荐',
+      badge: '',
+      afterIcon: 'fire-icon',
       key: 2
     }
   ]
@@ -49,18 +50,20 @@ export function useSearchTabsModel(conf) {
       label: '拟在建项目查询',
       key: 6,
       link: '/swordfish/page_big_pc/search/nzj'
-    },
+    }
   ]
   let resTab = []
-  if(showTabs2){
+  if (showTabs2) {
     resTab = Tabs2
-  } else {
+  }
+  else {
     // 个人分析报告不展示超前项目
-    if(inInjectBI){
-      resTab = Tabs.filter(item => {
+    if (inInjectBI) {
+      resTab = Tabs.filter((item) => {
         return item.label !== '超前项目'
       })
-    } else {
+    }
+    else {
       resTab = Tabs
     }
   }
@@ -75,7 +78,6 @@ export function useSearchTabsModel(conf) {
     activeTab.value = tab.key
   }
 
-
   return {
     searchTabs,
     activeTab,

+ 23 - 8
apps/bigmember_pc/src/views/search/components/search-header-card.vue

@@ -16,7 +16,7 @@ const props = defineProps({
     default: ''
   },
   // 是否展示右侧微信二维码
-  showWxQr:{
+  showWxQr: {
     type: Boolean,
     default: true
   },
@@ -38,16 +38,22 @@ const props = defineProps({
   // 是否展示搜索历史
   historyEnabled: {
     type: Boolean,
-    default: false  
+    default: false
   },
   // 是否激活联想列表
-  perSearchEnabled:{
+  perSearchEnabled: {
     type: Boolean,
     default: false
   }
 })
 
-const emit = defineEmits(['goWorkSpace', 'clearSearch', 'clearBrowse', 'selectBrowse', 'selectEnt'])
+const emit = defineEmits([
+  'goWorkSpace',
+  'clearSearch',
+  'clearBrowse',
+  'selectBrowse',
+  'selectEnt'
+])
 
 function goWorkSpaceCustom() {
   emit('goWorkSpace')
@@ -83,10 +89,10 @@ function SelectEnt(data) {
         :key="index"
         :class="{ 'is-active': tab.active, 'use-badge': tab.badge }"
         @click="$emit('change-tab', tab)"
-      >
-        {{ tab.label }}
-      </span>
-      <div class="search-tab-right" v-if='showWorkspaceButton'>
+        >{{ tab.label }}<i v-if="tab.afterIcon" :class="tab.afterIcon"></i
+      ></span>
+      <slot name="tab-other"></slot>
+      <div class="search-tab-right" v-if="showWorkspaceButton">
         <WorkspaceButtonGroup
           :goWorkSpaceCustom="goWorkSpaceCustom"
         ></WorkspaceButtonGroup>
@@ -144,5 +150,14 @@ function SelectEnt(data) {
     color: #1d1d1d;
     line-height: 22px;
   }
+  .fire-icon {
+    display: inline-block;
+    width: 12px;
+    height: 12px;
+    background: url(@/assets/images/icon/fire-icon.png) no-repeat center;
+    background-size: cover;
+    vertical-align: baseline;
+    margin-left: 4px;
+  }
 }
 </style>

+ 9 - 9
apps/bigmember_pc/src/views/search/nzj/components/nzj-article-item.vue

@@ -46,7 +46,7 @@ const props = defineProps({
 })
 const calcTitle = computed(() => {
   const hightLightedTitle = replaceKeyword(props.title, props.matchKeys, [
-    '<span class="highlight-text">',
+    '<span class="highlight-text-orange-bd">',
     '</span>'
   ])
   if (props.index) {
@@ -107,8 +107,8 @@ function onClick() {
 </template>
 
 <style lang="scss" scoped>
-.nzj-list-item{
-  &:hover{
+.nzj-list-item {
+  &:hover {
     background-color: #f5f6f7;
   }
   .visited {
@@ -117,7 +117,7 @@ function onClick() {
       color: #999 !important;
     }
     .hover:hover {
-      color: #2CB7CA !important;
+      color: #2cb7ca !important;
     }
     .visited-ft {
       color: #9b9ca3 !important;
@@ -186,12 +186,12 @@ function onClick() {
       &.grey {
         color: #686868;
         border-color: #ececec;
-        background-color: #F5F5FB;
+        background-color: #f5f5fb;
       }
       &.blue {
         color: #fff;
-        background-color: #2CB7CA;
-        border-color: #2CB7CA;
+        background-color: #2cb7ca;
+        border-color: #2cb7ca;
       }
       &.orange {
         color: #fff;
@@ -205,8 +205,8 @@ function onClick() {
       }
       &.deeppink {
         color: #fff;
-        background-color: #FF878D;
-        border-color: #FF878D;
+        background-color: #ff878d;
+        border-color: #ff878d;
       }
     }
 

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

@@ -101,14 +101,14 @@ export default function () {
       return {
         id: item.id,
         title: replaceKeyword(item.title, inputKeywordsState.value.input, [
-          '<span class="highlight-text">',
+          '<span class="highlight-text-orange-bd">',
           '</span>'
         ]),
         detail: showDetail
           ? replaceKeyword(
               item.detail.replace(/<[^>]*>/g, ''),
               inputKeywordsState.value.input,
-              ['<span class="highlight-text">', '</span>']
+              ['<span class="highlight-text-orange-bd">', '</span>']
             )
           : '',
         time: dateFromNow(item.publish_time * 1000),

+ 11 - 0
apps/bigmember_pc/src/views/workspace/components/AnalysisReport.vue

@@ -44,3 +44,14 @@ export default {
   }
 }
 </script>
+
+<style lang="scss" scoped>
+::v-deep {
+  .card-content {
+    padding: 4px 12px 12px;
+  }
+  .list-item {
+    cursor: pointer;
+  }
+}
+</style>

+ 23 - 15
apps/bigmember_pc/src/views/workspace/components/MessageTips.vue

@@ -21,13 +21,16 @@
           v-for="(itemList, index) in swiperList"
           :key="'message_' + index"
         >
-          <div class="message-item" v-for="temp in itemList" :key="temp.id">
+          <div
+            class="message-item"
+            @click="titleGoto(temp)"
+            v-for="temp in itemList"
+            :key="temp.id"
+          >
             <div class="l-msg">
               <i class="red-dot" :class="{ invisible: temp.isRead !== 0 }"></i>
               <!-- <h3 class="msg-type">{{item.msg_type}}</h3> -->
-              <span class="text ellipsis" @click="titleGoto(temp)">{{
-                temp.title
-              }}</span>
+              <span class="text ellipsis">{{ temp.title }}</span>
             </div>
             <p class="time">{{ temp.createTime }}</p>
           </div>
@@ -109,10 +112,10 @@ export default {
     }
   }
   .el-carousel__container {
-    height: 141px;
+    height: 150px;
   }
-  .card-content{
-    padding: 2px 20px 16px;
+  .card-content {
+    padding: 0 12px 16px;
   }
 }
 
@@ -141,8 +144,17 @@ export default {
   flex-direction: initial;
   align-items: center;
   justify-content: space-between;
-  &:not(:last-of-type) {
-    margin-bottom: 8px;
+  padding: 4px 8px;
+  border-radius: 4px;
+  //&:not(:last-of-type) {
+  //  margin-bottom: 8px;
+  //}
+  &:hover {
+    background: #eaf8fa;
+    cursor: pointer;
+    .l-msg .text {
+      color: #2abed1;
+    }
   }
 
   .l-msg {
@@ -151,10 +163,10 @@ export default {
     max-width: 65%;
     .msg-type {
       margin-left: 8px;
-      font-size: 16px;
+      font-size: 14px;
       font-weight: bold;
       color: #2cb7ca;
-      line-height: 24px;
+      line-height: 22px;
       white-space: nowrap;
     }
     .text {
@@ -163,10 +175,6 @@ export default {
       color: #1d1d1d;
       line-height: 22px;
       flex: 1;
-      &:hover {
-        color: #2cb7ca;
-        cursor: pointer;
-      }
     }
   }
   .time {

+ 11 - 0
apps/bigmember_pc/src/views/workspace/components/NewsList.vue

@@ -48,3 +48,14 @@ export default {
   }
 }
 </script>
+
+<style lang="scss" scoped>
+::v-deep {
+  .card-content {
+    padding: 4px 12px 12px;
+  }
+  .list-item {
+    cursor: pointer;
+  }
+}
+</style>

+ 3 - 5
apps/bigmember_pc/src/views/workspace/components/SubscribeList.vue

@@ -185,12 +185,10 @@ export default {
 }
 ::v-deep {
   .card-content {
-    padding-left: 0;
-    padding-right: 0;
+    padding: 4px 12px 12px;
   }
-  .article-item.list-item {
-    padding-left: 20px;
-    padding-right: 20px;
+  .list-item {
+    cursor: pointer;
   }
 }
 </style>

+ 7 - 15
apps/bigmember_pc/src/views/workspace/ui/ListCard.vue

@@ -112,12 +112,6 @@ export default {
 }
 .list-card {
   max-width: 490px;
-  ::v-deep {
-    .card-content {
-      padding-top: 8px;
-      padding-bottom: 8px;
-    }
-  }
 }
 
 .empty-tip {
@@ -143,24 +137,22 @@ export default {
 }
 
 .list-item {
-  // padding: 12px 0;
-  padding: 0;
-  margin-bottom: 8px;
+  padding: 4px 8px;
   display: flex;
   justify-content: space-between;
   align-items: center;
-  // &:not(.last) {
-  //   box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset;
-  // }
+
+  &:hover {
+    background: #eaf8fa;
+    border-radius: 4px;
+    color: #2cb7ca !important;
+  }
   .list-item-l {
     margin-right: 12px;
     font-size: 14px;
     color: #1d1d1d;
     line-height: 22px;
     cursor: pointer;
-    &:hover {
-      color: #2cb7ca !important;
-    }
   }
   .list-item-r {
     display: flex;

+ 8 - 6
apps/mobile/src/api/modules/public.js

@@ -67,8 +67,6 @@ export function ajaxSetNewUserADRead(data) {
 
 /**
  * 获取最新标讯,用于首页展示
- * @param data
- * @returns {*}
  */
 export function ajaxGetIndexList(data) {
   return request({
@@ -80,8 +78,6 @@ export function ajaxGetIndexList(data) {
 
 /**
  * 获取参标状态
- * @param data
- * @returns {*}
  */
 export function ajaxCanBiaoStatus(data) {
   return request({
@@ -94,13 +90,11 @@ export function ajaxCanBiaoStatus(data) {
 
 /**
  * 参标--终止参标
- * @param data
  * action:
  *  in:参标-当前用户参标
  *  out:终止参标-1、员工终止当前自己对此项目参标的状态;2:部门管理员终止当前部门下对此项目参标的状态;3:企业管理员终止当前企业下对此项目的参标状态
  *  transfer:划转-1、部门管理员当前部门下参标此项目的对象;2、企业管理员企业下~~~~
  *  参标|终止参标:bidIds和projectIds 必传一个
- * @returns {*}
  */
 export function ajaxCanBiaoAction(action, data) {
   return request({
@@ -331,3 +325,11 @@ export function getZhiMaFilterData() {
     method: 'get'
   })
 }
+
+// 是否是白名单用户
+export function getIsWhiteList() {
+  return request({
+    url: '/publicapply/userbase/whitelist',
+    method: 'get'
+  })
+}

BIN
apps/mobile/src/assets/image/icon/hot.png


BIN
apps/mobile/src/assets/image/public/logo-text-transparent-bg@2x.png


+ 17 - 11
apps/mobile/src/assets/style/_variables.scss

@@ -17,7 +17,7 @@ $gray_8: #33323a; // VIP背景灰色
 $gray_89: #1b1a2a; // VIP背景灰色
 $gray_9: #171826;
 
-$main: #2ABED1;
+$main: #2abed1;
 $green: #00d086;
 $blue: #3399ff;
 $purple: #8e6df2;
@@ -34,6 +34,7 @@ $main_deep: #1db5e5;
 $purple_deep: #6d00db;
 $red_deep: #ef3024;
 $gold_deep: #d69e55; // VIP 金色deep
+$orange_red: #fa6f33;
 
 $color_main: $main;
 $color_red: $red;
@@ -41,17 +42,17 @@ $gray_vip: $gray_9;
 
 // Background
 // 透明背景色使用时,需要配合白色背景使用
-$color_main_background: rgb($color_main,.1);
-$color_red_background: rgba($color_red,.1);
-$color_gold_deep_background: rgba($gold_deep,.1);
+$color_main_background: rgb($color_main, 0.1);
+$color_red_background: rgba($color_red, 0.1);
+$color_gold_deep_background: rgba($gold_deep, 0.1);
 
 // Border
-$border_color_1: rgba($white,.5);
-$border_color_2: rgba($white,.9);
-$border_color_3: rgba($black,.04);
-$border_color_4: rgba($black,.1);
-$border_color_5: rgba($black,.15);
-$border_color_6: rgba($black,.3);
+$border_color_1: rgba($white, 0.5);
+$border_color_2: rgba($white, 0.9);
+$border_color_3: rgba($black, 0.04);
+$border_color_4: rgba($black, 0.1);
+$border_color_5: rgba($black, 0.15);
+$border_color_6: rgba($black, 0.3);
 
 $gradient_main: linear-gradient(to bottom, $main, $main_deep);
 $gradient_green: linear-gradient(to bottom, #0bd991, #00b031);
@@ -64,7 +65,12 @@ $gradient_gold: linear-gradient(to right, $gold_light, $gold);
 // VIP 深色渐变
 $gradient_gray: linear-gradient(135deg, #3e3e52 0%, #2f2f3d 100%, #2f2f3d 100%);
 
-$gradient_search_header: linear-gradient(280.62deg, #D7F6FB 1.93%, #E7FCFF 49.44%, #E7F2FF 98.41%);;
+$gradient_search_header: linear-gradient(
+  280.62deg,
+  #d7f6fb 1.93%,
+  #e7fcff 49.44%,
+  #e7f2ff 98.41%
+);
 
 // Radius
 $radius_base: 2px;

+ 26 - 15
apps/mobile/src/assets/style/common.scss

@@ -13,7 +13,8 @@
   user-select: none;
 }
 
-input, textarea {
+input,
+textarea {
   caret-color: $color_main;
 }
 
@@ -68,7 +69,7 @@ input, textarea {
 .cell-clickable {
   transition: background-color 0.1s ease;
   &:active {
-    background-color: $gray_2!important;
+    background-color: $gray_2 !important;
   }
 }
 
@@ -176,9 +177,9 @@ input, textarea {
   align-items: center;
   justify-content: center;
   padding: 5px 10px;
-  color: #5F5E64;
+  color: #5f5e64;
   font-size: 14px;
-  background: #F5F6F7;
+  background: #f5f6f7;
   height: 36px;
   min-width: 78px;
   border-radius: 4px;
@@ -257,23 +258,23 @@ button[disabled] {
 }
 
 .tag-warning {
-  color: #FF9F40;
-  border-color: #FF9F40;
+  color: #ff9f40;
+  border-color: #ff9f40;
 }
 
 .tag-danger {
-  color: #FB483D;
-  border-color: #FB483D;
+  color: #fb483d;
+  border-color: #fb483d;
 }
 
 .tag-success {
-  color: #2ABED1;
-  border-color: #2ABED1;
+  color: #2abed1;
+  border-color: #2abed1;
 }
 
 /* page change */
 // FROM: https://juejin.im/post/5ba358a56fb9a05d2068401d
-$--transition-time: .3s;
+$--transition-time: 0.3s;
 
 // ============
 // fold-left -> forward
@@ -319,7 +320,7 @@ $--transition-time: .3s;
   animation-name: fold-right-out;
   animation-duration: $--transition-time;
 }
-@keyframes fold-right-in{
+@keyframes fold-right-in {
   0% {
     width: 100%;
     transform: translate3d(-100%, 0, 0);
@@ -333,7 +334,7 @@ $--transition-time: .3s;
     transform: translate3d(0, 0, 0);
   }
 }
-@keyframes fold-right-out  {
+@keyframes fold-right-out {
   0% {
     width: 100%;
     transform: translate3d(0, 0, 0);
@@ -369,14 +370,14 @@ $--transition-time: .3s;
   bottom: 0;
   left: 0;
   right: 0;
-  background-color: #E6E6E6;
+  background-color: #e6e6e6;
   transform-origin: center right;
   transform: scaleX(0);
 }
 
 .hover-css--slide.hover {
   cursor: pointer;
-  color: #9B9CA3;
+  color: #9b9ca3;
 }
 
 .hover-css--slide.hover::before {
@@ -402,3 +403,13 @@ $--transition-time: .3s;
   transform: scale(0.5);
   border-bottom-width: 1px;
 }
+
+// 新文字颜色高亮
+.highlight-text-orange {
+  color: $orange_red;
+}
+
+.highlight-text-orange-bd {
+  color: $orange_red;
+  font-weight: bold;
+}

+ 7 - 0
apps/mobile/src/assets/style/pic-icon.scss

@@ -220,6 +220,13 @@
   background-size: contain;
 }
 
+.icon-vip-badge {
+  width: 14px;
+  height: 14px;
+  background-image: url(@/assets/image/icon/vip/v_icon.png);
+  flex-shrink: 0;
+}
+
 .icon-renmai {
   background-image: url(@/assets/image/icon/icon-renmai@2x.png);
   background-size: contain;

+ 2 - 2
apps/mobile/src/components/ad/SwipeFloor.vue

@@ -199,13 +199,13 @@ $swiper-floor-item-font-size: 11px;
 .my-swipe-floor {
   width: 100%;
   margin: 0 auto;
-  padding: 8px 0;
+  padding: 4px 0;
   box-sizing: border-box;
   position: relative;
   &-group {
     width: 100%;
     height: $swiper-floor-content-height;
-    padding-bottom: 16px;
+    padding-bottom: 8px;
     box-sizing: content-box;
     .swiper-pagination {
       width: $swiper-floor-pagination-width;

+ 80 - 0
apps/mobile/src/components/common/ScrollNav.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="scroll-nav">
+    <div class="scroll-nav-left">
+      <div
+        class="scroll-nav-left-item"
+        :class="{ active: index === active }"
+        v-for="(item, index) in menuLeft"
+        :key="index"
+        @click="onClick(item, index)"
+      >
+        <span>{{ item.label }}</span>
+        <i v-if="item.vip" class="j-icon j-base-icon icon-vip-badge"></i>
+      </div>
+    </div>
+    <div class="scroll-nav-right">
+      <slot></slot>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'scroll-nav-component',
+  components: {},
+  props: {
+    menuLeft: {
+      type: Array,
+      default: () => {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      active: 0
+    }
+  },
+  methods: {
+    onClick(item, index) {
+      this.active = index
+      this.$emit('tab', { item, index })
+    },
+    setActive(index) {
+      this.active = index
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-nav {
+  display: flex;
+  height: 100%;
+  background: #f5f6f7;
+  overflow: hidden;
+  &-left {
+    display: flex;
+    flex-direction: column;
+    flex-shrink: 0;
+    overflow-y: auto;
+    &-item {
+      display: flex;
+      justify-content: space-between;
+      width: 86px;
+      padding: 11px 8px;
+      font-size: 12px;
+      line-height: 18px;
+      &.active {
+        background: #fff;
+        color: $color_main;
+      }
+    }
+  }
+  &-right {
+    padding-bottom: 48px;
+    overflow-y: auto;
+    background: #fff;
+  }
+}
+</style>

+ 1 - 1
apps/mobile/src/components/custom-report/index.vue

@@ -241,7 +241,7 @@ export default {
     align-items: center;
     padding: 0 16px;
     button {
-      width: 165px;
+      width: 156px;
       height: 40px;
       border-radius: 4px;
       font-family: 'PingFang SC';

+ 4 - 1
apps/mobile/src/components/home/HotKeyList.vue

@@ -122,7 +122,8 @@ export default {
   display: inline-block;
   width: 42px;
   height: 16px;
-  background: transparent url(@/assets/image/home-temp/hot-key-title@2x.png) no-repeat center;
+  background: transparent url(@/assets/image/home-temp/hot-key-title@2x.png)
+    no-repeat center;
   background-size: contain;
 }
 .hot-key-list {
@@ -133,6 +134,8 @@ export default {
   overflow: hidden;
 }
 .hot-key-item {
+  font-size: 14px;
+  line-height: 16px;
   &:not(:last-of-type) {
     margin-right: 8px;
   }

+ 98 - 29
apps/mobile/src/components/home/list.vue

@@ -1,10 +1,9 @@
 <template>
   <div class="home-list">
-    <div class="divider-container">
+    <!-- <div class="divider-container">
       <van-divider>最新标讯</van-divider>
-    </div>
-    <van-loading v-if="loading" style="text-align: center" />
-    <div
+    </div> -->
+    <!-- <div
       class="to-setting-container fixed-bottom"
       v-if="showToSettingTip"
       ref="settingTip"
@@ -17,16 +16,21 @@
           <span>去设置</span>
           <van-icon name="arrow" />
         </button>
-        <!-- <van-button
-          size="mini"
-          class="setting-button"
-          type="confirm"
+      </div>
+    </div> -->
+    <div class="flex flex-items-center van-hairline--bottom home-list-header">
+      <h3 class="header-title">商机推荐</h3>
+      <div class="flex flex-items-center header-value" v-if="!isSubCount">
+        <span class="header-desc">完善信息,推荐更准</span>
+        <span
+          class="flex flex-items-center header-set"
           @click="gotoKeySettingPage"
-          >去设置</van-button
-        > -->
+          >去设置 <van-icon name="arrow" color="#2ABED1"></van-icon
+        ></span>
       </div>
     </div>
     <div class="list">
+      <van-loading class="list-loading" v-if="loading" />
       <project-cell
         class="right-bottom"
         v-for="(item, index) in list"
@@ -67,7 +71,7 @@
             <AppIcon
               style="margin-right: 4px"
               svg
-              size="20"
+              size="18"
               :name="item.isCollected ? 'shoucang' : 'shoucang_weishoucang'"
             />
             <span class="label-icon">收藏</span>
@@ -138,15 +142,15 @@
           </template>
         </template>
         <!-- 空状态 -->
-        <template v-else-if="false">
+        <template v-else>
           <AppEmpty v-if="!getStatus.hasList"></AppEmpty>
           <p>为了使您接收更多信息,可对关键词进行新增或修改。</p>
-          <van-button
+          <!-- <van-button
             size="mini"
             type="confirm"
             @click="onClickTip(isFree ? 'goSubSetting' : 'goSubKey')"
             >去设置</van-button
-          >
+          > -->
         </template>
       </div>
     </div>
@@ -170,7 +174,7 @@ import {
 } from '@/utils'
 import { LINKS } from '@/data'
 import qs from 'qs'
-import { mapState, mapGetters } from 'vuex'
+import { mapState, mapGetters, mapActions } from 'vuex'
 import { ipRegExp } from '@/utils/constant'
 export default {
   name: 'home-list',
@@ -232,7 +236,7 @@ export default {
     showToSettingTip() {
       return this.showTip === 2 && this.showSetTip
     },
-    ...mapGetters('user', ['isLogin', 'isFree'])
+    ...mapGetters('user', ['isLogin', 'isFree', 'vSwitch', 'isSubCount'])
   },
   watch: {
     showToSettingTip(n) {
@@ -260,8 +264,11 @@ export default {
   },
   mounted() {
     this.calcTipBottom()
+    // 获取用户当前vSwitch状态
+    this.userVipSwitchState()
   },
   methods: {
+    ...mapActions('user', ['userVipSwitchState']),
     calcTipBottom() {
       const footer = document.querySelector('.footer-box')
       const settingTip = this.$refs.settingTip
@@ -470,16 +477,19 @@ export default {
       }
       openAppOrWxPage({
         wx: LINKS.标讯详情页前缀.wx + item.id + '.html?' + qs.stringify(query),
-        app: LINKS.标讯详情页前缀.app + item.id + '.html?' + qs.stringify(query),
+        app:
+          LINKS.标讯详情页前缀.app + item.id + '.html?' + qs.stringify(query),
         h5: LINKS.标讯详情页前缀.h5 + item.id + '.html?' + qs.stringify(query)
       })
     },
     gotoKeySettingPage() {
-      if (this.isFree) {
-        this.onClickTip('goSubKey')
-      } else {
-        this.onClickTip('goSubSetting')
-      }
+      // P611需求:去设置进入“我的订阅-订阅管理页”,如有多套订阅,则进入当前订阅列表所选产品页
+      // if (this.isFree) {
+      //   this.onClickTip('goSubKey')
+      // } else {
+      //   this.onClickTip('goSubSetting')
+      // }
+      this.onClickTip('goPublicSubSetting')
     },
     onClickTip(type) {
       if (!this.isLogin) {
@@ -506,6 +516,22 @@ export default {
           callChangeTab('subscribe', this.$router)
           break
         }
+        case 'goPublicSubSetting': {
+          if (this.vSwitch === 's') {
+            openLinkOfOther(
+              '/page_entniche_new/page/subsetting/sub_entrance.html'
+            )
+          } else if (this.vSwitch === 'v' || this.vSwitch === 'm') {
+            openAppOrWxPage(LINKS.订阅管理页面, {
+              query: {
+                vSwitch: this.vSwitch
+              }
+            })
+          } else {
+            openAppOrWxPage(LINKS.订阅管理页面)
+          }
+          break
+        }
       }
     },
     /**
@@ -563,8 +589,8 @@ export default {
                 v?.bidamount
                   ? formatMoney(v?.bidamount)
                   : v?.budget
-                  ? formatMoney(v?.budget)
-                  : ''
+                    ? formatMoney(v?.budget)
+                    : ''
               ].filter((v) => v),
               time: v?.publishTime ? v.publishTime * 1000 : '',
               data: v
@@ -591,6 +617,34 @@ export default {
 
 <style lang="scss" scoped>
 .home-list {
+  .home-list-header {
+    margin: 8px 8px 0;
+    padding: 6px 12px;
+    background: linear-gradient(#d7fbff, #ffffff);
+    border-radius: 12px 12px 0 0;
+    .header-title {
+      margin-right: 8px;
+      font-size: 14px;
+      line-height: 20px;
+      font-weight: 700;
+    }
+    .header-value {
+      padding: 0 8px;
+    }
+    .header-desc {
+      color: #5f5e64;
+      font-size: 11px;
+    }
+    .header-set {
+      padding-left: 10px;
+      font-size: 11px;
+      line-height: 16px;
+      color: $color_main;
+    }
+    .van-icon-arrow {
+      margin-left: 4px;
+    }
+  }
   .list {
     background: #f5f6f7;
   }
@@ -624,25 +678,40 @@ export default {
   .icon-box {
     margin-top: 2px;
   }
+  .list-loading {
+    margin: 0 8px;
+    padding-top: 32px;
+    min-height: 200px;
+    text-align: center;
+    background: #fff;
+  }
   .right-bottom {
     margin: 8px;
-    border-radius: 12px;
     &::after {
       margin-left: 16px;
     }
+    &:first-child {
+      margin-top: 0;
+      border-radius: 0 0 12px 12px;
+    }
   }
   .list-tips {
     background-color: #fff;
     display: flex;
     flex-direction: column;
     align-items: center;
+    margin: 0 8px 8px;
+    border-radius: 0 0 12px 12px;
     .tip-item {
       display: flex;
       flex-direction: column;
       align-items: center;
       padding: 24px 0;
+      .empty-container {
+        padding: 0;
+      }
       p {
-        font-size: 14px;
+        font-size: 13px;
         color: #686868;
         & + button {
           margin-top: 16px;
@@ -667,7 +736,7 @@ export default {
   left: 50%;
   bottom: calc(50px + 16px);
   transform: translateX(-50%);
-  transition: bottom ease .2s;
+  transition: bottom ease 0.2s;
   z-index: 98;
 }
 .to-setting-container {
@@ -683,8 +752,8 @@ export default {
     line-height: 18px;
     color: #171826;
     border-radius: 8px;
-    background: linear-gradient(180deg, #E8FFFF 0%, #FFFFFF 100%);
-    box-shadow: 0px 4px 16px 0px #081F2614;
+    background: linear-gradient(180deg, #e8ffff 0%, #ffffff 100%);
+    box-shadow: 0px 4px 16px 0px #081f2614;
     border: 0.5px solid $main;
   }
   .to-setting-text {

+ 55 - 20
apps/mobile/src/components/message/message-card.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="message-bg" v-if="list.length">
     <div class="message-main clickable">
-      <div class="card-title">
+      <!-- <div class="card-title">
         <span>最新消息</span>
         <span class="message-unread" v-if="msgData.unread > 0">
           {{ setUnRead }}
@@ -9,12 +9,8 @@
         <div class="icon-box" @click="goMore">
           <AppIcon name="youbian" size="14" color="#c0c4cc" />
         </div>
-      </div>
-      <div
-        class="message-card"
-        :class="{ 'have-one': list.length === 1 }"
-        ref="msgCard"
-      >
+      </div> -->
+      <div class="message-card" ref="msgCard">
         <div
           class="message-group"
           :style="{
@@ -30,10 +26,19 @@
             ref="listItem"
             @click="goMessage(item)"
           >
-            <span class="dot"></span>
-            <span class="type">{{ item.type }}</span>
-            <div class="van-ellipsis title">{{ item.title }}</div>
-            <span class="time">{{ item.time }}</span>
+            <!-- <span class="dot"></span> -->
+            <van-cell class="message-item-cell" is-link>
+              <template #title>
+                <span class="icon iconfont icon-nav_un_message"></span>
+                <span class="type">{{ item.type }}</span>
+                <span class="flex-1 title van-ellipsis">{{ item.title }}</span>
+              </template>
+              <template #default>
+                <span class="time">{{ item.time }}</span>
+              </template>
+            </van-cell>
+            <!-- <div class="van-ellipsis title">{{ item.title }}</div>
+            <span class="time">{{ item.time }}</span> -->
           </div>
         </div>
       </div>
@@ -48,6 +53,7 @@ import {
   ajaxMessageOpenLog
 } from '@/api/modules/message'
 import { AppIcon } from '@/ui'
+import { Cell } from 'vant'
 import { dateMatter } from '@/utils/date'
 import { appCallReloadTab } from '@/utils/callFn/appFn'
 import { callChangeTab, openLinkOfOther } from '@/utils'
@@ -59,7 +65,8 @@ import { vw2px, px2viewport } from '@/utils'
 export default {
   name: 'message-card',
   components: {
-    [AppIcon.name]: AppIcon
+    [AppIcon.name]: AppIcon,
+    [Cell.name]: Cell
   },
   data() {
     return {
@@ -128,11 +135,11 @@ export default {
           offsetHeight: offsetYPx
         }
       }
-      const listItemHeight = (listItem?.offsetHeight || offsetYPx) * 2
-      this.groupHeight = (this.list.length / 2) * listItemHeight
+      const listItemHeight = listItem?.offsetHeight || offsetYPx
+      this.groupHeight = this.list.length * listItemHeight
       this.scrollInterval = setInterval(() => {
         this.offsetHeight += listItemHeight // 每次滚动的距离,根据需求调整
-        if (-this.offsetHeight <= -((this.list.length / 2) * listItemHeight)) {
+        if (-this.offsetHeight <= -(this.list.length * listItemHeight)) {
           this.offsetHeight = 0
         }
       }, this.msgData.rollingTiming * 1000) // 滚动间隔,单位为秒
@@ -252,7 +259,7 @@ export default {
   display: flex;
   flex-direction: column;
   justify-content: center;
-  padding: 6px 0 10px;
+  // padding: 6px 0 10px;
   height: 100%;
   background-color: #fff;
   border-radius: 12px;
@@ -292,15 +299,22 @@ export default {
     align-items: center;
   }
   .message-group {
-    max-width: 315px;
+    //max-width: 315px;
+    width: 100%;
     transition: transform 0.5s ease; /* 添加过渡效果 */
   }
   .message-item {
     display: flex;
     flex-direction: row;
     align-items: center;
-    height: 20px;
+    height: 40px;
     line-height: 18px;
+    &-cell {
+      padding: 0;
+      line-height: normal;
+      display: flex;
+      align-items: center;
+    }
     &.visited {
       .dot {
         background-color: #c0c4cc;
@@ -324,16 +338,37 @@ export default {
     }
     .title {
       font-size: 11px;
-      line-height: 18px;
+      line-height: 24px;
       color: #171826;
       margin-right: 12px;
     }
     .time {
       flex-shrink: 0;
       font-size: 11px;
-      line-height: 18px;
+      line-height: 24px;
       color: #9b9ca3;
     }
+    .icon-nav_un_message {
+      margin-right: 4px;
+      color: $color_main;
+    }
+    ::v-deep {
+      .van-cell__title {
+        display: flex;
+        align-items: center;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+      .van-cell__value {
+        flex: unset;
+      }
+      .van-cell__right-icon {
+        color: $color_main;
+        font-size: 12px;
+        line-height: 26px;
+      }
+    }
   }
   .icon-youbian {
     font-size: 16px;

+ 5 - 1
apps/mobile/src/components/recommend/index.vue

@@ -180,7 +180,11 @@ export default {
   },
   methods: {
     getTitle({ title, keyWord }) {
-      return replaceKeyword(title, keyWord || [])
+      return replaceKeyword(
+        title,
+        keyWord || [],
+        '<span class="highlight-text-orange-bd">' + keyWord + '</span>'
+      )
     },
     onClickOutSide() {
       this.activeName = ''

Datei-Diff unterdrückt, da er zu groß ist
+ 488 - 255
apps/mobile/src/components/search/bidding/filters.vue


+ 6 - 0
apps/mobile/src/components/selector/keyword-input-group/index.vue

@@ -334,4 +334,10 @@ export default {
     }
   }
 }
+.search-mode-container {
+  .checkbox {
+    width: 16px;
+    height: 16px;
+  }
+}
 </style>

+ 18 - 6
apps/mobile/src/components/selector/money-input-group/index.vue

@@ -3,7 +3,8 @@
     <van-field
       type="number"
       v-model="inputMap.start"
-      :placeholder="placeholder"
+      :maxlength="maxLength.start"
+      :placeholder="placeholder.start"
       :class="{ focus: focus.start && hoverBorderHighlight }"
       @click.stop="onClick('start')"
       @input="onInput('start')"
@@ -17,8 +18,9 @@
     <div class="line"></div>
     <van-field
       type="number"
+      :maxlength="maxLength.end"
       v-model="inputMap.end"
-      :placeholder="placeholder"
+      :placeholder="placeholder.end"
       :class="{ focus: focus.end && hoverBorderHighlight }"
       @click.stop="onClick('end')"
       @input="onInput('end')"
@@ -44,13 +46,23 @@ export default {
       type: Boolean,
       default: true
     },
-    placeholder: {
-      type: String,
-      default: '请输入金额'
-    },
     extra: {
       type: String,
       default: '万'
+    },
+    placeholder: {
+      type: Object,
+      default: () => ({
+        start: '请输入金额',
+        end: '请输入金额'
+      })
+    },
+    maxLength: {
+      type: Object,
+      default: () => ({
+        start: 10,
+        end: 10
+      })
     }
   },
   data() {

+ 2 - 5
apps/mobile/src/composables/attachment-download/component/AttachmentDownload.vue

@@ -158,7 +158,7 @@ export default {
       power: (state) => state.user.power,
       userInfo: (state) => state.user.userInfo
     }),
-    IsCustomTopNet () {
+    IsCustomTopNet() {
       return this.customSkip
     },
     canShowTip() {
@@ -181,10 +181,7 @@ export default {
       }
     },
     fileNum() {
-      if (this.resourcePack.number > 0) {
-        return this.resourcePack.number
-      }
-      return this.power?.fileNum || 0
+      return this.resourcePack.number || 0
     },
     isNewSuper() {
       return this.power.viper && this.isSuper

+ 2 - 2
apps/mobile/src/data/bidding.js

@@ -10,11 +10,11 @@ export const biddingSearchListType = [
 // 招标搜索范围
 export const biddingSearchScope = [
   {
-    label: '标题搜索',
+    label: '标题',
     key: 'title'
   },
   {
-    label: '正文搜索',
+    label: '正文',
     key: 'content'
   },
   {

+ 23 - 5
apps/mobile/src/store/modules/user.js

@@ -9,7 +9,8 @@ import {
   getMySelectEntInfo,
   getUserIdentity,
   changeUserIdentity,
-  getMineCompany
+  getMineCompany,
+  getIsWhiteList
 } from '@/api/modules'
 
 export default {
@@ -80,7 +81,9 @@ export default {
     // 用户当前身份
     userCurrentIdentity: null,
     // 用户所属公司信息
-    userCompanyInfo: null
+    userCompanyInfo: null,
+    // 白名单用户
+    whiteListStatus: false
   }),
   mutations: {
     changeVipSwitch(state, data) {
@@ -117,6 +120,9 @@ export default {
     // 用户所属公司信息
     updateCompanyInfo(state, data) {
       state.userCompanyInfo = data
+    },
+    updateIsWhiteList(state, data) {
+      state.whiteListStatus = data
     }
   },
   actions: {
@@ -146,9 +152,8 @@ export default {
     },
     async userVipSwitchState({ commit }, payload) {
       try {
-        const { error_code: code, data = {} } = await userVipSwitchState(
-          payload
-        )
+        const { error_code: code, data = {} } =
+          await userVipSwitchState(payload)
         if (code === 0) {
           commit('changeVipSwitch', data.vt)
         }
@@ -234,6 +239,15 @@ export default {
           return data
         }
       } catch (error) {}
+    },
+    async getWhiteListInfo({ commit }) {
+      try {
+        const { error_code: code, data = {} } = await getIsWhiteList()
+        if (code === 0) {
+          commit('updateIsWhiteList', data?.onTheWhitelist)
+          return data
+        }
+      } catch (error) {}
     }
   },
   getters: {
@@ -413,6 +427,10 @@ export default {
     // 用户公司信息
     userCompanyInfo(state) {
       return state.userCompanyInfo || {}
+    },
+    // 是否是白名单用户
+    isWhiteList(state) {
+      return state.whiteListStatus || false
     }
   }
 }

+ 1 - 0
apps/mobile/src/ui/j-cell/index.vue

@@ -5,6 +5,7 @@
     class="j-row-cell bg-white"
     :class="{ 'cell-clickable': isLink }"
     @click="onClick"
+    ref="cellRef"
     v-on="$listeners"
   >
     <div class="j-row-cell-content" :class="contentClass">

+ 33 - 26
apps/mobile/src/ui/project-cell/index.vue

@@ -19,7 +19,7 @@
         </span>
         <span v-html="getTitle"></span>
         <span v-if="filetext_search" style="padding-left: 8px"
-          >(<span style="color: #2abed1">{{ setKeyLength }}</span
+          >(<span class="highlight-text-orange-bd">{{ setKeyLength }}</span
           >在附件中)</span
         >
       </div>
@@ -49,6 +49,15 @@
               {{ leftTopBadgeText }}
             </div>
           </slot>
+          <span
+            v-if="pushSourceTag.text"
+            class="tag-item push-source-tag"
+            :class="pushSourceTag.className"
+            >{{ pushSourceTag.text }}</span
+          >
+          <span v-if="isFile && fileText" class="tag-item title-file main">
+            <slot>{{ fileText.replace(/[\[\]]/g, '') }}</slot>
+          </span>
           <span
             class="tag-item"
             :class="item.className"
@@ -58,15 +67,6 @@
           >
             <slot name="tag-item">{{ item.name }}</slot>
           </span>
-          <span v-if="isFile && fileText" class="tag-item title-file main">
-            <slot>{{ fileText.replace(/[\[\]]/g, '') }}</slot>
-          </span>
-          <span
-            v-if="pushSourceTag.text"
-            class="tag-item push-source-tag"
-            :class="pushSourceTag.className"
-            >{{ pushSourceTag.text }}</span
-          >
         </div>
       </template>
     </div>
@@ -109,10 +109,7 @@
         </template>
       </div>
     </div>
-    <div
-      class="footer-container"
-      :class="{ 'van-hairline--top': isNotDefault }"
-    >
+    <div class="footer-container">
       <template v-if="isDefault">
         <slot name="left-top-badge">
           <div class="badge left-top red" v-if="leftTopBadgeText">
@@ -268,11 +265,11 @@ export default {
           text: '个人订阅'
         },
         2: {
-          className: 'orange',
+          className: 'main',
           text: '企业自动分发'
         },
         3: {
-          className: 'orange',
+          className: 'main',
           text: '企业手动分发'
         }
       }
@@ -307,18 +304,27 @@ export default {
       return this.tagSourceMap[this.pushSource] || {}
     },
     getTitle() {
-      return replaceKeyword(this.title, this.keys)
+      return replaceKeyword(this.title, this.keys, [
+        '<span class="highlight-text-orange-bd">',
+        '</span>'
+      ])
     },
     getDetail() {
       if (this.autoShowDetail) {
         // 有匹配词且匹配上才显示正文
         if (this.setDetailText) {
-          return replaceKeyword(this.setDetailText, this.keys)
+          return replaceKeyword(this.setDetailText, this.keys, [
+            '<span class="highlight-text-orange-bd">',
+            '</span>'
+          ])
         } else {
           return ''
         }
       } else {
-        return replaceKeyword(this.detail, this.keys)
+        return replaceKeyword(this.detail, this.keys, [
+          '<span class="highlight-text-orange-bd">',
+          '</span>'
+        ])
       }
     },
     // 正文开头和高亮词之间,最多保留10个字符
@@ -372,7 +378,9 @@ export default {
 }
 .project-cell {
   position: relative;
-  padding: 12px 16px;
+  margin: 0 8px;
+  border-radius: 12px;
+  padding: 12px;
   font-weight: 400;
   font-size: 16px;
   line-height: 24px;
@@ -392,7 +400,7 @@ export default {
       top: 0;
     }
     &.red {
-      color: $red;
+      color: $orange_red;
       background-color: $color_red_background;
     }
   }
@@ -431,7 +439,7 @@ export default {
     flex-wrap: wrap;
   }
   .tag-item {
-    margin: 2px;
+    margin: 2px 2px 4px;
     display: inline-block;
     box-sizing: border-box;
     border-radius: 4px;
@@ -454,7 +462,7 @@ export default {
       border-color: $color_gold_deep_background;
     }
     &.red {
-      color: $red;
+      color: $orange_red;
       background-color: $color_red_background;
     }
     &--time {
@@ -497,7 +505,7 @@ export default {
   }
 
   .more-detail {
-    margin-bottom: 12px;
+    margin-bottom: 4px;
   }
   .detail-item {
     font-size: 13px;
@@ -515,7 +523,7 @@ export default {
     }
     .info-group {
       order: 4;
-      margin-bottom: 12px;
+      margin-bottom: 2px;
       align-items: flex-start;
       flex-direction: column;
     }
@@ -537,7 +545,6 @@ export default {
       display: flex;
       align-items: center;
       justify-content: space-between;
-      padding-top: 10px;
     }
   }
 }

+ 147 - 74
apps/mobile/src/utils/format/modules/filter-history-formatter.js

@@ -1,19 +1,20 @@
+import dayjs from 'dayjs'
+import { InfoTypeTransform } from './info-type-transform'
 import chinaMapJSON from '@/assets/js/china_area'
 import {
-  biddingSearchScope,
   biddingSearchConcat,
-  industryListMapExp,
-  buyerClassListMapExp,
   biddingSearchFileExists,
+  biddingSearchScope,
+  biddingSearchTime,
+  buyerClassListMapExp,
+  industryListMapExp,
   infoTypeAdvancedList,
+  infoTypeListExp,
   infoTypeNotAdvancedList,
-  wordsModeList,
   searchModeList,
-  biddingSearchTime
+  wordsModeList
 } from '@/data'
 import { dateFormatter } from '@/utils'
-import { InfoTypeTransform } from './info-type-transform'
-import dayjs from 'dayjs'
 
 /**
  * 整理已存筛选数据,去除空数据
@@ -75,25 +76,27 @@ export function filterHistoryNotEmptyFormat(formatted) {
    * searchGroup === '2' 表示为超前项目
    * 如果此时信息类型为空。则显示其所有类型的文字,而非"全部"两个字
    */
-  const infoTypeAll =
-    !infoTypeText || (Array.isArray(infoTypeText) && infoTypeText.length === 0)
+  const infoTypeAll
+    = !infoTypeText || (Array.isArray(infoTypeText) && infoTypeText.length === 0)
   if (infoTypeAll) {
     if (searchGroup === '1') {
       // 非超前项目
       infoTypeText = infoTypeNotAdvancedList
-        .map((i) => i.value)
-        .filter((i) => !!i)
-    } else if (searchGroup === '2') {
+        .map(i => i.value)
+        .filter(i => !!i)
+    }
+    else if (searchGroup === '2') {
       // 超前项目
       infoTypeText = infoTypeAdvancedList
         .map((i) => {
           if (i && i.value && i.value.includes('拟建')) {
             return i.name
-          } else {
+          }
+          else {
             return i.value
           }
         })
-        .filter((i) => !!i)
+        .filter(i => !!i)
     }
   }
   if (Array.isArray(infoTypeText) && infoTypeText.length) {
@@ -191,10 +194,10 @@ export class FilterHistoryAjaxModel2ViewModel {
     // 采购单位
     const { buyerClass, buyerClassText } = this.formatBuyerClass(map.buyerclass)
     // 联系方式
-    const { basicData: buyerConcat, basicDataText: buyerConcatText } =
-      this.formatContact(map.buyertel)
-    const { basicData: winnerConcat, basicDataText: winnerConcatText } =
-      this.formatContact(map.winnertel)
+    const { basicData: buyerConcat, basicDataText: buyerConcatText }
+      = this.formatContact(map.buyertel)
+    const { basicData: winnerConcat, basicDataText: winnerConcatText }
+      = this.formatContact(map.winnertel)
 
     const formatted = {
       keywords: map.searchvalue ? map.searchvalue.split(',') : [],
@@ -238,7 +241,8 @@ export class FilterHistoryAjaxModel2ViewModel {
 
   static mapToList(map) {
     let list = []
-    if (!map) return list
+    if (!map)
+      return list
     for (const key in map) {
       if (Array.isArray(map[key])) {
         list = list.concat(map[key])
@@ -262,7 +266,7 @@ export class FilterHistoryAjaxModel2ViewModel {
       m = '0'
     }
     m = String(m)
-    const target = wordsModeList.find((item) => m === item.key)
+    const target = wordsModeList.find(item => m === item.key)
     if (target) {
       result.wordsMode = [target.key]
       result.wordsModeText = target.label
@@ -285,7 +289,7 @@ export class FilterHistoryAjaxModel2ViewModel {
       m = '0'
     }
     m = String(m)
-    const target = searchModeList.find((item) => m === item.key)
+    const target = searchModeList.find(item => m === item.key)
     if (target) {
       result.searchMode = [target.key]
       result.searchModeText = target.label
@@ -305,7 +309,8 @@ export class FilterHistoryAjaxModel2ViewModel {
       scope: undefined,
       scopeText: undefined
     }
-    if (!val) return result
+    if (!val)
+      return result
     const map = {}
     biddingSearchScope.forEach((item) => {
       map[item.key] = item.label
@@ -316,7 +321,7 @@ export class FilterHistoryAjaxModel2ViewModel {
       .map((key) => {
         return map[key]
       })
-      .filter((key) => !!key)
+      .filter(key => !!key)
 
     result.scope = selectKeyArr
     result.scopeText = selectKeyTextArr
@@ -335,7 +340,8 @@ export class FilterHistoryAjaxModel2ViewModel {
       industry: undefined,
       industryText: undefined
     }
-    if (!val || val === '全部') return result
+    if (!val || val === '全部')
+      return result
 
     const industry = {}
     let industryText = []
@@ -346,8 +352,9 @@ export class FilterHistoryAjaxModel2ViewModel {
       const industryChildren = industry[vSplit[0]]
       if (Array.isArray(industryChildren)) {
         industryChildren.push(vSplit[1])
-      } else {
-        industry[vSplit[0]] = [vSplit[1]]
+      }
+      else {
+        industry[vSplit[0]] = vSplit[1] ? [vSplit[1]] : [vSplit[0]]
       }
     })
     if (Object.keys(industry).length) {
@@ -364,7 +371,8 @@ export class FilterHistoryAjaxModel2ViewModel {
     for (const key in industry) {
       if (industry[key].length === calcChildrenCount[key]) {
         industryText.push(key)
-      } else {
+      }
+      else {
         // P510延申需求:因数据源二级分类都加上的“其他”,为了做区分,如果二级分类中有“其他” 显示的时候要拼上一级分类, 没有“其他”的还按原来需求只显示二级分类
         const industryArr = industry[key].map((item) => {
           if (key === '其他') {
@@ -372,7 +380,8 @@ export class FilterHistoryAjaxModel2ViewModel {
           }
           if (item === '其他') {
             return `${key}_${item}`
-          } else {
+          }
+          else {
             return item
           }
         })
@@ -412,7 +421,8 @@ export class FilterHistoryAjaxModel2ViewModel {
     let text = ''
     if (area && city) {
       text = `${area},${city}`
-    } else {
+    }
+    else {
       text = area || city
     }
     if (district) {
@@ -430,7 +440,8 @@ export class FilterHistoryAjaxModel2ViewModel {
         if (pName.includes(regItem)) {
           // 省级区域
           region[regItem] = {}
-        } else {
+        }
+        else {
           p.city.forEach((c) => {
             const cName = c.name
             // 市级区域 示例:{ 郑州市:[] }
@@ -439,12 +450,14 @@ export class FilterHistoryAjaxModel2ViewModel {
                 region[pName] = {}
               }
               region[pName][regItem] = []
-            } else {
+            }
+            else {
               // 区县 示例:郑州市:['金水区']
               const districtArr = []
               if (c.area) {
-                const district =
-                  regItem.indexOf('_') > -1 ? regItem.split('_')[1] : regItem
+                const district = regItem.includes('_')
+                  ? regItem.split('_')[1]
+                  : regItem
                 c.area.forEach((dis) => {
                   if (dis.includes(district)) {
                     districtArr.push(district)
@@ -455,8 +468,9 @@ export class FilterHistoryAjaxModel2ViewModel {
                 if (!region[pName]) {
                   region[pName] = {}
                 }
-                const city =
-                  regItem.indexOf('_') > -1 ? regItem.split('_')[0] : regItem
+                const city = regItem.includes('_')
+                  ? regItem.split('_')[0]
+                  : regItem
                 if (!region[pName][city]) {
                   region[pName][city] = []
                 }
@@ -476,25 +490,28 @@ export class FilterHistoryAjaxModel2ViewModel {
 
     return result
   }
+
   static getAreaCityText(regionMap) {
     const { area, city, district } = areaObjToSingle(regionMap)
     let text = ''
     if (area && city) {
       text = `${area},${city}`
-    } else {
+    }
+    else {
       text = area || city
     }
     if (district) {
       const dArr = district.split(',') || []
-      let dItem = dArr
+      const dItem = dArr
         .map((temp) => {
-          return temp.indexOf('_') > -1 ? temp.split('_')[1] : temp
+          return temp.includes('_') ? temp.split('_')[1] : temp
         })
         .join('/')
       text += text ? `,${dItem}` : `${dItem}`
     }
     return text
   }
+
   /**
    * 金额整理1
    * @param String '1111-22222'
@@ -518,9 +535,11 @@ export class FilterHistoryAjaxModel2ViewModel {
     let priceText = ''
     if (start && end) {
       priceText = `${start}-${end}${unit}`
-    } else if (start && !end) {
+    }
+    else if (start && !end) {
       priceText = `${start}${unit}以上`
-    } else if (!start && end) {
+    }
+    else if (!start && end) {
       priceText = `${end}${unit}以下`
     }
     return priceText
@@ -539,7 +558,8 @@ export class FilterHistoryAjaxModel2ViewModel {
       publishTime: undefined,
       publishTimeText: undefined
     }
-    if (!val) return result
+    if (!val)
+      return result
     const map = {}
     biddingSearchTime.forEach((item) => {
       map[item.key] = item.label
@@ -555,11 +575,11 @@ export class FilterHistoryAjaxModel2ViewModel {
       const start = split[0] * 1000
       const end = split[1] * 1000
       const textArr = []
-      if (start && !isNaN(start)) {
+      if (start && !Number.isNaN(start)) {
         t.start = start
         textArr[0] = dateFormatter(start, 'yyyy/MM/dd')
       }
-      if (end && !isNaN(end)) {
+      if (end && !Number.isNaN(end)) {
         t.end = end
         textArr[1] = dateFormatter(end, 'yyyy/MM/dd')
       }
@@ -567,14 +587,17 @@ export class FilterHistoryAjaxModel2ViewModel {
       let publishTimeText = ''
       if (textArr[0] && textArr[1]) {
         publishTimeText = textArr.join('-')
-      } else if (textArr[0] && !textArr[1]) {
+      }
+      else if (textArr[0] && !textArr[1]) {
         publishTimeText = `${textArr[0]}以后`
-      } else if (!textArr[0] && textArr[1]) {
+      }
+      else if (!textArr[0] && textArr[1]) {
         publishTimeText = `${textArr[1]}以前`
       }
       // 计算text
       result.publishTimeText = publishTimeText
-    } else {
+    }
+    else {
       t.exact = val
       result.publishTimeText = map[val] || ''
     }
@@ -594,12 +617,14 @@ export class FilterHistoryAjaxModel2ViewModel {
       infoType: undefined,
       infoTypeText: undefined
     }
-    if (!val || val === '全部') return result
+    if (!val || val === '全部')
+      return result
     const arr = val.split(',').map((v) => {
       // 把<拟建>替换成<拟建项目>
       if (v === '拟建') {
         return '拟建项目'
-      } else {
+      }
+      else {
         return v
       }
     })
@@ -626,7 +651,8 @@ export class FilterHistoryAjaxModel2ViewModel {
       buyerClass: undefined,
       buyerClassText: undefined
     }
-    if (!val || val === '全部') return result
+    if (!val || val === '全部')
+      return result
     result.buyerClass = val.split(',')
 
     // 逻辑和行业类似,如果二级全选,则展示一级分类文字,否则展示二级分类文字
@@ -635,7 +661,7 @@ export class FilterHistoryAjaxModel2ViewModel {
     const keyListMap = {}
     for (const key in buyerClassListMapExp) {
       keyList.push(key)
-      if (val.indexOf(key) !== -1) {
+      if (val.includes(key)) {
         // 存在
         if (Array.isArray(keyListMap[key])) {
           keyListMap[key] = []
@@ -644,11 +670,12 @@ export class FilterHistoryAjaxModel2ViewModel {
       if (Array.isArray(buyerClassListMapExp[key])) {
         // 循环二级子项
         buyerClassListMapExp[key].forEach((item) => {
-          if (val.indexOf(item) !== -1) {
+          if (val.includes(item)) {
             // 存在
             if (Array.isArray(keyListMap[key])) {
               keyListMap[key].push(item)
-            } else {
+            }
+            else {
               keyListMap[key] = [item]
             }
           }
@@ -660,7 +687,8 @@ export class FilterHistoryAjaxModel2ViewModel {
     for (const key in keyListMap) {
       if (keyListMap[key].length === buyerClassListMapExp[key].length) {
         buyerClassText.push(key)
-      } else {
+      }
+      else {
         buyerClassText = [...buyerClassText, ...keyListMap[key]]
       }
     }
@@ -670,7 +698,7 @@ export class FilterHistoryAjaxModel2ViewModel {
     return {
       buyerClass: result.buyerClass,
       buyerClassText: result.buyerClassText,
-      keyListMap: keyListMap
+      keyListMap
     }
   }
 
@@ -745,7 +773,8 @@ export class FilterHistoryViewModel2AjaxModel {
    * 参数val示例:[content, title ,ppa]
    */
   static formatScope(val = [], split = ',') {
-    if (!Array.isArray(val)) return ''
+    if (!Array.isArray(val))
+      return ''
     return val.join(split)
   }
 
@@ -761,7 +790,8 @@ export class FilterHistoryViewModel2AjaxModel {
    */
   static formatIndustry(val = {}, split = ',') {
     let industry = ''
-    if (!val || Object.keys(val).length === 0) return industry
+    if (!val || Object.keys(val).length === 0)
+      return industry
 
     const industryArr = []
 
@@ -771,7 +801,8 @@ export class FilterHistoryViewModel2AjaxModel {
           // 如果选择一级分类其他,则传入一级分类‘其他’
           if (item === '其他' && key === '其他') {
             industryArr.push(`${key}`)
-          } else {
+          }
+          else {
             industryArr.push(`${key}_${item}`)
           }
         })
@@ -784,14 +815,15 @@ export class FilterHistoryViewModel2AjaxModel {
   }
 
   /**
- * 处理筛选条件二级类(行业)其他, 查询参数有其他时,提交时需要再增加一个‘其它’
- * '建筑工程,水利水电_其他,信息技术_其他,机械设备_其他设备'
- */
+   * 处理筛选条件二级类(行业)其他, 查询参数有其他时,提交时需要再增加一个‘其它’
+   * '建筑工程,水利水电_其他,信息技术_其他,机械设备_其他设备'
+   */
   static formatFilterApiOther(str) {
-    if (!str) return
+    if (!str)
+      return
     const arr = str.split(',')
-    const newArr = arr.map(item => {
-      if(item.indexOf('_其他') > -1) {
+    const newArr = arr.map((item) => {
+      if (item.includes('_其他')) {
         item = `${item},${item.replace(/_其他(.*)$/, '_其它')}`
       }
       return item
@@ -857,6 +889,7 @@ export class FilterHistoryViewModel2AjaxModel {
   static formatAreaCity(p = {}, split = ',') {
     return areaObjToSingle(p, split)
   }
+
   /**
    * 金额整理
    * @returns String
@@ -865,7 +898,8 @@ export class FilterHistoryViewModel2AjaxModel {
     const { start, end } = price
     if (start || end) {
       return [start || '', end || ''].join(split)
-    } else {
+    }
+    else {
       return ''
     }
   }
@@ -887,7 +921,8 @@ export class FilterHistoryViewModel2AjaxModel {
    */
   static formatTime(time, exact = false, split = '_') {
     let sortedTime = ''
-    if (!time) return sortedTime
+    if (!time)
+      return sortedTime
     const { start, end } = time
     if (exact || time.exact === 'exact') {
       const startVal = start ? dayjs(start).unix() : ''
@@ -895,10 +930,12 @@ export class FilterHistoryViewModel2AjaxModel {
       sortedTime = [startVal, endVal].join(split)
       if (startVal || endVal) {
         return [startVal, endVal].join(split)
-      } else {
+      }
+      else {
         return [].join(split)
       }
-    } else {
+    }
+    else {
       sortedTime = time.exact || ''
     }
     return sortedTime
@@ -913,7 +950,8 @@ export class FilterHistoryViewModel2AjaxModel {
    */
   static formatInfoType(infoType, split = ',') {
     let arr = []
-    if (!infoType) return arr.join(split)
+    if (!infoType)
+      return arr.join(split)
     for (const key in infoType) {
       arr = arr.concat(infoType[key])
     }
@@ -929,7 +967,8 @@ export class FilterHistoryViewModel2AjaxModel {
    */
   static formatBuyerClass(val, split = ',') {
     let buyerClass = ''
-    if (!val || Object.keys(val).length === 0) return buyerClass
+    if (!val || Object.keys(val).length === 0)
+      return buyerClass
 
     buyerClass = []
 
@@ -956,15 +995,17 @@ function areaObjToSingle(obj, split = ',') {
     city: '',
     district: ''
   }
-  if (!obj) return map
+  if (!obj)
+    return map
   const area = []
-  let city = []
+  const city = []
   let district = []
   for (const key in obj) {
     if (typeof obj[key] === 'object') {
       if (Object.keys(obj[key]).length === 0) {
         area.push(key)
-      } else {
+      }
+      else {
         // 城市项
         const cityItem = obj[key]
         for (const cKey in cityItem) {
@@ -973,9 +1014,10 @@ function areaObjToSingle(obj, split = ',') {
           if (Array.isArray(districtItem)) {
             if (districtItem.length === 0) {
               city.push(cKey)
-            } else {
+            }
+            else {
               const resetArr = districtItem.map((temp) => {
-                return cKey + '_' + temp
+                return `${cKey}_${temp}`
               })
               district = district.concat(resetArr)
             }
@@ -990,3 +1032,34 @@ function areaObjToSingle(obj, split = ',') {
     district: district.join(split)
   }
 }
+
+/**
+ * 信息类型比对是否全选
+ * selectedStr 选中的信息类型(有一级分类、二级分类) '拟建/招标预告/招标公告/招标结果/招标信用信息'
+ * sourceList 信息类型数据源 默认是infoTypeListExp包含所有的信息类型
+ * separator 分隔符
+ */
+export function deepCompareInfoType(
+  selectedStr = '',
+  sourceList = [],
+  separator = '/'
+) {
+  if (sourceList.length === 0) {
+    sourceList = infoTypeListExp
+  }
+  const excludeAll = sourceList.filter(v => v.name !== '全部')
+  const selectedArr = selectedStr.split(separator)
+
+  excludeAll.forEach((v) => {
+    v.selected = false
+
+    selectedArr.forEach((s) => {
+      if (v.name === s) {
+        v.selected = true
+      }
+    })
+  })
+  const checkedStateArr = excludeAll.map(v => v.selected)
+  const isAllChecked = checkedStateArr.every(v => v)
+  return isAllChecked
+}

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

@@ -796,3 +796,8 @@ export default {
   margin-bottom: 32px;
 }
 </style>
+<style>
+.no-select {
+  user-select: unset !important;
+}
+</style>

+ 35 - 26
apps/mobile/src/views/search/middle/bidding/index.vue

@@ -23,7 +23,7 @@
             v-if="filterHistory.length"
             :list="filterHistory"
             @click="clickFilterHistory"
-            title="已存筛选条件"
+            title="加载已存筛选条件"
           >
             <div
               slot="header-right"
@@ -139,7 +139,7 @@ export default {
     ...mapState({
       hotKeyList: (state) => state.search.hotKeyList
     }),
-    ...mapGetters('user', ['isFree', 'isLogin', 'isMember', 'isSuper']),
+    ...mapGetters('user', ['isFree', 'isLogin', 'isMember', 'isSuper'])
     // ...mapGetters('search', ['biddingSearchHistory'])
   },
   beforeRouteEnter(to, from, next) {
@@ -179,7 +179,7 @@ export default {
           }
         })
         .catch((error) => {
-          console.error(`清除历史记录失败: ${error}`);
+          console.error(`清除历史记录失败: ${error}`)
         })
     },
     getQueryString() {
@@ -195,7 +195,8 @@ export default {
         BIDDING_SEARCH_GROUP_LAST_CACHE_KEY,
         false
       )
-      if (params) {
+      // P611修复遗漏问题:搜索中间页信息类型免费用户不存上次选择的信息类型
+      if (params && !this.isFree) {
         this.searchGroup = params.searchGroup
       }
     },
@@ -214,7 +215,9 @@ export default {
       return t && Object.keys(t).length > 0
     },
     getLastCache() {
-      return this.$storage.get(BIDDING_SEARCH_LAST_FILTERS_CACHE_KEY, false, { login: true })
+      return this.$storage.get(BIDDING_SEARCH_LAST_FILTERS_CACHE_KEY, false, {
+        login: true
+      })
     },
     getLastFilters() {
       const lastFilters = this.getLastCache()
@@ -271,7 +274,9 @@ export default {
       // 同步输入到缓存
       this.syncInputToCacheFilters()
 
-      const filters = this.hasValue(this.lastFiltersFormatted) ? this.lastFiltersFormatted : undefined
+      const filters = this.hasValue(this.lastFiltersFormatted)
+        ? this.lastFiltersFormatted
+        : undefined
       if (filters && this.clickSearchGroup) {
         // 重置信息类型
         filters.searchGroup = this.clickSearchGroup
@@ -485,36 +490,40 @@ export default {
 .j-button-badge {
   position: relative;
   &::after {
-    content: attr(data-badge);
+    //content: attr(data-badge);
     position: absolute;
-    right: -6px;
-    top: -10px;
-    padding: 2px 6px;
-    font-size: 10px;
-    line-height: 14px;
-    color: #fff;
-    background: linear-gradient(98deg, #ffa674 0%, #f01212 100%);
-    border-radius: 7px 7px 7px 0;
-    white-space: nowrap;
+    right: -1px;
+    top: -3px;
+    //padding: 2px 6px;
+    //font-size: 10px;
+    //line-height: 14px;
+    //color: #fff;
+    //background: linear-gradient(98deg, #ffa674 0%, #f01212 100%);
+    //border-radius: 7px 7px 7px 0;
+    //white-space: nowrap;
+    content: '';
+    display: inline-block;
+    width: 12px;
+    height: 12px;
+    background: url(@/assets/image/icon/hot.png);
+    background-size: contain;
   }
 }
 
 .search-type-tab-container {
-  padding: 10px 16px;
+  padding: 10px 25px;
   display: flex;
+  background: linear-gradient(#2abed11f, #2abed100);
 
   .search-type-item {
-    padding: 4px 12px;
+    padding: 1px 12px;
     font-size: 12px;
     line-height: 22px;
-    color: #5f5e64;
-    border-radius: 4px;
-    background: linear-gradient(
-      180deg,
-      rgba(255, 255, 255, 0) 0%,
-      #ffffff 100%
-    );
-    box-shadow: 0px 2px 8px 0px #15abda33;
+    color: #171826;
+    border-radius: 12px;
+    white-space: nowrap;
+    background: linear-gradient(180deg, #ffffff 0%, #f7f9fa 100%);
+    box-shadow: 0px 4px 2px 0px #3693b31f;
     &:not(:last-of-type) {
       margin-right: 12px;
     }

+ 551 - 115
apps/mobile/src/views/search/result/bidding/index.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="j-container search-result-bidding top-radius">
-    <div
+    <!-- <div
       class="bidding-advanced-switch"
       v-if="conf.searchGroupList.length"
       :class="{ 'loading-mask': listState.loading }"
@@ -26,8 +26,8 @@
           </div>
         </van-tab>
       </van-tabs>
-    </div>
-    <div class="j-header linear-main-bg">
+    </div> -->
+    <div class="j-header linear-main-bg" v-show="tabSwitchShow">
       <!-- 筛选器 -->
       <BiddingSearchFilters
         :bidColPower="pageState.bidColPower"
@@ -38,13 +38,14 @@
         @confirm="onFilterConfirm"
         @reset="doSearch"
         @open="doOpen"
-        :defaultFilterState="defaultFilterState"
+        :defaultFilterState="noChangeDefaultFilterState"
         :dropdownMenuMaxHeight="conf.maxHeight"
         :infoTypeSourceConf="activeSearchGroupInfo"
+        :topSearch="topSearch"
         v-model="filters"
       />
       <!-- 精简列表/详细列表/表格 -->
-      <div v-if="tabSwitchShow" class="tab-switch bg-white border-line-b">
+      <!-- <div v-if="tabSwitchShow" class="tab-switch bg-white border-line-b">
         <van-tabs
           class="tab-left"
           v-model="pageState.listTabActive"
@@ -69,47 +70,36 @@
             <span class="text">保存筛选条件</span>
           </div>
         </div>
+      </div> -->
+      <div class="flex flex-justify-between tab-saved" v-if="isLogin">
+        <div class="tab-saved-left ellipsis">
+          <span class="tab-saved-left-label">已选:</span>
+          <span class="tab-saved-left-value">{{ calcFilterText }}</span>
+        </div>
+        <div class="tab-saved-right">
+          <span v-if="!isFree" class="clear-action" @click="onClearFilter"
+            >清空</span
+          >
+          <span class="save-action" @click="saveFilterToHistory">保存</span>
+        </div>
       </div>
       <div class="intercept-tip-container" v-show="interceptTipText">
         <AppIcon name="tishi" /> {{ interceptTipText }}
       </div>
-      <div class="recommend-card-container">
-        <!-- 超前项目推荐 & 定制化分析报告 -->
-        <RecommendCard
-          :key="recommendInfo.key"
-          v-if="recommendInfo.show"
-          v-model="recommendInfo.showContent"
-          :chart-data="recommendInfo.chart"
-          :brief-list="recommendInfo.brief"
-          :project-list="recommendInfo.project"
-          :keys="pageState.splitKeys"
-          @do-leave="saveState"
-        />
-      </div>
     </div>
     <div class="j-main list-container" ref="listContainer">
-      <van-list
-        v-model="listState.loading"
-        :finished="listState.finished"
-        :offset="listState.offset"
-        :finished-text="finishedText"
-        v-show="
-          pageState.listTabActive === 'list' ||
-          pageState.listTabActive === 'detailedList'
-        "
-        @load="getList"
-        class="more-list calc-height-1px"
-        ref="vanList"
-      >
-        <div class="tab-search-info" v-show="tabSearchInfoShow">
-          <p class="search-total-count">
-            <template v-if="listState.total > 0">
-              搜索到<span class="highlight-text">
-                {{ calcListTotalText(listState.total) }} </span
-              >条信息
-            </template>
-          </p>
-          <div class="tab-right">
+      <div class="tab-search-info" v-show="tabSearchInfoShow">
+        <div
+          class="flex flex-(items-center justify-between) tab-search-info-top"
+        >
+          <div class="flex">
+            <p class="search-total-count">
+              <template v-if="listState.total > 0">
+                搜索到<span class="highlight-text">
+                  {{ calcListTotalText(listState.total) }} </span
+                >条信息
+              </template>
+            </p>
             <div
               class="data-export clickable"
               v-show="!inInjectBI"
@@ -117,18 +107,47 @@
               @click="dataExport"
             >
               <AppIcon name="shujudaochu_xiao1" />
-              <span class="text">数据导出</span>
+              <span class="text">导出</span>
             </div>
           </div>
+          <div class="tab-right">
+            <van-popover
+              v-model="showPopover"
+              trigger="click"
+              :actions="cardTypeTabList"
+              :offset="[6, 16]"
+              placement="bottom-end"
+              get-container=".tab-search-info"
+            >
+              <div class="tab-column">
+                <div
+                  class="tab-column-item"
+                  :class="{ active: pageState.listTabActive === tab.name }"
+                  v-for="(tab, index) in cardTypeTabList"
+                  :name="tab.name"
+                  :key="index"
+                  @click.stop="onListTabClick(tab.name)"
+                >
+                  {{ tab.title }}
+                </div>
+              </div>
+              <template #reference>
+                <div class="selected-tab-content">
+                  <span>{{ listTabActiveText }}</span>
+                  <van-icon name="arrow-down" color="#2ABED1" />
+                </div>
+              </template>
+            </van-popover>
+          </div>
         </div>
         <div
-          class="tip-toggle-search-mode-container"
           v-show="toggleBlurModeTip.show"
+          class="tip-toggle-search-mode-container"
         >
           <div>
-            如需查看更多相关信息,建议您将搜索模式切换为
+            如需查看更多相关信息,建议您切换至
             <div class="tip-action highlight-text">
-              “模糊搜索”
+              "模糊搜索"
               <AppIcon
                 class="search-mode-label-icon"
                 name="help1"
@@ -136,10 +155,41 @@
               >
               </AppIcon>
             </div>
-            按照当前条件共匹配到{{ toggleBlurModeTip.count }}条公告。
+            搜索模式 按照当前条件共匹配到{{ toggleBlurModeTip.count }}条公告。
+            <div class="search-model-switch" @click="doToggleSearchBlurMode">
+              <span class="search-model-switch-text">立即切换查看</span>
+              <AppIcon name="youbian" color="#2ABED1" />
+            </div>
           </div>
-          <button @click="doToggleSearchBlurMode">立即切换查看</button>
         </div>
+      </div>
+      <!-- 超前项目推荐 & 定制化分析报告 P611需求:将报告插到列表第一条数据后面位置 -->
+      <div
+        class="recommend-card-container"
+        :style="{ opacity: cardLoaded ? 'unset' : '0' }"
+      >
+        <RecommendCard
+          ref="recommendCardRef"
+          v-if="recommendInfo.show"
+          :key="recommendInfo.key"
+          v-model="recommendInfo.showContent"
+          :chart-data="recommendInfo.chart"
+          :brief-list="recommendInfo.brief"
+          :project-list="recommendInfo.project"
+          :keys="pageState.splitKeys"
+          @do-leave="saveState"
+        />
+      </div>
+      <van-list
+        v-show="pageState.listTabActive !== 'table'"
+        v-model="listState.loading"
+        :finished="listState.finished"
+        :offset="listState.offset"
+        :finished-text="finishedText"
+        @load="getList"
+        class="more-list calc-height-1px"
+        ref="vanList"
+      >
         <div class="list-wrapper" ref="listWrapper">
           <van-popup
             :style="popupHeight"
@@ -236,10 +286,11 @@
             <div
               v-else-if="isLogin"
               :key="[item.id, index].join('-')"
-              v-show="item.show"
+              :data-key="[item.id, index].join('-')"
               class="middle-list-container"
             >
               <AdSingle
+                v-show="item.show"
                 :class="item.className"
                 :ad="getContentAdID"
                 :showCloseIcon="true"
@@ -282,7 +333,10 @@
           >
         </AppEmpty>
       </van-list>
-      <div class="table-container" v-show="pageState.listTabActive === 'table'">
+      <div
+        class="table-container calc-height-1px"
+        v-show="pageState.listTabActive === 'table'"
+      >
         <div class="scroll" v-show="listState.list.length">
           <table class="table">
             <tr class="table-header">
@@ -313,7 +367,7 @@
               <!-- 项目名称 -->
               <td
                 v-html="
-                  replaceKeyword(
+                  highlightText(
                     item.projectName ? item.projectName : item.title,
                     pageState.splitKeys
                   )
@@ -365,11 +419,20 @@
             </tr>
           </table>
         </div>
-        <div class="to-look-more" v-show="listState.list.length > 20">
+        <div
+          class="to-look-more"
+          :class="{ 'ios-look-more': $envs.inIOS }"
+          v-show="listState.list.length > 20"
+        >
           <van-button plain size="small" type="primary" @click="dataExport"
             >查看更多</van-button
           >
         </div>
+        <!-- 占位解决ios回弹底部遮挡 -->
+        <div
+          v-show="listState.list.length > 20 && $envs.inIOS"
+          class="seat"
+        ></div>
         <AppEmpty v-show="listState.list.length === 0 && listState.finished">
           <div class="empty-text" v-html="emptyText"></div>
           <van-button
@@ -383,7 +446,7 @@
         </AppEmpty>
       </div>
     </div>
-    <div class="j-footer">
+    <div class="sub-position">
       <!-- 直接订阅 -->
       <div class="sub-this-keywords" v-show="subThisNoticeShow">
         <AppIcon
@@ -391,12 +454,15 @@
           name="close_touming"
           @click="pageState.toSubThisKeyNoticeBarShow = false"
         />
-        <div class="center text">如果您对以上结果满意可【直接订阅】。</div>
-        <div class="right action clickable" @click="toSubThisKey">直接订阅</div>
+        <div class="center text">如果您对以上结果满意可直接订阅</div>
+        <div class="right action clickable" @click="toSubThisKey">
+          去订阅
+          <AppIcon name="youbian" color="#2ABED1" />
+        </div>
       </div>
     </div>
     <!--    客服-->
-    <customer-corner  :scroll-status="scrollStatus" bottom-position="12%"/>
+    <customer-corner :scroll-status="scrollStatus" bottom-position="18%" />
     <SearchFilterHistoryDialog
       v-model="pageState.saveFilterDialog"
       :beforeClose="beforeFilterHistoryDialogClose"
@@ -417,7 +483,7 @@
 <script>
 import qs from 'qs'
 import { mapState, mapGetters, mapActions } from 'vuex'
-import { Cell, Tab, Tabs, List, Button, Tag, Popup } from 'vant'
+import { Cell, Tab, Tabs, List, Button, Tag, Popup, Popover, Icon } from 'vant'
 import bidStatusNode from '@/components/bid-update/BidUpdate'
 import AdSingle from '@/components/ad/Ad'
 import BiddingSearchFilters from '@/components/search/bidding/filters'
@@ -450,7 +516,8 @@ import {
   InfoTypeTransform,
   FilterHistoryViewModel2AjaxModel,
   FilterHistoryAjaxModel2ViewModel,
-  filterHistoryNotEmptyFormat
+  filterHistoryNotEmptyFormat,
+  deepCompareInfoType
 } from '@/utils'
 import {
   getBiddingSearchList,
@@ -479,6 +546,8 @@ export default {
     [List.name]: List,
     [Tag.name]: Tag,
     [Popup.name]: Popup,
+    [Popover.name]: Popover,
+    [Icon.name]: Icon,
     BiddingSearchFilters,
     SearchFilterHistoryDialog,
     OneKeySubscribeDialog,
@@ -554,12 +623,12 @@ export default {
         ],
         tabList: [
           {
-            title: '精简列表',
+            title: '精简',
             cardType: 'simplify',
             name: 'list'
           },
           {
-            title: '详细列表',
+            title: '详细',
             name: 'detailedList',
             cardType: 'detailed',
             needPower: true
@@ -592,6 +661,30 @@ export default {
           buyerList: [],
           winnerList: [],
           agencyList: []
+        },
+        noChangeDefaultFilterState: {
+          moreKeywordsMode: {},
+          searchMode: ['0'],
+          scope: ['title', 'content'],
+          industry: {},
+          area: {},
+          priceCheckbox: [''],
+          price: {
+            start: '',
+            end: ''
+          },
+          dateTime: {
+            exact: 'thisyear'
+          },
+          infoType: [],
+          buyerClass: [],
+          fileExists: ['0'],
+          winnerConcat: [''],
+          buyerConcat: [''],
+          notKey: [],
+          buyerList: [],
+          winnerList: [],
+          agencyList: []
         }
       },
       // 发送请求整理的数据
@@ -686,7 +779,11 @@ export default {
         show: false,
         count: ''
       },
-      scrollStatus: true
+      scrollStatus: true,
+      showPopover: false,
+      popoverActions: [{ text: '精简' }, { text: '详细' }, { text: '表格' }],
+      lastScroll: 0,
+      cardLoaded: false
     }
   },
   computed: {
@@ -878,6 +975,31 @@ export default {
         count: this.toggleSearchBlurData.count
       }
       return result
+    },
+    listTabActiveText() {
+      const { listTabActive } = this.pageState
+      if (listTabActive === 'list') {
+        return '精简'
+      } else if (listTabActive === 'detailedList') {
+        return '详细'
+      } else if (listTabActive === 'table') {
+        return '表格'
+      } else {
+        return '精简'
+      }
+    },
+    calcFilterText() {
+      const params = this.getSaveFilterToHistoryParams()
+      const { label } = this.formatFilterItems(params, 'text')
+      return label
+    },
+    // 默认筛选条件(不可更改赋值)用于清空操作,原defaultFilterState会被缓存赋值(版本需求)
+    noChangeDefaultFilterState() {
+      const { noChangeDefaultFilterState } = this.conf
+      if (!this.isFree) {
+        noChangeDefaultFilterState.dateTime.exact = 'fiveyear'
+      }
+      return noChangeDefaultFilterState
     }
   },
   provide() {
@@ -904,8 +1026,13 @@ export default {
               '推荐使用电脑浏览器访问剑鱼标讯网站\njianyu360.cn查看数据表格,体验更佳。'
           })
         }
-      } else {
-        this.$toast.clear()
+      }
+      this.moveRecommendCard(n)
+    },
+    searchList(list) {
+      if (list && list.length && this.pageState.listTabActive === 'list') {
+        // 市场分析报告插到第一条数据后面位置
+        this.moveRecommendCard('list')
       }
     }
   },
@@ -960,11 +1087,13 @@ export default {
     this.calcDropdownMenuMaxHeight()
     this.$nextTick(() => {
       const scrollWrap = this.$refs.listContainer
-      scrollWrap.addEventListener('scroll', throttle(this.scrollWrapFn, 500))
+      scrollWrap.addEventListener('scroll', throttle(this.scrollWrapFn, 300))
     })
+    this.getWhiteListInfo()
   },
   methods: {
     ...mapActions('search', ['setHistory']),
+    ...mapActions('user', ['getWhiteListInfo']),
     formatMoney,
     dateFormatter,
     replaceKeyword,
@@ -1057,11 +1186,19 @@ export default {
         const filterDOM = searchFilters?.$el
         const domTop =
           filterDOM.getBoundingClientRect().top + filterDOM.clientHeight
+        console.log(
+          domTop + h5Offset,
+          filterDOM.getBoundingClientRect().top,
+          filterDOM.clientHeight
+        )
         this.conf.maxHeight = `calc(100vh - ${domTop + h5Offset}px)`
       }
     },
     initDefaultFilterState() {
-      Object.assign(this.filters, JSON.parse(JSON.stringify(this.defaultFilterState)))
+      Object.assign(
+        this.filters,
+        JSON.parse(JSON.stringify(this.defaultFilterState))
+      )
       this.$nextTick(() => {
         this.filters.keywords = this.topSearch.input
       })
@@ -1200,6 +1337,12 @@ export default {
       }
       if (filters.price) {
         const key = 'price'
+        if (!filters[key].start) {
+          filters[key].start = ''
+        }
+        if (!filters[key].end) {
+          filters[key].end = ''
+        }
         if (filters[key].start || filters[key].end) {
           this.filters.priceCheckbox = ['custom']
         }
@@ -2052,16 +2195,31 @@ export default {
       //    --> 新用户-未选择区域-订阅页面
       //           --> 选择区域-关键词列表
       // const { inWX } = this.$envs
+      if (!this.topSearch.input) {
+        return this.$toast('请先输入关键词')
+      }
       const superUser = this.isSuper || this.isMember
       if (superUser) {
+        const { moreKeywordsMode } = this.filters
+        const { tags, wordsMode } = moreKeywordsMode
+        // 订阅的关键词 = 主关键词 + 多关键词
+        let formatKeyword = ''
+        if (tags && tags.length) {
+          formatKeyword = this.filters.keywords + ' ' + tags.join(' ')
+        } else {
+          formatKeyword = this.filters.keywords
+        }
         const params = {
           pageType: 'keyWords',
           actionType: 'directSubKWS',
-          kws_name: this.filters.keywords,
-          vSwitch: this.vSwitch
+          kws_name: formatKeyword,
+          vSwitch: this.vSwitch,
+          match_way: wordsMode
         }
+        const loading = this.$toast.loading({ duration: 0 })
         try {
           const { flag } = await setUserSubInfo(params)
+          loading.clear()
           if (flag === 'y') {
             this.saveState()
             openAppOrWxPage(LINKS.关键词列表)
@@ -2086,10 +2244,26 @@ export default {
           if (keyLength >= 10) {
             return this.$toast('您已经超过订阅关键字上限')
           }
+          // 设置完区域后跳至关键词订阅页面,区域设置成功后关键词要同步设置(要携带参数过去)
+          const { moreKeywordsMode } = this.filters
+          const { tags, wordsMode } = moreKeywordsMode
+          // 订阅的关键词 = 主关键词 + 多关键词
+          let formatKeyword = ''
+          if (tags && tags.length) {
+            formatKeyword = this.filters.keywords + ' ' + tags.join(' ')
+          } else {
+            formatKeyword = this.filters.keywords
+          }
           loading.clear()
           if (!isSelectArea) {
             if (isUpgrade) {
-              this.toSetArea()
+              this.toSetArea({
+                query: {
+                  url: LINKS.关键词列表[this.$env.platform],
+                  keywords: formatKeyword,
+                  wordsMode
+                }
+              })
             } else {
               // 提示去升级
               await this.$dialog.confirm({
@@ -2098,7 +2272,13 @@ export default {
                 className: 'j-confirm-dialog',
                 confirmButtonText: '立即升级'
               })
-              this.toSetArea()
+              this.toSetArea({
+                query: {
+                  url: LINKS.关键词列表[this.$env.platform],
+                  keywords: formatKeyword,
+                  wordsMode
+                }
+              })
               return
             }
           } else {
@@ -2110,9 +2290,19 @@ export default {
       }
     },
     async toSetFreeKey() {
+      const { moreKeywordsMode } = this.filters
+      const { tags, wordsMode } = moreKeywordsMode
+      // 订阅的关键词 = 主关键词 + 多关键词
+      let formatKeyword = ''
+      if (tags && tags.length) {
+        formatKeyword = this.filters.keywords + ' ' + tags.join(' ')
+      } else {
+        formatKeyword = this.filters.keywords
+      }
       const params = {
-        keys: this.filters.keywords,
-        reqType: 'subscribe'
+        keys: formatKeyword,
+        reqType: 'subscribe',
+        match_way: wordsMode
       }
       const { area } = this.pageState.freeSubInfo
       try {
@@ -2133,9 +2323,9 @@ export default {
       this.saveState()
       this.$leaveInfo.toLeaveInfoPage({ source })
     },
-    toSetArea() {
+    toSetArea(query = {}) {
       this.saveState()
-      openAppOrWxPage(LINKS.省份订阅包设置省份)
+      openAppOrWxPage(LINKS.省份订阅包设置省份, query)
     },
     // 去用户反馈页面
     feedback() {
@@ -2193,10 +2383,17 @@ export default {
     // 保存筛选条件
     async saveFilterToHistory() {
       const params = this.getSaveFilterToHistoryParams()
-
-      // if (!params.searchvalue) {
-      //   return this.$toast('请先输入关键词')
-      // }
+      console.log(params, 'params')
+      // 如未输入关键词(包含顶部搜索框及更多筛选条件设置的多关键词、采购单位、中标单位和招标代理机构)则toast提示“请输入关键词”
+      if (
+        !params.searchvalue &&
+        !params.additionalWords &&
+        !params.buyer &&
+        !params.winner &&
+        !params.agency
+      ) {
+        return this.$toast('请先输入关键词')
+      }
       const { savedFilterListMaxCount: maxCount } = this.conf
       if (this.savedFilterListCount >= maxCount) {
         return this.$toast(`对不起,最多可保存${maxCount}个筛选条件。`)
@@ -2261,7 +2458,7 @@ export default {
         done()
       }
     },
-    formatFilterItems(item) {
+    formatFilterItems(item, type = 'dialog') {
       item.scope = item.selectType
       item.infotype = item.subtype
       const formatted = FilterHistoryAjaxModel2ViewModel.formatAll(item)
@@ -2282,12 +2479,43 @@ export default {
         )
       }
       const formattedList = filterHistoryNotEmptyFormat(formattedItem)
-      const { keywords, additionalWords, wordsModeText } = formatted
+      const { keywords, additionalWords, wordsModeText, searchModeText } =
+        formatted
       const keywordsText = keywords.join(' ')
       const allKeywordsArr = [keywordsText]
         .concat(additionalWords)
         .filter((k) => !!k)
       const additionalWordsText = additionalWords.join(' ')
+      const { searchGroup } = this.$route.query
+      /**
+       * 1.从招标采购搜索首页,点击了“超前项目”、“招标预告”、“招标公告”、“招标结果”,则已选结果此处展示点击的类型
+       * 2.输入框有关键词 已选结果才展示搜索范围和搜索模式
+       * */
+      let labelList = formattedList
+        .filter((v) => {
+          if (v.label.includes('信息类型')) {
+            const isChecked = deepCompareInfoType(v.text)
+            v.text = type === 'text' && isChecked ? '' : v.text
+          }
+          if (this.topSearch.input) {
+            return v && v.text
+          } else {
+            return !v.label.includes('搜索范围') && v.text
+          }
+        })
+        .map((item) => item.text)
+      if (searchModeText && this.topSearch.input) {
+        labelList = [searchModeText].concat(labelList)
+      }
+      // console.log(formattedList, 'formattedList')
+      const isHaveInfoType = formattedList.some((v) =>
+        v.label.includes('信息类型')
+      )
+      if (searchGroup > 0 && !isHaveInfoType) {
+        labelList = labelList.concat(this.activeSearchGroupInfo.title)
+      }
+      let label = ''
+      label += labelList.join(',')
       return {
         ...formattedItem,
         keywordsText: keywords.join(' '),
@@ -2295,7 +2523,8 @@ export default {
         allKeywordsText: allKeywordsArr.join(','), // 此处用逗号分割
         allKeywordsArr,
         wordsModeText: additionalWordsText ? wordsModeText : '',
-        formattedList
+        formattedList,
+        label
       }
     },
     // 检查一键订阅是否打开(仅免费用户检查)
@@ -2536,13 +2765,28 @@ export default {
     scrollWrapFn(e) {
       const scrollDOM = e.target
       const scrollTop = scrollDOM.scrollTop
-      this.recommendInfo.showContent = false
+      const offsetHeight =
+        document.querySelector('.j-header.linear-main-bg').offsetHeight || 90
+      if (scrollTop < offsetHeight) {
+        window.clearTimeout(this._timer)
+        this._timer = setTimeout(() => {
+          this.setScrollWrapState(e)
+        }, 400)
+      } else {
+        this.setScrollWrapState(e)
+      }
+    },
+    setScrollWrapState(e) {
+      const scrollDOM = e.target
+      const scrollTop = scrollDOM.scrollTop
+      // this.recommendInfo.showContent = false
 
-      if (scrollTop >= this.conf.tabSwitchShowOffset) {
+      if (scrollTop > this.lastScroll) {
         this.pageState.tabSwitchShow = false
       } else {
         this.pageState.tabSwitchShow = true
       }
+      this.lastScroll = scrollTop
       this.scrollStatus = scrollTop < 60
     },
     // 定制化分析报告&&超前项目推荐数据请求
@@ -2589,6 +2833,64 @@ export default {
           }
         }
       } catch (error) {}
+    },
+    onListTabClick(name) {
+      const isPass = this.beforeTabActiveChange(name)
+      if (isPass) {
+        this.pageState.listTabActive = name
+        this.onListTabChange(name)
+        this.showPopover = false
+      }
+    },
+    // 清空已选筛选条件,恢复到默认值
+    onClearFilter() {
+      const noChangeDefaultFilterState = this.noChangeDefaultFilterState
+      this.filters.infoType = noChangeDefaultFilterState.infoType
+      this.pageState.searchGroup = '0'
+      for (const key in noChangeDefaultFilterState) {
+        this.$set(this.filters, key, noChangeDefaultFilterState[key])
+      }
+      this.doSearch()
+    },
+    highlightText(value, keyStr) {
+      return replaceKeyword(
+        value,
+        keyStr,
+        '<span class="highlight-text-orange-bd">' + keyStr + '</span>'
+      )
+    },
+    moveRecommendCard(n) {
+      if (n === 'table') {
+        // 市场分析报告插到表格头部位置
+        this.$nextTick(() => {
+          const recommend = document.querySelector('.recommend-card-container')
+          const scroll = document.querySelector('.table-container .scroll')
+          const recommendChild = document.querySelector('.recommend-bg')
+          if (recommend && scroll) {
+            const parentNode = scroll.parentNode
+            parentNode.insertBefore(recommend, scroll)
+            this.cardLoaded = true
+            if (recommendChild) {
+              recommendChild.style.margin = '0 8px'
+            }
+          }
+        })
+      } else {
+        // 市场分析报告插到第一条数据后面位置
+        this.$nextTick(() => {
+          const recommend = document.querySelector('.recommend-card-container')
+          const cellList = document.querySelectorAll('.project-cell')
+          const recommendChild = document.querySelector('.recommend-bg')
+          if (recommend && cellList[0]) {
+            const parentNode = cellList[0].parentNode
+            parentNode.insertBefore(recommend, cellList[0].nextSibling)
+            this.cardLoaded = true
+            if (recommendChild) {
+              recommendChild.style.margin = '8px 8px 0'
+            }
+          }
+        })
+      }
     }
   }
 }
@@ -2613,27 +2915,22 @@ export default {
 <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;
+  margin-top: 8px;
+  //background: linear-gradient(180deg, #e8ffff 0%, #ffffff 100%);
   color: #5f5e64;
-  font-size: 13px;
-  line-height: 20px;
+  font-size: 12px;
+  line-height: 18px;
   .tip-action {
     display: inline-flex;
     align-items: center;
   }
-  button {
-    margin-top: 12px;
-    background: #2abed1;
-    padding: 5px 12px;
-    border-radius: 4px;
-    color: #f7f9fa;
+  .search-model-switch {
+    display: inline-flex;
+    align-items: center;
+    &-text {
+      color: $color_main;
+      text-decoration: underline;
+    }
   }
 }
 .search-result-bidding {
@@ -2707,11 +3004,19 @@ export default {
     white-space: nowrap;
   }
 }
+.data-export {
+  margin-left: 10px;
+  line-height: 20px;
+  .text {
+    font-size: 11px;
+  }
+}
 .tab-switch {
   display: flex;
   align-items: center;
   justify-content: space-between;
   padding: 2px 16px;
+  margin-top: -1px;
   padding-left: 8px;
   background: #fff;
   .tab-right {
@@ -2734,18 +3039,57 @@ export default {
 }
 
 .tab-search-info {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  padding: 8px 16px;
-  line-height: 30px;
+  position: relative;
+  margin: 8px;
+  padding: 8px;
+  line-height: 20px;
+  border-radius: 8px;
+  border: 1px solid transparent;
+  background-clip: padding-box, border-box;
+  background-image: linear-gradient(#e8ffff 40%, #ffffff 100%),
+    linear-gradient(to right, #2abed1, #4de4f84c, #2abed1);
+  background-origin: padding-box, border-box;
   .tab-right {
     display: flex;
     align-items: center;
   }
+  ::v-deep {
+    .van-popover__arrow {
+      display: none;
+    }
+    .tab-column {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      width: 88px;
+      &-item {
+        width: 100%;
+        height: 44px;
+        font-size: 14px;
+        line-height: 44px;
+        text-align: center;
+        letter-spacing: 2px;
+        &:not(:last-child) {
+          border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+        }
+        &.active {
+          padding-right: 10px;
+          color: $color_main;
+          background: url(@/assets/image/icon/icon-check.png) no-repeat 58px
+            center;
+          background-size: 16px 16px;
+        }
+      }
+    }
+    .selected-tab-content {
+      font-size: 11px;
+      line-height: 16px;
+    }
+  }
 }
 .search-total-count {
-  font-size: 14px;
+  font-size: 13px;
+  font-weight: 700;
 }
 
 .intercept-tip-container {
@@ -2761,9 +3105,16 @@ export default {
 }
 
 .list-item {
+  margin: 0 8px;
+  border-radius: 12px;
   &:not(:first-of-type) {
     margin-top: 8px;
   }
+  .icon-star-streak,
+  .icon-star-fill {
+    width: 18px;
+    height: 18px;
+  }
 }
 .middle-list-container {
   + .list-item {
@@ -2793,9 +3144,12 @@ export default {
 }
 .table {
   min-width: 1000px;
-  margin: 16px;
+  margin: 8px;
   font-size: 14px;
+  background: #fff;
+  border-radius: 12px;
   border-collapse: collapse;
+  overflow: hidden;
   tr {
     td {
       padding: 6px 12px;
@@ -2829,7 +3183,10 @@ export default {
   }
   .table-header {
     font-size: 13px;
-    background-color: $gray_1;
+    background-color: #fff;
+    td {
+      color: #9b9ca3;
+    }
   }
   .table-content-tr {
     &.visited {
@@ -2867,34 +3224,47 @@ export default {
     rgba(255, 255, 255, 1),
     rgba(255, 255, 255, 1)
   );
+  &.ios-look-more {
+    height: 180px;
+    padding-bottom: 50px;
+  }
+}
+.seat {
+  height: 60px;
+  background: #fff;
 }
 .sub-this-keywords {
   display: flex;
   align-items: center;
   justify-content: space-between;
-  padding: 8px 16px;
-  height: 46px;
-  color: #fff;
-  background-color: #37c6da;
+  padding: 10px 12px;
+  height: 40px;
+  color: #171826;
+  border: 0.5px solid transparent;
+  background-clip: padding-box, border-box;
+  background-image: linear-gradient(#e8ffff 40%, #ffffff 100%),
+    linear-gradient(to right, #2abed1 10%, #4de4f84c 30%, #2abed1);
+  background-origin: padding-box, border-box;
+  border-radius: 8px;
   .left {
-    font-size: 22px;
+    font-size: 20px;
+    color: #87dfea;
   }
   .center {
     margin: 0 4px;
     flex: 1;
   }
   .text {
-    font-size: 13px;
+    font-size: 12px;
+    line-height: 18px;
   }
   .action {
     display: flex;
     align-items: center;
     justify-content: center;
-    padding: 0 6px;
-    font-size: 13px;
-    line-height: 26px;
-    border-radius: 16px;
-    border: 1px solid $white;
+    font-size: 12px;
+    line-height: 18px;
+    color: $color_main;
   }
 }
 .right-event {
@@ -2928,4 +3298,70 @@ export default {
     opacity: 0.5;
   }
 }
+.recommend-card-container,
+.recommend-card-table {
+  ::v-deep {
+    .recommend-bg {
+      padding-bottom: 0;
+      margin: 8px 8px 0;
+      border: 1px solid rgba(0, 0, 0, 0.05);
+      border-radius: 12px;
+      overflow: hidden;
+    }
+    .van-cell {
+      padding: 8px 12px;
+      background: linear-gradient(#ffffff 10%, #f5f5f5 100%);
+    }
+  }
+}
+.recommend-card-table {
+  ::v-deep {
+    .recommend-bg {
+      margin-top: 0;
+    }
+  }
+}
+.tab-saved {
+  padding: 2px 12px 8px;
+  background: #fff;
+  &-left {
+    flex: 1;
+    margin-right: 4px;
+    &-label {
+      color: #171826;
+      font-size: 13px;
+      line-height: 20px;
+      font-weight: bold;
+    }
+    &-value {
+      font-size: 12px;
+      line-height: 18px;
+      color: #5f5e64;
+    }
+  }
+  &-right {
+    flex-shrink: 0;
+    color: $color_main;
+    font-size: 12px;
+    line-height: 18px;
+    .clear-action {
+      margin-right: 10px;
+      padding: 1px 4px;
+    }
+    .save-action {
+      padding: 1px 4px;
+      border-radius: 4px;
+      border: 1px solid $color_main;
+    }
+  }
+}
+.sub-position {
+  position: absolute;
+  bottom: 40px;
+  left: 12px;
+  right: 12px;
+}
+.customer-corner {
+  z-index: 10;
+}
 </style>

+ 17 - 11
apps/mobile/src/views/tabbar/Home.vue

@@ -4,7 +4,7 @@
     @scroll="onScroll"
     @click.capture="doSave"
     ref="home-page"
-    :class="{ 'app-header-top': appHeaderTop}"
+    :class="{ 'app-header-top': appHeaderTop }"
   >
     <!-- 头部广告位 -->
     <div class="header-exposure" v-if="isLogin"></div>
@@ -46,12 +46,19 @@
       <!-- 消息 -->
       <message-card></message-card>
       <!-- 最新标讯 -->
-      <home-list ref="list" @bottomSetTip="bottomSetTip" :show-set-tip="showSetTip"></home-list>
+      <home-list
+        ref="list"
+        @bottomSetTip="bottomSetTip"
+        :show-set-tip="showSetTip"
+      ></home-list>
     </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 :scroll-status="sideStatus" :bottom-position="hasBottomSetTip ? '16%' :'12%'"/>
+    <customer-corner
+      :scroll-status="sideStatus"
+      :bottom-position="hasBottomSetTip ? '16%' : '12%'"
+    />
     <!-- 弹窗广告位 -->
     <AdPopScreen
       v-if="AD.full.pic"
@@ -434,7 +441,7 @@ export default {
       const scrollTop = e.target.scrollTop
       this.sideStatus = scrollTop < 60
       // P599需求,滚动到最新咨询展示
-      if(this.$refs.list) {
+      if (this.$refs.list) {
         const listRect = this.$refs.list.$el.getBoundingClientRect() || {}
         const listTop = listRect.top
         this.showSetTip = listTop <= scrollTop
@@ -605,7 +612,7 @@ export default {
       }
     },
     // 有无订阅关键词设置提示,影响侧边广告、客服距离底部高度
-    bottomSetTip (show) {
+    bottomSetTip(show) {
       this.hasBottomSetTip = show
     }
   }
@@ -638,8 +645,7 @@ export default {
   }
 
   .hot-key-wrapper {
-    padding: 0 8px;
-    padding-bottom: 12px;
+    padding: 0 16px 8px;
   }
 
   .home-content-container {
@@ -653,7 +659,7 @@ export default {
     box-shadow: 0px -4px 16px 0px #081f2614;
   }
   .message-bg {
-    padding-bottom: 0;
+    padding: 8px 8px 0;
   }
 
   .van-sticky--fixed,
@@ -681,7 +687,7 @@ export default {
       display: flex;
       flex-direction: row;
       align-items: center;
-      height: 40px;
+      height: 36px;
       padding: 0 12px;
       background: #ffffff;
       transition: background-color 0.2s;
@@ -703,7 +709,7 @@ export default {
     left: 0;
     width: 100%;
     min-height: 240px;
-    background: linear-gradient(180deg, #00aee6 0%, #05b6cd 38%, #87efea 100%);
+    background: linear-gradient(180deg, #00aee6 0%, #05b6cd 38%, #87dfea 100%);
     img {
       width: 100%;
       max-width: 100%;

+ 23 - 22
apps/mobile/vite.config.js

@@ -1,4 +1,4 @@
-import { resolve } from 'path'
+import { resolve } from 'node:path'
 
 import UnoCSS from 'unocss/vite'
 import viteCompression from 'vite-plugin-compression'
@@ -19,21 +19,21 @@ function getExternals(isDev) {
   }
 
   return {
-    vue: 'Vue',
+    'vue': 'Vue',
     'vue-router': 'VueRouter',
-    vuex: 'Vuex',
-    axios: 'axios',
-    echarts: 'echarts',
-    vant: 'vant',
-    lodash: '_',
-    dayjs: 'dayjs',
+    'vuex': 'Vuex',
+    'axios': 'axios',
+    'echarts': 'echarts',
+    'vant': 'vant',
+    'lodash': '_',
+    'dayjs': 'dayjs',
     'js-cookie': 'Cookies',
-    jquery: '$',
+    'jquery': '$',
     'lottie-web': 'lottie'
   }
 }
 
-export default defineConfig(({ mode,command }) => {
+export default defineConfig(({ mode, command }) => {
   const env = loadEnv(mode, process.cwd())
   return {
     base: env.VITE_APP_BASE_PUBLIC,
@@ -84,13 +84,14 @@ export default defineConfig(({ mode,command }) => {
           vcsRemote: env.VITE_APP_GIT_BRANCH
         },
         sourcemaps: {
-          filesToDeleteAfterUpload: ["../../dist/jy_mobile/**/*.js.map"]
+          filesToDeleteAfterUpload: ['../../dist/jy_mobile/**/*.js.map']
         },
         url: 'https://jysentry.jydev.jianyu360.cn',
-        org: "jianyu",
-        project: "jy-mobile",
-        authToken: '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',
-      }),
+        org: 'jianyu',
+        project: 'jy-mobile',
+        authToken:
+          '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'
+      })
     ],
     resolve: {
       alias: [
@@ -126,21 +127,21 @@ export default defineConfig(({ mode,command }) => {
       proxy: {
         // 接口解密iframe
         '^/page_decrypt': {
-          target: 'https://jybx3-webtest.jydev.jianyu360.com',
+          target: 'https://jybx-webtest.jydev.jianyu360.com',
           changeOrigin: true
         },
         '/jyapi': {
-          target: 'https://app5-jytest.jydev.jianyu360.com',
+          target: 'https://app3-jytest.jydev.jianyu360.com',
           changeOrigin: true,
-          rewrite: (path) => path.replace(/^\/jyapi/, '')
+          rewrite: path => path.replace(/^\/jyapi/, '')
         },
         '/api': {
-          target: 'https://app5-jytest.jydev.jianyu360.com',
+          target: 'https://app3-jytest.jydev.jianyu360.com',
           changeOrigin: true,
-          rewrite: (path) => path.replace(/^\/api/, '')
+          rewrite: path => path.replace(/^\/api/, '')
         },
-        '/commonFunctions': 'https://jybx3-webtest.jydev.jianyu360.com',
-        '/common-module': 'https://jybx3-webtest.jydev.jianyu360.com'
+        '/commonFunctions': 'https://jybx-webtest.jydev.jianyu360.com',
+        '/common-module': 'https://jybx-webtest.jydev.jianyu360.com'
       }
     }
   }

+ 2 - 2
data/data-models/modules/article/model/content.js

@@ -74,7 +74,7 @@ class ContentModel extends BaseModel {
       highlightKeys = formatted.content.highlightKeys
     }
     highlightKeys.forEach((key) => {
-      title = replaceKeywordWithRichText(title, key, '<span class="keyword highlight-text">$1</span>')
+      title = replaceKeywordWithRichText(title, key, '<span class="keyword highlight-text-orange-bd">$1</span>')
     })
     return title
   }
@@ -131,7 +131,7 @@ class ContentModel extends BaseModel {
       highlightKeys = formatted.content.highlightKeys
     }
     highlightKeys.forEach((key) => {
-      content = replaceKeywordWithRichText(content, key, '<span class="keyword highlight-text">$1</span>')
+      content = replaceKeywordWithRichText(content, key, '<span class="keyword highlight-text-orange-bd">$1</span>')
     })
 
     // 将多个连续的br替换成一个

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.