Browse Source

省市区

lifanagju_citu 8 months ago
parent
commit
3191368f5a

+ 58 - 6
src/views/recruit/personal/position/components/conditionFilter.vue

@@ -1,23 +1,26 @@
 <template>
   <div>
-    <div class="d-flex">
+    <div class="d-flex" style="flex-wrap: wrap;">
       <template v-for="item in list" :key="item.key">
         <component
+          v-if="!item.hide"
           :is="item.path"
           :idName="item.key"
           :title="item.title"
           :isSingle="item.isSingle"
           :isSlot="item.isSlot"
+          :itemKey="item.itemKey"
+          :itemText="item.itemText"
           :displayDictName="item.displayDictName"
           :provideData="item.provideData || []"
-          :info="item"
+          btnClass="mt-1"
           @inputChange="inputChange"
         ></component>
       </template>
     </div>
     <div v-if="showSelectList?.length">
       <div style="margin-top: 20px; border-top: 1px solid #eee;">
-        <div v-for="item in showSelectList" :key="item.key" style="margin: 4px 8px 4px 0px;">
+        <div v-for="item in showSelectList" :key="item.key" style="margin: 4px 8px 4px 0px;" :style="`display: ${item.key.includes('cityId_') ? 'inline-block' : 'block'};`">
           <template v-if="item.checkedItems?.length">
             <span style="color: #999;">{{ item.title }}:</span>
             <v-btn
@@ -41,7 +44,7 @@
 </template>
 <script setup>
 import { useRoute } from 'vue-router'; const route = useRoute()
-import { watch, ref, shallowRef } from 'vue'
+import { watch, ref, shallowRef, nextTick } from 'vue'
 import { filterList, getItemObj } from './dict'
 defineOptions({name: 'retrieval-components-conditionFilter'})
 const emits = defineEmits(['change', 'reset'])
@@ -56,9 +59,54 @@ const list = shallowRef(props.showFilterList === 'all' ? filterList : props.show
   return item ? { ...item, ...e } : ''
 }).filter(Boolean) : [])
 
-const inputChange = ({ idName: key, values }) => {
+// 城市处理
+const cityDelete = (cityLevel) => {
+  list.value.forEach(e => {
+    if (e.key.includes('cityId_') && e.cityLevel > cityLevel) {
+      emits('change', e.key, '')
+      e.del = true
+    }
+  })
+  list.value = list.value.filter(e => !e.del)
+}
+// 城市处理
+const cityDeal = (str, key, clickItem) => {
+  if (str === '10000') { // 全国
+    cityDelete(1)
+    return
+  } 
+  const i = list.value.findIndex(e => e.key === key)
+  if (i !== -1) {
+    cityDelete(list.value[i].cityLevel) // 去掉当前选中层级后面的市区
+    if (str && clickItem?.children?.length) { // 选中-添加下级
+      let noProvince = false
+      if (clickItem.children[0][list.value[i].itemText] === clickItem[list.value[i].itemText] && clickItem.children[0].children?.length) { // 直辖市
+        clickItem = clickItem.children[0]
+        noProvince = true
+      }
+      const obj = {
+        ...list.value[i], // 复制其他属性
+        toFilterDictName: null, toFilterApiType: null, displayDictName: null, displayApiType: null,
+        isSingle: Boolean(clickItem.children[0]?.children?.length),
+        provideData: clickItem.children, // 赋值下拉数据
+        toFilterDictDataList: clickItem.children // 回显使用
+      }
+      obj.cityLevel++ // 层级
+      if (noProvince) obj.cityLevel++ // 直辖市
+      obj.key = 'cityId_' + obj.cityLevel
+      obj.title = obj.cityLevel === 2 ? '市' : '区'
+      nextTick(() => {
+        list.value.splice(i+1, 0, obj)
+      })
+    }
+  }
+}
+
+const inputChange = ({ idName: key, values, clickItem }) => {
   const str = values.length ? values.join('_') : ''
   if (!key) return
+  if (key.includes('cityId_')) cityDeal(str, key, clickItem) // 城市处理
+  //
   emits('change', key, str)
 }
 
@@ -74,7 +122,7 @@ const showSelectList = ref([])
 // 添加
 const assembleList = ({ key, idsStr }) => {
   const ids = idsStr.split('_') || []
-  const obj = getItemObj({ key, ids })
+  const obj = getItemObj({ key, ids, dictArr: list.value })
   if (!obj) return
   const index = showSelectList.value.findIndex(i => i.key === key)
   if (index === -1) showSelectList.value.push(obj)
@@ -102,6 +150,10 @@ watch(
       // showSelectList去掉newVal里面没有的key
       showSelectList.value = showSelectList.value.filter(item => Object.keys(newVal).includes(item.key))
     }
+    showSelectList.value = [ // 城市放在一起展示
+      ...showSelectList.value.filter(item => item.key.includes('cityId_')),
+      ...showSelectList.value.filter(item => !item.key.includes('cityId_')),
+    ]
   },
   { immediate: true },
   { deep: true }

+ 21 - 9
src/views/recruit/personal/position/components/conditionFilter/commonPath.vue

@@ -1,20 +1,20 @@
 <template>
-  <commonStyle :btnTitle="btnTitle" :close-on-content-click="props.isSingle" v-if="show">
+  <commonStyle :btnTitle="btnTitle" v-bind="$attrs" :close-on-content-click="props.isSingle" v-if="show">
     <!-- 行业类型 -->
     <industryTypeCard v-if="idName === 'industryIds'" :select="selectedItems" @handleClickIndustry="handle"></industryTypeCard>
     <!-- 职位类型 -->
     <jobTypeCard v-else-if="idName === 'positionId'" :select="selectedItems" isSingle echo clearable @handleJobClick="handle"></jobTypeCard>
     <v-list v-else>
       <v-list-item
-        v-for="item in items" :key="item.id" :value="item.value"
-        :active="selectedItems.includes(item.value)"
+        v-for="item in items" :key="item.id" :value="item[itemKey]"
+        :active="selectedItems.includes(item[itemKey])"
         color="primary"
-        @click="handle(item.value)"
+        @click="handle(item, item[itemKey])"
       >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
+        <template v-if="selectedItems.includes(item[itemKey])" v-slot:append>
           <v-icon icon="mdi-check"></v-icon>
         </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
+        <v-list-item-title>{{ item[itemText] }}</v-list-item-title>
       </v-list-item>
     </v-list>
   </commonStyle>
@@ -24,6 +24,7 @@ import commonStyle from './commonStyle.vue'
 import industryTypeCard from '@/components/industryTypeCard'
 import jobTypeCard from '@/components/jobTypeCard'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { useRoute } from 'vue-router'; const route = useRoute()
 import { ref, computed, watch } from 'vue';
 
 defineOptions({name: 'conditionFilter-JobType'})
@@ -45,6 +46,14 @@ const props = defineProps({
     type: String,
     default: ''
   },
+  itemKey: {
+    type: String,
+    default: 'value'
+  },
+  itemText: {
+    type: String,
+    default: 'label'
+  },
   displayDictName: {
     type: [String, Number],
     default: '' // 1: 插槽使用会返回数组
@@ -67,7 +76,8 @@ let show = ref(false)
 let items = ref()
 const selectedItems = ref([])
 
-const handle = (value) => {
+const handle = (item) => {
+  const value = item[props.itemKey]
   if (props.isSlot) {
     selectedItems.value = value
   } else {
@@ -81,12 +91,14 @@ const handle = (value) => {
   }
   emits('inputChange', {
     idName: props.idName,
+    clickItem: item,
     // title: props.title,
     values: selectedItems.value,
     isEmit: props.positionIndexPage
   })
 }
 
+
 // 字典
 if (props.isSlot) show.value = true // 插槽使用
 else if (props.provideData?.length) { // 自定义下拉数据
@@ -94,14 +106,14 @@ else if (props.provideData?.length) { // 自定义下拉数据
   show.value = true
 }
 else if (props.displayDictName) {
-  getDict(props.displayDictName).then(({ data }) => {
+  getDict(props.displayDictName, props.displayParams, props.displayApiType).then(({ data }) => {
     data = data?.length && data || []
     items.value = data
     show.value = true
   })
 } else console.log('error->字典参数未传递!!')
 
-import { useRoute } from 'vue-router'; const route = useRoute()
+
 watch(
   () => route.query, 
   (newVal, oldVal) => {

+ 5 - 0
src/views/recruit/personal/position/components/conditionFilter/commonStyle.vue

@@ -11,6 +11,7 @@
     <template v-slot:activator="{ isActive, props }">
       <v-btn
         class="mr-3 py-0 px-2"
+        :class="defineProps.btnClass"
         density="comfortable"
         :append-icon="isActive ? 'mdi mdi-menu-up' : 'mdi mdi-menu-down'"
         color="primary" variant="tonal"
@@ -33,6 +34,10 @@ const defineProps = defineProps({
   closeOnContentClick: {
     type: Boolean,
     default: true
+  },
+  btnClass: {
+    type: String,
+    default: ''
   }
 })
 </script>

+ 30 - 33
src/views/recruit/personal/position/components/dict.js

@@ -6,39 +6,34 @@ import commonPath from './conditionFilter/commonPath.vue'
 // 当type是tree类型的数据的时候需要提供dictType
 const dictList = [
   {
-    displayDictName: 'menduner_area_type',
-    apiType: 'areaList',
-    key: 'areaIds',
+    toFilterDictName: 'menduner_area_type',
+    toFilterApiType: 'areaList',
+    displayDictName: 'areaTreeData',
+    displayApiType: 'areaTreeData',
+    displayParams: {},
+    key: 'cityId_1',
+    cityLevel: 1,
     itemKey: 'id',
     itemText: 'name',
-    title: '工作地点',
-    path: commonPath,
-    data: []
-  },
-  {
-    displayDictName: 'menduner_area_type',
-    apiType: 'areaList',
-    key: 'areaIds',
-    itemKey: 'id',
-    itemText: 'name',
-    title: '工作地点',
+    title: '工作城市',
+    isSingle: true,
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     toFilterDictName: 'menduner_industry_type',
-    apiType: 'industryList',
+    toFilterApiType: 'industryList',
     key: 'industryIds',
     isSlot: true,
     itemKey: 'id',
     itemText: 'nameCn',
     title: '行业类型',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     toFilterDictName: 'positionData',
-    apiType: 'positionData',
+    toFilterApiType: 'positionData',
     key: 'positionId',
     isSlot: true,
     itemKey: 'id',
@@ -46,7 +41,7 @@ const dictList = [
     title: '职位类型',
     isSingle: true,
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_job_type',
@@ -55,7 +50,7 @@ const dictList = [
     itemText: 'label',
     title: '求职类型',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_exp_type',
@@ -64,7 +59,7 @@ const dictList = [
     itemText: 'label',
     title: '工作经验',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_pay_scope',
@@ -73,9 +68,8 @@ const dictList = [
     itemText: 'label',
     title: '薪资待遇',
     isSingle: true,
-    isString: true,
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_education_type',
@@ -84,7 +78,7 @@ const dictList = [
     itemText: 'label',
     title: '学历要求',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_scale',
@@ -93,7 +87,7 @@ const dictList = [
     itemText: 'label',
     title: '公司规模',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
   {
     displayDictName: 'menduner_financing_status',
@@ -102,7 +96,7 @@ const dictList = [
     itemText: 'label',
     title: '融资阶段',
     path: commonPath,
-    data: []
+    toFilterDictDataList: []
   },
 ]
 export const filterList = dictList
@@ -111,8 +105,9 @@ export const filterList = dictList
 const getDictList = async () => {
   dictList.forEach(async (dictListItem) => {
     const toFilterDictName = dictListItem.toFilterDictName || dictListItem.displayDictName
-    const { data } = await getDict(toFilterDictName, dictListItem.params, dictListItem.apiType)
-    dictListItem.data = data
+    if (!toFilterDictName) return
+    const { data } = await getDict(toFilterDictName, dictListItem.params, dictListItem.toFilterApiType)
+    dictListItem.toFilterDictDataList = data
   })
 }
 
@@ -121,13 +116,15 @@ const getData = async () => {
 }
 getData()
 
-export const getItemObj = ({ key, ids = [] }) => {
-  const item = dictList.find(dictListItem => dictListItem.key === key)
+export const getItemObj = ({ key, ids = [], dictArr = [] }) => {
+  if (!dictArr?.length) dictArr = dictList
+  //
+  const item = dictArr.find(dictListItem => dictListItem.key === key)
   const checkedItems = ids.map(id => {
-    if (!item?.data?.length) return ''
-    const obj = item.data.find(e => e[item.itemKey] === id)
+    if (!item?.toFilterDictDataList?.length) return ''
+    const obj = item.toFilterDictDataList.find(e => e[item.itemKey] === id)
     return obj ? { text: obj[item.itemText], value: obj[item.itemKey] } : ''
   }).filter(Boolean)
 
-  return checkedItems?.length ? { key, title: item.title, checkedItems, ref: item.ref } : ''
+  return checkedItems?.length ? { key, title: item.title, checkedItems } : ''
 }

+ 1 - 1
src/views/recruit/personal/position/index.vue

@@ -49,7 +49,7 @@ const route = useRoute(); const router = useRouter()
 const cityFilterRef = ref()
 const conditionFilterRef = ref()
 const showFilterList = [
-  // { key: 'cityId' },
+  // { key: 'cityId_1' },
   { key: 'industryIds' },
   { key: 'positionId', isSingle: true },
   { key: 'jobType' },