Browse Source

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

Xiao_123 1 năm trước cách đây
mục cha
commit
13fa33387b

+ 0 - 55
src/views/recruit/position/components/areaCascader/index copy 2.vue

@@ -1,55 +0,0 @@
-<template>
-  <div>
-    <div v-if="currentOptions.length">  
-      <label>{{ label }}</label>  
-      <select  
-        v-model="selected"  
-        @change="onChange"  
-        :disabled="!currentOptions.length"  
-      >  
-        <option v-for="option in currentOptions" :key="option.value" :value="option.value">  
-          {{ option.label }}  
-        </option>  
-      </select>  
-      <cascader  
-        v-if="selected"  
-        :options="options"  
-        :value="selected"  
-        :label="`${label} > `"  
-        @update:value="onChildUpdate"  
-      />  
-    </div>
-  </div>
-</template>
-
-<script setup>
-import { computed } from 'vue';
-
-defineOptions({name: 'defineOptions-area-cascader'})
-const props = defineProps({
-  modelValue: [String, Number],
-  options: Object,
-  value: {  
-    type: [String, Number],  
-    default: null,  
-  },
-  label: {  
-    type: String,  
-    default: '请选择',  
-  }
-})
-const currentOptions = computed(() => {
-  if (!this.selected) {  
-    return props.options.filter(option => !option.children || !option.children.length);  
-  }  
-
-  const selectedOption = props.options.find(option => option.value === this.selected);  
-  if (selectedOption && selectedOption.children) {  
-    return selectedOption.children;  
-  }  
-
-  return [];  
-})
-</script>
-<style lang="scss" scoped>
-</style>

+ 0 - 21
src/views/recruit/position/components/areaCascader/index copy.vue

@@ -1,21 +0,0 @@
-<template>
-  <div v-if="show">
-    <recursive v-if="items?.length" :items="items"></recursive>
-  </div>
-</template>
-<script setup>
-import recursive from './recursive'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref } from 'vue';
-defineOptions({ name:'common-components-areaTree'})
-
-let items = ref() 
-let children = ref() 
-const show = ref(false) 
-getDict('areaTreeData', {}, 'areaTreeData').then(({ data }) => {
-  items.value = data?.length && data || []
-  children.value = items.value[0]?.children.length && items.value[0].children || []
-  show.value = true
-})
-
-</script>

+ 121 - 8
src/views/recruit/position/components/areaCascader/index.vue

@@ -1,21 +1,134 @@
 <template>
   <div v-if="show">
-    <recursive v-if="items?.length" :items="items"></recursive>
+    <!-- <recursive v-if="items?.length" :items="items"></recursive> -->
+    <div v-for="(list, levelIndex) in treeList" :key="`select${levelIndex}`">
+      <div v-if="levelIndex < props.multipleLevel">
+        <span v-for="(item, itemIndex) in list" :key="item.id">
+          <span
+            v-if="itemIndex + 1 <= num"
+            class="mx-3"
+            :class="{'act': calcAct(item.id, levelIndex)}"
+            style="line-height: 32px;"
+            @click="handleNext(item, levelIndex)"
+          >{{ item.name }}</span>
+        </span>
+        <!-- 其他 -->
+        <span v-if="list?.length > num" class="mx-3" style="line-height: 32px;">其他</span>
+      </div>
+      <div v-else class="embedded">
+        <span
+          v-for="item in list" :key="item.id"
+          class="mx-3"
+          :class="{'act': calcAct(item.id, levelIndex)}"
+          style="line-height: 32px;"
+          @click="handleNext(item, levelIndex)"
+        >{{ item.name }}</span>
+      </div>
+    </div>
   </div>
 </template>
 <script setup>
-import recursive from './recursive'
+// import recursive from './recursive'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref } from 'vue';
+import { reactive, ref } from 'vue'
 defineOptions({ name:'common-components-areaTree'})
+const emits = defineEmits('input')
 
-let items = ref() 
-let children = ref() 
+const props = defineProps({
+  // items: Object,
+  defaultOpen: {
+    type: Number,
+    default: 2
+  },
+  multipleLevel: {
+    type: Number,
+    default: 3
+  },
+  parentId: {
+    type: [Number, String],
+    default: -1
+  }
+})
+const num = 10
+
+let treeList = ref() 
 const show = ref(false) 
+// 获取区域数据
 getDict('areaTreeData', {}, 'areaTreeData').then(({ data }) => {
-  items.value = data?.length && data || []
-  children.value = items.value[0]?.children.length && items.value[0].children || []
+  const arr = data?.length && data || []
+  treeList.value = [arr]
   show.value = true
+  
+  // 默认展开
+  if (props.defaultOpen > 0) {
+    for (let index = 0; index < props.defaultOpen; index++) {
+      if (treeList.value?.length && treeList.value[index]?.length && treeList.value[index][0]) {
+        const stopExpand = (index + 1) === props.defaultOpen
+        handleNext(treeList.value[index][0], index, stopExpand)
+      }
+    }
+    emits('input', idChecked)
+  }
 })
 
-</script>
+// 设置选中ids
+const idChecked = reactive([])
+const getIdChecked = (item, levelIndex) => {
+  if (!idChecked[levelIndex]) idChecked[levelIndex] = [] // 不存在初始化为空
+  if (levelIndex < props.multipleLevel) {
+    idChecked[levelIndex] = [ item.id ]
+  } else {
+    const findIndex = idChecked[levelIndex]?.length ? idChecked[levelIndex].findIndex(j => j === item.id) : -1
+    if (findIndex !== -1) {  
+      idChecked[levelIndex].splice(findIndex, 1) // 删除  
+    } else {  
+      idChecked[levelIndex].push(item.id) // 添加  
+    }
+  }
+  idChecked.splice(levelIndex + 1, treeList.value.length) // 取消其下级数据
+}
+
+// 展开下一级
+const handleNext = (item, index, stopExpand) => { // stopExpand:不展开下级
+  getIdChecked(item, index)
+  if (!stopExpand &&item.children && item.children.length) {
+    treeList.value[index + 1] = item.children
+    treeList.value.splice(index + 2, treeList.value.length)
+  } else {
+    treeList.value.splice(index + 1, treeList.value.length)
+  }
+}
+
+// 选中样式判断
+const calcAct = (id, levelIndex) => {
+  if (!id) return false
+  if (Array.isArray(idChecked) && Array.isArray(idChecked[levelIndex])) {
+    const index = idChecked[levelIndex].findIndex(itemToCheck => itemToCheck=== id)
+    return index !== -1 ? true : false; // 如果找到返回索引,否则返回 false
+  }
+  else return false
+}
+</script>
+<style lang="scss" scoped>
+.text666 {
+  border-right: 1px solid #666666;
+}
+.text333 {
+  color: #333333;
+}
+.act {
+  color: var(--v-primary-base);
+}
+span {
+  span { cursor: pointer; }
+  cursor: pointer;
+  &:hover {
+    color: var(--v-primary-lighten2);
+  }
+}
+.embedded {
+  padding: 4px;
+  background-color: #f8f8f8;
+  border-radius: 5px;
+}
+</style>

+ 241 - 66
src/views/recruit/position/components/areaCascader/recursive.vue

@@ -1,31 +1,65 @@
 <template>
-  <div>
-    <div :class="{'embedded': outweigh}">
-      <template v-if="outweigh">
-        <span :class="{'act': actIndex === -1}">不限</span>
-        <!-- <span class="text666 mr-2"></span> -->
-      </template>
+  <div v-for="(list, levelIndex) in treeList" :key="`select${levelIndex}`">
+    <div v-if="levelIndex < props.defaultOpen">
+      <span v-for="(item, itemIndex) in list" :key="item.id">
+        <span
+          v-if="itemIndex + 1 <= num"
+          class="mx-3"
+          :class="{'act': calcAct(item.id, levelIndex)}"
+          style="line-height: 32px;"
+          @click="handleNext(item, levelIndex)"
+        >{{ item.name }}</span>
+      </span>
+      <!-- 其他 -->
+      <span v-if="list?.length > num" class="mx-3" style="line-height: 32px;">其他</span>
+    </div>
+    <div v-else class="embedded">
+      <span
+        v-for="item in list" :key="item.id"
+        class="mx-3"
+        :class="{'act': calcAct(item.id, levelIndex)}"
+        style="line-height: 32px;"
+        @click="handleNext(item, levelIndex)"
+      >{{ item.name }}</span>
+    </div>
+  </div>
+  <!-- <div>
+    <div v-for="(item, index) in treeList" :key="`select${index}`">
+      <div :class="{'embedded': index + 1 > props.defaultOpen }">
+        <template v-for="(val, listIndex) in item" :key="`val${listIndex}`">
+          <span v-if="listIndex < num" class="mx-3" style="line-height: 32px;" @click="handleNext(val, index)">{{ val.name }}</span>
+        </template>
+      </div>
       <span v-for="(item, index) in props.items" :key="item.id">
-        <span v-if="index < num" class="mx-3" :class="{'act': actIndex === index}" style="line-height: 32px;" @click="handleClick(item, index)">{{ item.name }}</span>
+        <span v-if="index < num" class="mx-3" :class="{'act': calcAct(item)}" style="line-height: 32px;" @click="handleClick(item, index)">{{ item.name }}</span>
       </span>
       <template v-if="underAndEqual">
-        <!-- <span class="text666 mr-2"></span> -->
         <span v-if="props.items?.length >= num" @click="handleClick(props.items, 'other')">其他</span>
       </template>
     </div>
     <template v-if="children?.length">
       <v-divider v-if="outweigh" class="mx-2"></v-divider>
-      <recursive ref="childRef" :defaultOpen="props.defaultOpen" :items="children" :parentId="itemId"></recursive>
+      <recursive ref="childRef" :defaultOpen="props.defaultOpen" :items="children" :parentId="itemId" v-model="modelValueDeep"></recursive>
     </template>
-  </div>
+  </div> -->
 </template>
 <script setup>
-import { computed, reactive, ref, watch } from 'vue'
-import recursive from './recursive'
+import { reactive, ref } from 'vue'
+// import recursive from './recursive'
+// import { useRoute, useRouter } from 'vue-router'
 defineOptions({ name:'common-components-areaTree-recursive'})
+const emits = defineEmits('input')
+// const route = useRoute(); const router = useRouter()
+// const checked = reactive({})
+// console.log('to:/recruit/position-> query', route.query)
+// if (Object.keys(route.query).length) {
+//   Object.keys(route.query).forEach(_e => {
+//     checked[_e]
+//   })
+// }
 
-const num = 14
-const childRef = ref(null)
+const num = 10
+// const childRef = ref(null)
 const props = defineProps({
   items: Object,
   defaultOpen: {
@@ -37,68 +71,207 @@ const props = defineProps({
     default: -1
   }
 })
-// const currentRowType = computed(() => {
-//   if (props.items?.length) return props.items[0].type - 0
-//   else return 0
-// })
-let itemId = ref(0)
-let currentRowType = ref(0)
-let actIndex = ref(0)
-let currentRow = reactive({ id: -1})
-let children = ref([])
-const setRow = (item) => {
-  if (item) {
-    console.log('currentRow1', { ...item, children: null})
-    currentRow = item
-    children.value = currentRow.children
-    itemId.value = currentRow.id || 0
-    currentRowType.value = currentRow.type || 0
+
+const idChecked = reactive([])
+const getIdChecked = (item, levelIndex) => {
+  if (!idChecked[levelIndex]) idChecked[levelIndex] = [] // 不存在初始化为空
+  if (levelIndex < props.defaultOpen) {
+    idChecked[levelIndex] = [ item.id ]
   } else {
-    currentRow = { id: -1 }
-    itemId.value = -1
-    currentRowType.value = 0
+    const findIndex = idChecked[levelIndex]?.length ? idChecked[levelIndex].findIndex(j => j === item.id) : -1
+    if (findIndex !== -1) {  
+      idChecked[levelIndex].splice(findIndex, 1) // 删除  
+    } else {  
+      idChecked[levelIndex].push(item.id) // 添加  
+    }
   }
+  // console.log('idChecked', idChecked)
 }
 
-const init = () => {
-  itemId.value = -1
-  if (currentRowType.value < props.defaultOpen && props.items?.length) {
-    setRow(props.items[0])
-    actIndex.value = 0
+const treeList = ref([
+  [...props.items]
+])
+const handleNext = (item, index, stopExpand) => { // stopExpand:不展开下级
+  getIdChecked(item, index)
+  if (!stopExpand &&item.children && item.children.length) {
+    treeList.value[index + 1] = item.children
+    treeList.value.splice(index + 2, treeList.value.length)
   } else {
-    setRow(null)
+    treeList.value.splice(index + 1, treeList.value.length)
   }
-  if (currentRowType.value > props.defaultOpen) {
-    actIndex.value = -1
+}
+
+if (props.defaultOpen > 0) {
+  for (let index = 0; index < props.defaultOpen; index++) {
+    if (treeList.value?.length && treeList.value[index]?.length && treeList.value[index][0]) {
+      const stopExpand = (index + 1) === props.defaultOpen
+      handleNext(treeList.value[index][0], index, stopExpand)
+    }
   }
+  emits('input', idChecked)
 }
 
-// 监听
-watch(
-  () => props.parentId, 
-  () => {
-    // 函数
-    init()
-  },
-  { immediate: true },
-  { deep: true }
-)
-
-const handleClick = (item, index) => {
-  console.log('init', item.name)
-  if (index === 'other') return
-  else {
-    actIndex.value = index
-    currentRow.value = item
-    children.value = item.children
-    children.value = item.children
-    itemId.value = item.id || 0
+const calcAct = (id, levelIndex) => {
+  if (!id) return false
+  if (Array.isArray(idChecked) && Array.isArray(idChecked[levelIndex])) {
+    const index = idChecked[levelIndex].findIndex(itemToCheck => itemToCheck=== id)
+    return index !== -1 ? true : false; // 如果找到返回索引,否则返回 false
   }
+  else return false
 }
 
-console.log('currentRowType', currentRowType)
-const outweigh = computed(() => (currentRowType.value > props.defaultOpen))
-const underAndEqual = computed(() => (currentRowType.value <= props.defaultOpen))
+
+// const modelValueDeep = ref([])
+// let itemId = ref(0)
+// let currentRowType = ref(0)
+// let actIndex = ref(0)
+// let currentRow = reactive({ id: -1})
+// let children = ref([])
+// const rowExtend = (item) => {
+//   if (item) {
+//     currentRow = item
+//     itemId.value = currentRow.id || 0
+//     currentRowType.value = currentRow.type || 0
+//   } else {
+//     currentRow = { id: -1 }
+//     itemId.value = -1
+//     currentRowType.value = 0
+//   }
+// }
+// // 选中回显
+// const checkedFun = (item) => {
+//   const key = 'type' + item.type
+//   let typeChecked = checked[key] || (checked[key] = []) // 不存在初始化为空
+//   if (item.type <= props.defaultOpen) {
+//     typeChecked.length = 0 // 清空数组
+//     typeChecked.push({ id: item.id, name: item.name })
+//   } else {
+//     // 多选
+//     const index = typeChecked.findIndex(itemToCheck => itemToCheck.id === item.id)
+//     if (index !== -1) {  
+//       typeChecked.splice(index, 1) // 删除  
+//     } else {  
+//       typeChecked.push({ id: item.id, name: item.name }) // 添加  
+//     }
+//   }
+// }
+
+// const idChecked = ref([])
+// const getIdChecked = (item) => {
+//   const { name, id } = item
+//   // if (item.type <= props.defaultOpen) {
+//   //   idChecked.value = [{ name, id }]
+//   // } else {
+//   //   const index = idChecked.value.findIndex(j => j.id === item.id)
+//   //   if (index !== -1) {  
+//   //     idChecked.value.splice(index, 1) // 删除  
+//   //   } else {  
+//   //     idChecked.value.push({ name, id }) // 添加  
+//   //   }
+//   // }
+//   // 提交已选中的给areaCascader-index组件
+//   // const params = { [`type${item.type}`]: idChecked.value }
+
+//   emits('update:modelValue', [...props.modelValue, {name, id}])
+//   // console.log('params', props.value)
+// }
+
+// const init = () => {
+//   if (props.items?.length) {
+//     const item = props.items[0]
+//     // 设置激活样式
+//     actIndex.value = 0
+//     if (item.type - 0 <= props.defaultOpen) getIdChecked(item)
+//     // 显示子级数据
+//     if (item.type - 0 < props.defaultOpen) {
+//       children.value = item.children
+//     } else {
+//       children.value = []
+//     }
+//     rowExtend(item)
+//   } else {
+//     rowExtend(null)
+//   }
+// }
+
+// 监听
+// watch(
+//   () => props.parentId, 
+//   () => {
+//     // 函数
+//     init()
+//   },
+//   { immediate: true },
+//   { deep: true }
+// )
+// watch(
+//   () => props.modelValue, 
+//   (val) => {
+//     console.log('val', val)
+//   },
+//   { immediate: true },
+//   { deep: true }
+// )
+// 点击事件
+// const handleClick = (item) => {
+//   // console.log(item, index)
+//   const { name, id } = item
+//   emits('update:modelValue', [...props.modelValue, { name, id }])
+//   // if (index === 'other') return
+//   // else {
+//   //   actIndex.value = index
+//   //   if (item.children?.length) {
+//   //     if (item.type - 0 > props.defaultOpen - 1) { // 下一级是多选的情况下(props.defaultOpen的上一级)
+//   //       const i = { id: 0, name: '不限', type: currentRowType.value + 1, parentId: item.parentId, children: [] }
+//   //       children.value = [i, ...item.children]
+//   //     }
+//   //     else children.value = item.children
+//   //   } else children.value = []
+//   //   rowExtend(item) // 相关属性
+//   //   getIdChecked(item) // 加入checked
+
+//   //   // const key = `type${currentRowType.value}`
+//   //   // const query = { [`type${currentRowType.value}`]: idChecked.value.join('_') }
+//   //   // router.push({ path: route.path, query })
+//   // }
+// }
+
+// // 设置激活样式
+// const calcActFun = (item) => {
+//   // 首先确保 item 有 id 属性
+//   if (!item?.id) {
+//     return false
+//   }
+//   // 计算 key
+//   const key = 'type' + item.type
+  
+//   // 尝试从 checked 对象中获取对应的数组
+//   const typeChecked = checked[key]
+  
+//   // 如果 typeChecked 存在并且是一个数组,则查找索引
+//   if (Array.isArray(typeChecked)) {
+//     const index = typeChecked.findIndex(itemToCheck => itemToCheck.id === item.id)
+//     return index !== -1 ? true : false; // 如果找到返回索引,否则返回 false
+//   }
+  
+//   // 如果 typeChecked 不存在或不是一个数组,返回 false
+//   return false
+// }
+
+// 设置激活样式
+// const calcAct = (item) => {
+//   // 首先确保 item 有 id 属性
+//   if (!item?.id) {
+//     return false
+//   }
+//   if (Array.isArray(idChecked.value)) {
+//     const index = idChecked.value.findIndex(itemToCheck => itemToCheck.id=== item.id)
+//     return index !== -1 ? true : false; // 如果找到返回索引,否则返回 false
+//   }
+// }
+
+// const outweigh = computed(() => (currentRowType.value > props.defaultOpen))
+// const underAndEqual = computed(() => (currentRowType.value <= props.defaultOpen))
 
 </script>
 <style lang="scss" scoped>
@@ -113,13 +286,15 @@ const underAndEqual = computed(() => (currentRowType.value <= props.defaultOpen)
   color: var(--v-primary-base);
 }
 span {
+  span { cursor: pointer; }
   cursor: pointer;
   &:hover {
-    color: var(--v-primary-lighten1);
+    color: var(--v-primary-lighten2);
   }
 }
 .embedded {
-  padding: 4px 12px;
+  padding: 4px;
   background-color: #f8f8f8;
+  border-radius: 5px;
 }
 </style>

+ 5 - 1
src/views/recruit/position/components/cityFilter.vue

@@ -5,7 +5,7 @@
       </v-tabs>
       <v-window v-model="tab" class="mt-3">
         <v-window-item :value="1">
-          <areaTree></areaTree>
+          <areaTree @input="inputChange"></areaTree>
         </v-window-item>
       </v-window>
     </div>
@@ -16,6 +16,10 @@ import { ref } from 'vue'
 
 defineOptions({name: 'retrieval-components-cityFilter'})
 const tab = ref(1)
+const inputChange = (idChecked) => {
+  console.log('idChecked', idChecked)
+
+}
 const tabClick = () => {
 }
 </script>

+ 16 - 14
src/views/recruit/position/index.vue

@@ -10,8 +10,9 @@
       <conditionFilter class="mx-5 mb-3"></conditionFilter>
     </v-card>
     <div class="d-flex mt-3">
-      <div class="mr-3">
-        <PositionLongStrip :items="items"></PositionLongStrip>
+      <div class="mr-3" style="min-width: 884px;">
+        <div v-if="!items?.length" style="text-align: center;">暂无数据</div>
+        <PositionLongStrip v-else :items="items"></PositionLongStrip>
       </div>
       <rightRecommend></rightRecommend>
     </div>
@@ -91,23 +92,24 @@ const test = {
 const getPositionList = async () => {
   const pageReqVO = {
     ...pageInfo,
-    content: '', // 搜索内容,示例值(xx科技/xx经理)
-    areaIds: [], //工作地区id集合,示例值([])
-    expType: 0, // 工作经验(menduner_exp_type),示例值(1)
-    eduType: 0, // 	学历要求(menduner_education_type),示例值(1)
-    payType: 0, // 薪酬待遇范围(menduner_pay_scope),示例值(12)
-    jobType: 0, // 求职类型(menduner_job_type),示例值(2)
-    positionId: 0, // 职位类型,示例值(2)
-    enterpriseType: 0, // 企业类型(menduner_enterprise_type)
-    industryIds: [], // 行业信息id集合,示例值([])
-    scale: 0, // 人员规模(0-20人,20-99人)示例值(1)
-    financingStatus: 0 // 融资阶段(未融资,天使轮,A轮,不需要融资),示例值(1)
+    // content: '', // 搜索内容,示例值(xx科技/xx经理)
+    // areaIds: [], //工作地区id集合,示例值([])
+    // expType: 0, // 工作经验(menduner_exp_type),示例值(1)
+    // eduType: 0, // 	学历要求(menduner_education_type),示例值(1)
+    // payType: 0, // 薪酬待遇范围(menduner_pay_scope),示例值(12)
+    // jobType: 0, // 求职类型(menduner_job_type),示例值(2)
+    // positionId: 0, // 职位类型,示例值(2)
+    // enterpriseType: 0, // 企业类型(menduner_enterprise_type)
+    // industryIds: [], // 行业信息id集合,示例值([])
+    // scale: 0, // 人员规模(0-20人,20-99人)示例值(1)
+    // financingStatus: 0 // 融资阶段(未融资,天使轮,A轮,不需要融资),示例值(1)
   }
-  const res = await getJobAdvertisedSearch({ ...pageReqVO })
+  const res = await getJobAdvertisedSearch(pageReqVO)
   // items.value = res.list
   items.value = [...res.list, test]
   total.value = res.total
 }
+// items.value = [test]
 getPositionList()
 
 const handleChangePage = (index) => {