Browse Source

Merge branch 'feature/v1.0.36' of https://jygit.jydev.jianyu360.cn/jianyu/web into feature/v1.0.36

# Conflicts:
#	apps/bigmember_pc/src/views/search/bidding/model/index.js
zhangyuhan 1 year ago
parent
commit
5404e643a3

+ 1 - 0
apps/bigmember_pc/src/api/modules/index.js

@@ -29,3 +29,4 @@ export * from './crmApplication'
 export * from './pay'
 export * from './message'
 export * from './business'
+export * from './search'

+ 10 - 0
apps/bigmember_pc/src/api/modules/search.js

@@ -0,0 +1,10 @@
+import request from '@/api'
+
+// 检查已存筛选是否pass
+export function checkBiddingFilterPass(data) {
+  return request({
+    url: '/jyapi/jybx/base/checkSearchScreen',
+    method: 'POST',
+    data: data
+  })
+}

+ 10 - 16
apps/bigmember_pc/src/components/filter-items/KeywordTagsSelector.vue

@@ -7,7 +7,7 @@
   >
     <KeywordTagsSelectorContent
       slot="empty"
-      :list='list'
+      :list='value'
       :placeholder='inputPlaceholder'
       :max-tip='maxTip'
       :disabled='disabled'
@@ -20,15 +20,12 @@
 
 <script>
 import  Layout from '@/components/filter-items/Layout.vue'
-import { Dropdown, DropdownMenu} from 'element-ui'
 import KeywordTagsSelectorContent from './KeywordTagsSelectorContent'
 
 export default {
   components: {
-    [Dropdown.name]: Dropdown,
-    [DropdownMenu.name]: DropdownMenu,
-    KeywordTagsSelectorContent,
-    Layout
+    Layout,
+    KeywordTagsSelectorContent
   },
   props: {
     type: {
@@ -56,12 +53,6 @@ export default {
       type: Number,
       default: 15
     },
-    list: {
-      type: Array,
-      default: () => {
-        return []
-      }
-    },
     // 数组最大长度
     maxListLength: {
       type: Number,
@@ -77,19 +68,22 @@ export default {
       default: () => []
     }
   },
+  model: {
+    prop: 'value',
+    event: 'change'
+  },
   data () {
-    return {
-    }
+    return {}
   },
   computed: {
     computedVal () {
-      return  this.list.length ? `${this.placeholder} ${this.list.length || 0}/${this.maxListLength}` : ''
+      return  this.value.length ? `${this.placeholder} ${this.value.length || 0}/${this.maxListLength}` : ''
     }
   },
   created() {},
   methods: {
     keywordTagsChange (list) {
-      this.$emit('onChange', list)
+      this.$emit('change', list)
     }
   }
 }

+ 1 - 1
apps/bigmember_pc/src/components/toast/index.js

@@ -5,7 +5,7 @@ const ToastConstructor = vue.extend(toastComponent)
 let ToastHistory = {}
 
 // 定义弹出组件的函数 接收2个参数, 要显示的文本 和 显示时间
-function showToast(text, duration = 2000) {
+export function showToast(text, duration = 2000) {
   if (ToastHistory.el) {
     ToastHistory.destory()
   }

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

@@ -0,0 +1,379 @@
+import dayjs from 'dayjs'
+
+
+
+/**
+ * 整理已存筛选数据,去除空数据
+ * 需要和 FilterHistoryAjaxModel2ViewModel.formatAll 配合使用
+ */
+export function filterHistoryNotEmptyFormat(formatted) {
+  const {
+    searchGroup,
+    scopeText,
+    industryText,
+    AreaCityText,
+    priceText,
+    publishTimeText,
+    buyerClassText,
+    winnerConcatText,
+    buyerConcatText,
+    fileExists,
+    notKey,
+    buyerList,
+    winnerList,
+    agencyList
+  } = formatted
+  let { infoTypeText } = formatted
+
+  const formattedList = []
+  if (Array.isArray(scopeText) && scopeText.length) {
+    formattedList.push({
+      label: '搜索范围:',
+      text: scopeText.join('/')
+    })
+  }
+  if (Array.isArray(industryText) && industryText.length) {
+    formattedList.push({
+      label: '行业:',
+      text: industryText.join('/')
+    })
+  }
+  if (Array.isArray(AreaCityText) && AreaCityText.length) {
+    formattedList.push({
+      label: '地区:',
+      text: AreaCityText.join('/')
+    })
+  }
+  if (priceText) {
+    formattedList.push({
+      label: '金额:',
+      text: priceText
+    })
+  }
+  if (publishTimeText) {
+    formattedList.push({
+      label: '时间:',
+      text: publishTimeText
+    })
+  }
+
+  /**
+   * searchGroup === '1' 表示为非超前项目
+   * searchGroup === '2' 表示为超前项目
+   * 如果此时信息类型为空。则显示其所有类型的文字,而非"全部"两个字
+   */
+  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') {
+      // 超前项目
+      infoTypeText = infoTypeAdvancedList
+        .map((i) => {
+          if (i && i.value && i.value.includes('拟建')) {
+            return i.name
+          } else {
+            return i.value
+          }
+        })
+        .filter((i) => !!i)
+    }
+  }
+  if (Array.isArray(infoTypeText) && infoTypeText.length) {
+    formattedList.push({
+      label: '信息类型:',
+      text: infoTypeText.join('/')
+    })
+  }
+  if (fileExists && Array.isArray(fileExists)) {
+    // 附件选择全部时候,则不显示
+    const fileState = fileExists.join('')
+    if (fileState !== '0') {
+      const textInfo = biddingSearchFileExists.find((item) => {
+        return fileState === item.key
+      })
+      if (textInfo) {
+        formattedList.push({
+          label: '附件:',
+          text: textInfo.label
+        })
+      }
+    }
+  }
+  if (buyerClassText) {
+    formattedList.push({
+      label: '采购单位类型:',
+      text: buyerClassText.join('/')
+    })
+  }
+  if (winnerConcatText) {
+    formattedList.push({
+      label: '中标企业联系方式:',
+      text: winnerConcatText.join('/')
+    })
+  }
+  if (buyerConcatText) {
+    formattedList.push({
+      label: '采购单位联系方式:',
+      text: buyerConcatText.join('/')
+    })
+  }
+  if (notKey) {
+    formattedList.push({
+      label: '排除词:',
+      text: notKey.split(',').join(' ')
+    })
+  }
+  if (buyerList) {
+    formattedList.push({
+      label: '采购单位:',
+      text: buyerList.split(',').join(' ')
+    })
+  }
+  if (winnerList) {
+    formattedList.push({
+      label: '中标企业:',
+      text: winnerList.split(',').join(' ')
+    })
+  }
+  if (agencyList) {
+    formattedList.push({
+      label: '代理机构:',
+      text: agencyList.split(',').join(' ')
+    })
+  }
+  return formattedList
+}
+
+
+/**
+ * 保存筛选条件
+ * 将组件初始化filter,格式成保存筛选条件接口需要数据格式
+ * 前端标准数据转接口中的数据
+ */
+export class FilterHistoryViewModel2AjaxModel {
+  static formatAll(map) {
+    // 搜索范围整理
+    const selectType = this.formatScope(map.selectType)
+    // 行业整理
+    const industry = this.formatIndustry(map.industry)
+    // 地区整理
+    // const { area, city } = this.formatAreaCity(map.area)
+    // 金额筛选整理
+    const price = this.formatPrice(map.price)
+    // 时间筛选整理
+    // const publishTime = this.formatTime(map.publishTime)
+    // 信息类型
+    const subtype = this.formatInfoType(map.subtype)
+    // 采购单位
+    const { buyerClass } = this.formatBuyerClass(map.buyerclass)
+    // 包含关系、多个关键词
+    const { additionalWords, wordsMode } = this.formatSelectMoreKey(map.selectMoreKey, map.additionalWords, map.wordsMode)
+
+    const formatted = {
+      searchvalue: map.input,
+      selectType,
+      industry,
+      minprice: map.minprice,
+      maxprice: map.maxprice,
+      publishtime: map.publishtime, // 发布时间
+      subtype,   // 信息类型
+      buyerclass: buyerClass, // 采购单位
+      buyertel: map.buyertel,  // 采购单位联系方式
+      winnertel: map.winnertel,  // 中标企业联系方式
+      notkey: map.notkey ? map.notkey.join(',') : '', // 排除词
+      buyer: map.buyer ? map.buyer.join(',') : '',  // 采购单位
+      winner: map.winner ? map.winner.join(',') : '', // 中标企业
+      agency: map.agency ? map.agency.join(',') : '', // 招标代理机构
+      fileExists: map.fileExists, // 附件
+      regionMap: map.regionMap, // 地区
+      searchGroup: map.searchGroup, // 搜索分组:默认0:全部;1:招标采购公告;2:超前项目
+      searchMode: Number(map.searchMode),  // 搜索模式:0:精准搜索;1:模糊搜索
+      wordsMode: wordsMode, // 搜索关键词模式;默认0:包含所有,1:包含任意
+      additionalWords: additionalWords, //关键词:附加关键词(副:五组,每组最多15个字符)
+      dateTime:  map.publishtime, // 标讯搜索恢复数据可能要用到?
+    }
+
+    // 删去undefined/null的项
+    for (const key in formatted) {
+      if (formatted[key] === '' || formatted[key] === undefined || formatted[key] === null) {
+        delete formatted[key]
+      }
+    }
+
+    return formatted
+  }
+
+  /**
+   * 搜索范围整理
+   * @param String val
+   * @returns Object
+   *
+   * 参数val示例:[content, title ,ppa]
+   */
+  static formatScope(val = [], split = ',') {
+    if (!Array.isArray(val)) return ''
+    return val.join(split)
+  }
+
+  /**
+   * 行业整理
+   * @param String val
+   * @returns Object
+   *
+   * 参数val示例:
+   * {
+   *    机械设备: ['工程机械', '车辆', '其他机械设备', '办公家具']
+   * }
+   */
+  static formatIndustry(val = {}, split = ',') {
+    let industry = ''
+    if (!val || Object.keys(val).length === 0) return industry
+
+    const industryArr = []
+
+    for (const key in val) {
+      if (Array.isArray(val[key])) {
+        val[key].forEach((item) => {
+          industryArr.push(`${key}_${item}`)
+        })
+      }
+    }
+
+    industry = industryArr.join(split)
+
+    return industry
+  }
+
+  /**
+   * 三级地级市地区整理
+   * @param String area
+   * @param String city
+   * @returns Object
+   *
+   * 参数area示例
+   * {
+   *    北京: {
+   *      朝阳区: [],
+   *      东城区: []
+   *    },
+   *    河南: {
+   *      南阳市: [],
+   *      郑州: ['金水区'],
+   *      洛阳市: ['栾川县']
+   *    },
+   *    澳门: {}
+   * }
+   */
+  static formatAreaCity(p = {}, split = ',') {
+    return areaObjToSingle(p, split)
+  }
+  /**
+   * 金额整理
+   * @returns String
+   */
+  static formatPrice(price = { start: '', end: '' }, split = '-') {
+    const { start, end } = price
+    if (start || end) {
+      return [start || '', end || ''].join(split)
+    } else {
+      return ''
+    }
+  }
+
+  /**
+   * 时间整理
+   * @param String val
+   * @returns Object
+   *
+   * 参数time: 时间选择器选择结果
+   * {
+   *    start: '',
+   *    end: '',
+   *    exact: 'exact'
+   * }
+   *
+   * exact: 是否只输出精确结果
+   * split: 精确结果的分隔符
+   */
+  static formatTime(time, exact = false, split = '_') {
+    let sortedTime = ''
+    if (!time) return sortedTime
+    const { start, end } = time
+    if (exact || time.exact === 'exact') {
+      const startVal = start ? dayjs(start).unix() : ''
+      const endVal = end ? dayjs(end).unix() : ''
+      sortedTime = [startVal, endVal].join(split)
+      if (startVal || endVal) {
+        return [startVal, endVal].join(split)
+      } else {
+        return [].join(split)
+      }
+    } else {
+      sortedTime = time.exact || ''
+    }
+    return sortedTime
+  }
+
+  /**
+   * 信息类型整理
+   * @param String val
+   * @returns Object
+   *
+   * 参数val示例:{}
+   */
+  static formatInfoType(infoType, split = ',') {
+    let arr = []
+    if (!infoType) return arr.join(split)
+    for (const key in infoType) {
+      arr = arr.concat(infoType[key])
+    }
+    return arr.join(split)
+  }
+
+  /**
+   * 采购单位类型整理
+   * @param String val
+   * @returns Object
+   *
+   * 参数val示例:{}
+   */
+  static formatBuyerClass(val, split = ',') {
+    let buyerClass = ''
+    if (!val || Object.keys(val).length === 0) return buyerClass
+
+    buyerClass = []
+
+    for (const key in val) {
+      if (Array.isArray(val[key])) {
+        val[key].forEach((item) => {
+          buyerClass.push(item)
+        })
+      }
+    }
+
+    buyerClass = buyerClass.join(split)
+
+    return buyerClass
+  }
+
+  /**
+   * 格式化包含关键词模式、包含关键词
+   */
+  static formatSelectMoreKey (selectMoreKey, additionalWords, wordsMode) {
+    let aWords = '' // 附加关键词筛选模式
+    let wMode = 0 // 附加关键词筛选模式
+    if(selectMoreKey) {
+      aWords = additionalWords ? additionalWords.join(',') : ''
+      wMode = Number(wordsMode)
+    }
+    return {
+      additionalWords: aWords,
+      wordsMode: wMode
+    }
+  }
+}

+ 1 - 0
apps/bigmember_pc/src/utils/index.js

@@ -7,3 +7,4 @@ export * from './globalFunctions'
 export * from './format/money'
 export * from './format/ad'
 export * from './format/date'
+export * from './format/search-bid-filter'

+ 30 - 0
apps/bigmember_pc/src/views/search/bidding/components/search-header-title.vue

@@ -0,0 +1,30 @@
+<script setup>
+import { SearchBidModel } from '../model/index'
+const { onSaveFilter } = SearchBidModel
+import { computed, getCurrentInstance, ref } from 'vue'
+const fixedTop = ref(false)
+const showFilter = ref(true)
+function toggleFilter() {}
+console.log(getCurrentInstance())
+</script>
+
+<template>
+  <div class="filter-header-container" :class="fixedTop ? 'fixed' : ''">
+    <div class="filter-header" :class="fixedTop ? 'fixed-top' : ''">
+      <div
+        class="f-h-label"
+        :class="showFilter ? 'caret-up' : 'caret-down'"
+        @click="toggleFilter"
+      >
+        <span>筛选条件</span>
+      </div>
+      <div class="f-h-action nologin-hide">
+        <!--        <span class="action-item reset-item" @click="onResetFilter">重置筛选条件</span>-->
+        <!--        <span class="action-item has-item" @click="onHasFilter">已存筛选条件 ${filterCounts}</span>-->
+        <span class="action-item save-item" @click="onSaveFilter"
+          >保存筛选条件</span
+        >
+      </div>
+    </div>
+  </div>
+</template>

+ 12 - 0
apps/bigmember_pc/src/views/search/bidding/constant/search-filters.js

@@ -7,6 +7,7 @@ import AttachmentSelector from '@/components/filter-items/AttachmentSelector.vue
 import AmountRangeSelector from '@/components/filter-items/AmountRangeSelector.vue'
 import IndustrySelector from '@/components/filter-items/IndustrySelector.vue'
 import KeywordTagsSelector from '@/components/filter-items/KeywordTagsSelector'
+import RegionSelector from '@/components/filter-items/RegionSelector'
 
 const SearchBidBaseSchema = [
   {
@@ -55,6 +56,17 @@ const SearchBidBaseSchema = [
 ]
 
 const SearchBidMoreSchema = [
+  {
+    key: 'regionMap',
+    label: '地区',
+    defaultVal: '',
+    _name: 'type',
+    _type: 'component',
+    expand: {
+      component: RegionSelector,
+      hooks: {}
+    }
+  },
   {
     key: 'industry',
     label: '行业',

+ 2 - 1
apps/bigmember_pc/src/views/search/bidding/index.vue

@@ -2,6 +2,7 @@
 import { computed, reactive, ref } from 'vue'
 import SearchBidHeader from '@/views/search/bidding/components/search-bid-header.vue'
 import SearchBidFilter from '@/views/search/bidding/components/search-bid-filter.vue'
+import searchHeaderTitle from '@/views/search/bidding/components/search-header-title.vue'
 import SearchList from '@/views/search/layout/search-list.vue'
 import ArticleItem from '@/components/article-item/ArticleItem.vue'
 import Adsense from '@/views/order/components/adsense/index.vue'
@@ -32,8 +33,8 @@ const {
     <div class="search-bidding-header-container b-rd-8px m-t-24px">
       <search-bid-header></search-bid-header>
     </div>
-
     <div class="search-bidding-filter-container b-rd-8px">
+      <searchHeaderTitle></searchHeaderTitle>
       <search-bid-filter></search-bid-filter>
     </div>
 

+ 22 - 28
apps/bigmember_pc/src/views/search/bidding/model/base.js

@@ -7,6 +7,7 @@ import { useSearchFilterModel } from './modules/filter'
 import { useSearchInputKeywordsModel } from './modules/filter-keywords'
 import { useSearchListHeaderActionsModel } from './modules/list-header-actions'
 import { useSearchTabsModel } from './modules/tabs'
+import { saveFilterActionsModel } from './modules/save-filter-actions'
 import { useStore } from '@/store'
 
 export default function () {
@@ -152,33 +153,6 @@ export default function () {
    */
 
   function getParams(params = {}) {
-    // 完整参数参考
-    const fullParams = {
-      pageNum: 1,
-      pageSize: 50,
-      reqType: '',
-      keyWords: '',
-      province: '',
-      city: '',
-      district: '',
-      subtype: '',
-      publishTime: '1682319144-1713941544',
-      searchGroup: 0,
-      searchMode: 0,
-      wordsMode: 0,
-      selectType: 'title,content',
-      price: '',
-      industry: '',
-      buyerClass: '',
-      winnerTel: '',
-      buyerTel: '',
-      exclusionWords: '',
-      buyer: '',
-      winner: '',
-      agency: '',
-      fileExists: '0',
-      splitKeywords: ''
-    }
     // 合并所有模型的搜索筛选项
     const result = Object.assign(
       {
@@ -211,6 +185,25 @@ export default function () {
     })
   }
 
+  /**
+   * 保存、重置筛选条件部分
+   **/
+  const { saveFilterDialog, filterSaveParams } = saveFilterActionsModel
+
+  /**
+   * 保存筛选条件
+   */
+  function onSaveFilter() {
+    const originParams = Object.assign(
+      {},
+      filterState.value,
+      inputKeywordsState.value
+    )
+    const config = {
+      filter: originParams
+    }
+  }
+
   return {
     searchModelOptions,
     searchListProps,
@@ -224,6 +217,7 @@ export default function () {
     doChangeAllSelect,
     doChangeSelect,
     doChangePageNum,
-    doChangePageSize
+    doChangePageSize,
+    onSaveFilter
   }
 }

+ 57 - 0
apps/bigmember_pc/src/views/search/bidding/model/modules/data-export-actions.js

@@ -0,0 +1,57 @@
+import { computed, ref } from 'vue'
+import { ajaxGetDontPromptAgain, ajaxSetDontPromptAgain } from '@/api/modules/'
+import { tryCallHooks } from '@jianyu/easy-inject-qiankun'
+
+
+// 判断是否展示弹框
+async function getDontPromptAgain() {
+  const { error_code: code, isPrompt } = await ajaxGetDontPromptAgain()
+  return {
+    code,
+    isPrompt
+  }
+}
+
+async function toDataExportEvent() {
+  // const res = await getPushListExport(this.vt, query)
+  // this.exportLoading = false
+  // if (res.data) {
+  //   const link = `/front/dataExport/toCreateOrderPage/${res.data}`
+  //   tryCallHooks({
+  //     fn: () => {
+  //       this.$BRACE.methods.open({
+  //         route: {
+  //           link
+  //         }
+  //       })
+  //     },
+  //     spareFn: () => {
+  //       location.href = link
+  //       // window.open(link)
+  //     }
+  //   })
+  // }
+}
+
+export function dataExportActionsModel (config = {}) {
+  const { list, loading, finished, total, selectedIds } = config
+  const { code, isPrompt } = getDontPromptAgain()
+  if(code === 0) {
+    const countBool = ref(false)
+    // 限制2000条提示弹窗
+    const showDataExportDialog = ref(false)
+    if(selectedIds > 0) {
+      countBool.value = selectedIds >= 2000
+    } else {
+      countBool.value = total >= 2000
+    }
+    if (isPrompt && countBool) {
+      showDataExportDialog.value = isPrompt
+    } else {
+      // toDataExportEvent()
+    }
+  } else {
+    // toDataExportEvent()
+  }
+
+}

+ 2 - 0
apps/bigmember_pc/src/views/search/bidding/model/modules/filter.js

@@ -9,6 +9,8 @@ export function useSearchFilterModel() {
     selectType: ['content', 'title'],
     // 信息类型
     subtype: [],
+    // 地区
+    regionMap: {},
     // 行业
     industry: {},
     // 附件

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

@@ -0,0 +1,50 @@
+import { computed, reactive, ref, getCurrentInstance } from 'vue'
+import { checkBiddingFilterPass } from '@/api/modules'
+import  { FilterHistoryViewModel2AjaxModel } from '@/utils'
+import { showToast } from '@/components/toast'
+import { ajaxGetSearchBidList } from '@jy/data-models/modules/quick-search/api/search-bid'
+
+const saveConfig = {
+  savedFilterListMaxCount: 10 //筛选条件保存条数最大值
+}
+
+export function saveFilterActionsModel () {
+   let filterSaveParams = reactive({})
+   const saveFilterDialog = ref(false)
+
+  // 检测筛选条件是否可保存
+  //  async function checkFilterPass (config) {
+  //    const  { filter } = config
+  //    filterSaveParams = FilterHistoryViewModel2AjaxModel.formatAll(filter)
+  //
+  //    const hasOneKey = ref(filterSaveParams.buyer || filterSaveParams.winner || filterSaveParams.agency)
+  //    if (!filterSaveParams.searchvalue && !filterSaveParams.additionalWords && !filterSaveParams.industry && !hasOneKey) {
+  //      return showToast('请先输入关键词')
+  //    }
+  //    const { savedFilterListMaxCount: maxCount} = saveConfig
+  //    if(maxCount) {
+  //      return showToast(`对不起,最多可保存${maxCount}个筛选条件。`)
+  //    }
+  //    const { data: id, error_code: code = 0, error_msg: msg } = await checkBiddingFilterPass(filterSaveParams)
+  //   if(code === 0) {
+  //     saveFilterDialog.value = true
+  //   } else {
+  //     if (msg) {
+  //       if (msg.includes('无用户身份')) {
+  //         showToast('请登录')
+  //       } else {
+  //         showToast(msg)
+  //       }
+  //     }
+  //   }
+  // }
+  // console.log(111111)
+  //  console.log(checkFilterPass)
+
+
+
+  return {
+    saveFilterDialog,
+    filterSaveParams,
+  }
+}

+ 1 - 1
apps/bigmember_pc/src/views/search/layout/search-list.vue

@@ -42,7 +42,7 @@ const props = defineProps({
     })
   }
 })
-
+console.log(props.headerActions)
 const canShowPagination = computed(() => {
   if (props.listState.loading && props.listState.pageNum === 1) {
     return false