Xiao_123 пре 3 месеци
родитељ
комит
02b97437c7

+ 2 - 1
src/components/FormUI/autocomplete/index.vue

@@ -20,6 +20,7 @@
       :hide-no-data="item.hideNoData"
       :no-data-text="item.noDataText || 'No data available'"
       :hide-selected="item.hideSelected"
+      :return-object="item.returnObject || false"
       :hide-details="item.hideDetails || false"
       @update:search="v => item.search ? debouncedCallbackSearch(v) : null"
       @update:modelValue="modelValueUpDate"
@@ -31,7 +32,7 @@ import { debounce } from 'lodash'
 import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-autocomplete'})
 
-const props = defineProps({item: Object, modelValue: [String, Array, Number, Boolean]})
+const props = defineProps({item: Object, modelValue: [String, Array, Number, Boolean, Object]})
 
 const value = ref()
 watch(

+ 9 - 0
src/views/recruit/enterprise/jobFair/job/item.vue

@@ -20,6 +20,10 @@
               <span>{{ val.positionName }}</span>
             </div>
           </div>
+          <div class="text-center color-primary d-flex flex-column justify-center cursor-pointer" @click="handleToResume(val)">
+            <div class="font-weight-bold font-size-18">{{ val.count || 0 }}</div>
+            <div class="font-size-14">已投递简历</div>
+          </div>
         </div>
         <div class="bottom pa-5 d-flex justify-space-between align-center">
           <div>到期时间:{{ val.expireTime ? timesTampChange(val.expireTime, 'Y-M-D') : '长期有效' }}</div>
@@ -76,6 +80,11 @@ const handleRemove = ({ id }) => {
   })
   
 }
+
+// 查看职位投递简历
+const handleToResume = (val) => {
+  router.push(`/recruit/enterprise/invite/resume?id=${val.id}&jobFairId=${route.params.id}`)
+}
 </script>
 
 <style scoped lang="scss">

+ 177 - 0
src/views/recruit/enterprise/resume/components/filterPage.vue

@@ -0,0 +1,177 @@
+<template>
+	<div class="pa-5">
+		<h3 style="color: var(--v-primary-base);">条件筛选</h3>
+		<v-divider class="my-5"></v-divider>
+		<CtForm :items="formItems"></CtForm>
+		<div class="bottom">
+      <v-divider></v-divider>
+      <div class="d-flex justify-space-between mt-3">
+        <div class="ml-3">
+          <v-btn class="half-button mr-3" color="primary" @click="confirm">筛选</v-btn>
+          <v-btn class="half-button mr-3" variant="tonal" @click="emit('cancel')">取消</v-btn>
+        </div>
+        <v-btn class="half-button ml-3" variant="tonal" color="orange" @click="handleReset(true)">重置</v-btn>
+      </div>
+    </div>
+	</div>
+</template>
+
+<script setup>
+defineOptions({ name: 'filterPage'})
+import { ref, onMounted } from 'vue'
+import { getJobAdvertised } from '@/api/enterprise'
+import { getDict } from '@/hooks/web/useDictionaries'
+import { dealDictArrayData } from '@/utils/position'
+import { formatName } from '@/utils/getText'
+import Snackbar from '@/plugins/snackbar'
+import { getJobFairList } from '@/api/recruit/enterprise/jobFair'
+
+const emit = defineEmits(['confirm', 'cancel', 'reset'])
+const props = defineProps({ jobId: [String, Number], jobFairId: [String, Number] })
+
+const formItems = ref({
+  options: [
+    {
+      type: 'autocomplete',
+      key: 'jobId',
+      value: null,
+      label: '投递职位',
+      itemText: 'label',
+      itemValue: 'value',
+			clearable: true,
+			returnObject: true,
+      items: []
+    },
+		{
+      type: 'autocomplete',
+      key: 'jobFairId',
+      value: null,
+      label: '招聘会',
+      itemText: 'label',
+      itemValue: 'value',
+			clearable: true,
+			returnObject: true,
+      items: []
+    },
+		{
+      type: 'autocomplete',
+      key: 'eduType',
+      value: null,
+      label: '最高学历',
+      itemText: 'label',
+      itemValue: 'value',
+			clearable: true,
+			dictTypeName: 'menduner_education_type',
+			returnObject: true,
+			col: 6,
+      items: []
+    },
+		{
+      type: 'autocomplete',
+      key: 'expType',
+      value: null,
+      label: '工作经验',
+      itemText: 'label',
+      itemValue: 'value',
+			dictTypeName: 'menduner_exp_type',
+			returnObject: true,
+			col: 6,
+			flexStyle: 'ml-3',
+			clearable: true,
+      items: []
+    },
+		{
+      type: 'autocomplete',
+      key: 'jobStatus',
+      value: null,
+      label: '求职状态',
+      itemText: 'label',
+      itemValue: 'value',
+			dictTypeName: 'menduner_job_seek_status',
+			returnObject: true,
+			clearable: true,
+			col: 6,
+      items: []
+    }
+  ]
+})
+
+const confirm = () => {
+	const params = {}
+	const data = []
+	formItems.value.options.forEach(k => {
+		if (k.value) {
+			params[k.key] = k.value[k.itemValue]
+			data.push({ ...k.value, title: k.label, key: k.key })
+		}
+	})
+	if (!Object.keys(params).length) return Snackbar.warning('请选择筛选条件')
+
+	emit('confirm', params, data)
+}
+
+const handleReset = (close) => {
+	formItems.value.options.forEach(k => k.value = null)
+	emit('reset', close)
+}
+
+const handleClear = (item) => {
+	formItems.value.options.find(e => e.key === item.key).value = null
+}
+
+onMounted(() => {
+	formItems.value.options.forEach(async (k) => {
+		// 字典数据获取
+		if (k.dictTypeName) {
+			getDict(k.dictTypeName).then(({ data }) => {
+				data = data?.length && data || []
+				k.items = data
+			})
+			return
+		}
+		// 招聘会数据获取
+		if (k.key === 'jobFairId') {
+			const data = await getJobFairList()
+			k.items = data.map(e => {
+				return { label: e.title.replace(/<\/?p[^>]*>/gi, ''), value: e.id }
+			})
+			if (props.jobFairId) {
+				k.value = k.items.find(e => e.value.toString() === props.jobFairId)
+			}
+			return
+		}
+
+		// 投递职位
+		const data = await getJobAdvertised()
+		if (!data || !data.length) return
+		const list = dealDictArrayData([], data)
+		k.items = list.map(e => {
+			const salary = e.payFrom && e.payTo ? `${e.payFrom}-${e.payTo}${e.payName ? '/' + e.payName : ''}` : '面议'
+			return { label: `${formatName(e.name)}_${e.areaName ? e.area?.str : '全国'} ${salary}_${e.status === '0' ? '招聘中' : '已关闭'}`, value: e.id, isJobFair: e.source === '2' && e.bizId }
+		})
+
+		// 传入jobId,默认选中
+		if (props.jobId) {
+			k.value = k.items.find(e => e.value === props.jobId)
+			confirm()
+		}
+	})
+})
+
+defineExpose({
+	handleClear,
+	handleReset
+})
+</script>
+
+<style scoped lang="scss">
+.bottom {
+  position: fixed;
+  width: 96%;
+  margin: 0 12px;
+  bottom: 0;
+  left: 0;
+  padding-bottom: 14px;
+  background-color: #fff;
+}
+</style>

+ 73 - 24
src/views/recruit/enterprise/resume/index.vue

@@ -1,21 +1,38 @@
 <!-- 精英管理 -->
 <template>
   <v-card class="pa-3 card-box">
-    <div class="d-flex justify-space-between">
+    <div class="d-flex justify-space-between mb-3">
       <v-tabs v-model="tab" align-tabs="start" color="primary" bg-color="#f7f8fa" @update:model-value="handleChangeTab">
         <v-tab v-for="k in tabList" :value="k.value" :key="k.value">{{ k.label }}</v-tab>
       </v-tabs>
-      <TextInput v-model="textItems.value" :item="textItems" @appendInnerClick="handleSearch" @enter="handleSearch"></TextInput>
+      <div class="d-flex align-center">
+        <TextInput v-model="textItems.value" :item="textItems" @appendInnerClick="handleSearch" @enter="handleSearch"></TextInput>
+        <v-btn color="primary" prependIcon="mdi-filter-multiple-outline" class="ml-3" variant="tonal" @click="showDrawer = true">筛选{{ rawData.length > 0 ? rawData.length : '' }}</v-btn>
+      </div>
     </div>
-    <Screen
-     :tab="tab" 
-     :jobId="router.currentRoute.value?.query?.id" 
-     :hire="router.currentRoute.value?.query?.hire"
-      @search="handleScreen"
-      @reset="handleScreenReset"
-      @select="handleSelect"
-      @change="handleChangeBounty"
-    ></Screen>
+
+    <div class="d-flex justify-space-between align-center mb-3" v-if="tab === 0">
+      <div class="mr-5 d-flex align-center">
+        <v-radio-group v-model="bounty" inline style="height: 28px;" @update:modelValue="handleChangeBounty">
+          <v-radio v-model="bounty" label="普通职位" :value="false" color="primary" hide-details density="compact" class="mr-3"></v-radio>
+          <v-radio v-model="bounty" label="赏金职位" :value="true" color="primary" hide-details density="compact"></v-radio>
+        </v-radio-group>
+
+        <v-radio-group class="ml-5" v-model="selected" inline style="height: 28px;" @update:modelValue="handleSelect">
+          <v-radio v-model="selected" label="新投递" value="0" color="primary" hide-details density="compact" class="mr-3"></v-radio>
+          <v-radio v-model="selected" label="已查看" value="1" color="primary" hide-details density="compact"></v-radio>
+        </v-radio-group>
+      </div>
+      <div class="color-primary font-size-14 cursor-pointer" @click="FilterPageRef.handleReset(false)">重置</div>
+    </div>
+    <div v-if="rawData && rawData.length > 0">
+      <v-chip v-for="item in rawData" :key="item.id" closable class="mr-2 mb-2" label @click:close="handleClose(item)">{{ item.title }}: {{ item.label }}</v-chip>
+    </div>
+
+    <!-- 筛选抽屉 -->
+    <v-navigation-drawer v-model="showDrawer" location="right" absolute temporary width="700">
+      <FilterPage ref="FilterPageRef" :jobId="route.query?.id" :jobFairId="route.query?.jobFairId" @confirm="handleConfirm" @cancel="showDrawer = false" @reset="handleScreenReset" />
+    </v-navigation-drawer>
 
     <v-window v-model="tab" class="mt-1">
       <v-window-item v-for="k in tabList" :value="k.value" :key="k.value">
@@ -27,18 +44,18 @@
 
 <script setup>
 defineOptions({ name: 'enterprise-elite-management'})
-import { ref } from 'vue'
+import { ref, onMounted } from 'vue'
 import { getPersonCvPage } from '@/api/enterprise'
 import { personCvUnfitPage } from '@/api/recruit/enterprise/personnel'
 import { dealDictObjData } from '@/utils/position'
 import { getDict } from '@/hooks/web/useDictionaries'
 import { getInterviewInvitePage } from '@/api/recruit/enterprise/interview'
 import TablePage from './components/table.vue'
-import Screen from './components/screen.vue'
 import { timesTampChange } from '@/utils/date'
-import { useRouter } from 'vue-router'
+import { useRoute } from 'vue-router'
+import FilterPage from './components/filterPage.vue'
 
-const router = useRouter()
+const route  = useRoute()
 const total = ref(0)
 const query = ref({
   pageNo: 1,
@@ -46,6 +63,10 @@ const query = ref({
   status: null,
   type: null
 })
+const selected = ref()
+const bounty = ref(null)
+const showDrawer = ref(false)
+const FilterPageRef = ref()
 const tab = ref(0)
 const tabList = ref([
   { label: '投递简历', value: 0, api: getPersonCvPage, status: null },
@@ -59,6 +80,7 @@ const textItems = ref({
   value: '',
   width: 250,
   label: '搜索姓名',
+  hideDetails: true,
   clearable: true,
   appendInnerIcon: 'mdi-magnify'
 })
@@ -96,7 +118,20 @@ const getList = async () => {
   })
 }
 // 没有带id时一进来才刷新,带id由组件传值刷新
-if (!router.currentRoute.value?.query?.id) getList()
+if (!route.query?.id) getList()
+
+onMounted(() => {
+  // 众聘职位
+  if (route.query?.hire) {
+    query.value.hire = true
+    bounty.value = true
+  }
+  // 招聘会职位
+  if (route.query?.jobFairId) {
+    if (tab.value !== 0) return delete query.value.jobFairId
+    query.value.jobFairId = route.query.jobFairId
+  }
+})
 
 // 分页
 const handleChangePage = (i) => {
@@ -112,16 +147,29 @@ const handleSearch = () => {
   getList()
 }
 
-// 下拉筛选
-const handleScreen = ({ value, key }) => {
-  if (value) query.value[key] = value
-  else delete query.value[key]
-  if (router.currentRoute.value?.query?.hire) query.value.hire = true
+// 筛选
+const rawData = ref([])
+const handleConfirm = (params, data) => {
+  rawData.value = data
+  query.value.pageNo = 1
+  query.value = Object.assign(query.value, params)
+  showDrawer.value = false
+  getList()
+}
+
+// 筛选条件单个清除
+const handleClose = (item) => {
+  FilterPageRef.value.handleClear(item)
+  delete query.value[item.key]
+  rawData.value = rawData.value.filter(e => e.key !== item.key)
   getList()
 }
 
-// 下拉筛选重置
-const handleScreenReset = () => {
+// 重置
+const handleScreenReset = (close) => {
+  rawData.value = []
+  bounty.value = ''
+  selected.value = ''
   query.value = {
     pageSize: 10,
     pageNo: 1,
@@ -131,10 +179,11 @@ const handleScreenReset = () => {
     query.value.status = null
     query.value.type = null
   }
-  textItems.value.value = ''
+  if (close) showDrawer.value = false
   getList()
 }
 
+// 职位类型选择
 const handleSelect = (e) => {
   query.value.pageNo = 1
   query.value.status = e