Prechádzať zdrojové kódy

公司信息展示-在招职位

lifanagju_citu 11 mesiacov pred
rodič
commit
bb7ef23150

+ 272 - 0
src/views/enterprise/enterpriseCenter/components/positions.vue

@@ -0,0 +1,272 @@
+<!-- 在招职位 -->
+<template>
+  <div class="top">
+    <div class="d-flex">
+      <div class="font-weight-bold position-category-left">职位类别:</div>
+      <div class="position-category-right">
+        <span 
+          :class="['category-item', {'default-active': k.active}, {'font-weight-bold': k.active}]" 
+          v-for="k in positionCategory" 
+          :key="k.id"
+          @click="handleClickCategory(k)"
+        >{{ k.id === -1 ? `${k.label}` : `${k.label} (${k.number})` }}</span>
+      </div>
+    </div>
+    <div class="d-flex mt-3">
+      <areaType v-if="areaList.length" :list="areaList" @inputChange="val => handleSearch('areaIds', val)"></areaType>
+      <expType :isSingle="true" @inputChange="val => handleSearch('expType', val)"></expType>
+      <educationType :isSingle="true" @inputChange="val => handleSearch('eduType', val)"></educationType>
+      <payScope @input-change="val => handleSearch('payType', val)"></payScope>
+      <div style="width: 300px;">
+        <v-text-field
+          v-model="query.content"
+          variant="outlined" 
+          label="查找职位关键字"
+          hide-details
+          color="primary"
+          append-inner-icon="mdi-magnify"
+          @click:append-inner="handleSearch('content', { values: query.content })"
+          @keyup.enter="handleSearch('content', { values: query.content })"
+        >
+        </v-text-field>
+      </div>
+    </div>
+  </div>
+  <v-divider class="mt-5"></v-divider>
+  <div class="bottom mt-4">
+    <div v-if="list.length">
+      <div 
+        v-for="(val, i) in list" 
+        :key="i" 
+        :class="['bottom-item', {'border-bottom-dashed': i !== list.length -1}, 'd-flex', 'justify-space-between', 'cursor-pointer']" 
+        @mouseenter="val.active = true"
+        @mouseleave="val.active = false"
+        @click="handlePosition(val)"
+      >
+        <div>
+          <p v-if="val.job.name.includes('style')" :class="['name', {'default-active': val.active }]" v-html="val.job.name"></p>
+          <p v-else :class="['name', {'default-active': val.active }]">{{ val.job.name }}</p>
+          <div style="line-height: 40px;">
+            <span v-for="k in desc" :key="k.mdi" class="mr-5">
+              <v-icon color="#666" size="15">{{ k.mdi }}</v-icon>
+              <span class="ml-1 tag-text">{{ val.job[k.value] }}</span>
+            </span>
+          </div>
+        </div>
+        <div v-if="!val.active" class="text-right">
+          <p class="salary">{{ val.job.payFrom }}-{{ val.job.payTo }}/{{ val.job.payName }}</p>
+          <div class="update-time">{{ timesTampChange(val.job.updateTime) }} 刷新</div>
+        </div>
+        <div v-else class="account-info">
+          <v-avatar :image="val.contact.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
+          <span class="account-label">{{ val.contact.name }} · {{ val.contact.postNameCn }}</span>
+          <span>
+            <v-btn class="half-button" color="primary" size="small">立即沟通</v-btn>
+          </span>
+        </div>
+      </div>
+      <MPagination
+        :total="total"
+        :page="pageInfo.pageNo"
+        :limit="pageInfo.pageSize"
+        @handleChange="handleChangePage"
+      ></MPagination>
+    </div>
+    <Empty v-else :elevation="false"></Empty>
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'enterprise-enterpriseCenter-positions'})
+import { reactive, ref, provide } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { timesTampChange } from '@/utils/date'
+import { getDict } from '@/hooks/web/useDictionaries'
+import { dealDictObjData } from '@/views/recruit/position/components/dict'
+import { getJobAdvertisedPositionCount, getJobAreaByEnterpriseId, getJobAdvertisedSearch } from '@/api/position'
+import MPagination from '@/components/CtPagination'
+import expType from '@/views/recruit/position/components/conditionFilter/expType.vue'
+import educationType from '@/views/recruit/position/components/conditionFilter/educationType.vue'
+import payScope from '@/views/recruit/position/components/conditionFilter/payScope.vue'
+import areaType from '@/views/recruit/position/components/conditionFilter/areaType.vue'
+
+const props = defineProps({
+  info: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const total = ref(0)
+const pageInfo = ref({
+  pageSize: 10,
+  pageNo: 1
+})
+let query = reactive({})
+const route = useRoute(); const router = useRouter()
+const routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? route.query : null
+if (routeQuery?.content) query.content = routeQuery?.content
+provide('routeQuery', routeQuery)
+if (routeQuery) query = routeQuery
+
+// 职位详情
+const handlePosition = (val) => {
+  window.open(`/recruit/position/details/${val.job.positionId}`)
+}
+
+// 行业列表
+const industryList = ref([])
+const getDictData = async () => {
+  const { data } = await getDict('menduner_industry_type', {}, 'industryList')
+  industryList.value = data
+}
+getDictData()
+
+// 职位类别&工作地点
+const positionCategory = ref([])
+const areaList = ref([])
+const getData = async () => {
+  const data = await getJobAdvertisedPositionCount({ enterpriseId: props.info.enterprise.id })
+  areaList.value = await getJobAreaByEnterpriseId({ enterpriseId: props.info.enterprise.id })
+  const list = data.map(val => {
+    const value = industryList.value.find(e => Number(e.id) === Number(val.key))
+    return { id: value.id, label: value.nameCn, number: val.value, active: false }
+  })
+  positionCategory.value = [{ id: -1, label: '全部', active: true }, ...list]
+}
+const getPoAr = async () => {
+  await getData()
+  // 职位类别回显
+  if (routeQuery?.positionId) {
+    positionCategory.value.map(e => e.active = false)
+    positionCategory.value.find(e => e.id === routeQuery.positionId).active = true
+  }
+}
+getPoAr()
+
+
+
+// 职位类别选中
+const handleClickCategory = (k) => {
+  positionCategory.value.map(e => e.active = false)
+  k.active = !k.active
+  handleSearch('positionId', { values: k.id })
+}
+
+const dealRouteQuery = () => {
+  const arr = Object.keys(query).map(e => {
+    if (Array.isArray(query[e]) && !query[e].length) {
+      delete query[e]
+    }
+    if (!query[e]) delete query[e]
+    if (e !== 'pageSize' && e !== 'pageNo' && e !== 'enterpriseId') return `${e}=${query[e]}`
+  }).filter(Boolean)
+  const str = ['key=recruitmentPositions', ...arr].join('&')
+  if (str) router.replace(`${route.path}?${str}`)
+}
+
+const handleSearch = (key, { values }) => {
+  if (values === -1 || !values || values[0] === -1 || !values.length) delete query[key]
+  else query[key] = values
+  dealRouteQuery()
+  getPositionList(true)
+}
+
+// 职位列表
+const list = ref([])
+// 职位列表
+const getPositionList = async (isSearch) => {
+  query = {
+    ...query,
+    ...pageInfo.value,
+    enterpriseId: props.info.enterprise.id
+  }
+  delete query.key
+  if (isSearch) query.pageNo = 1
+  const { list: arr, total: number } = await getJobAdvertisedSearch(query)
+  total.value = number
+  list.value = arr.map(e => {
+    e.active = false
+    e.job = { ...e.job, ...dealDictObjData({}, e.job) }
+    return e
+  })
+}
+getPositionList()
+
+const handleChangePage = (index) => {
+  pageInfo.value.pageNo = index
+  getPositionList()
+}
+
+// 城市、学历、工作经验
+const desc = [
+  { mdi: 'mdi-map-marker-outline', value: 'areaName' },
+  { mdi: 'mdi-school-outline', value: 'eduName' },
+  { mdi: 'mdi-clock-time-ten-outline', value: 'expName' }
+]
+</script>
+
+<style scoped lang="scss">
+.bottom-item {
+  width: 100%;
+  height: 68px;
+  margin-bottom: 12px;
+}
+.name {
+  position: relative;
+  max-width: 200px;
+  margin-right: 8px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  font-weight: 600;
+}
+.salary {
+  font-size: 16px;
+  font-weight: 700;
+  color: #fe574a;
+  line-height: 22px;
+  flex: none;
+}
+.tag-text {
+  color: #222;
+  font-size: 14px;
+}
+.update-time {
+  color: #666;
+  font-size: 14px;
+  line-height: 40px;
+}
+.account-info {
+  line-height: 52px;
+  .account-label {
+    color: #666;
+    font-size: 14px;
+    font-weight: 600;
+    margin: 0 10px;
+  }
+}
+.position-category-left {
+  width: 80px;
+}
+.position-category-right {
+  flex: 1;
+}
+.category-item {
+  display: inline-block;
+  margin-right: 20px;
+  font-size: 15px;
+  color: #666;
+  cursor: pointer;
+  &:hover {
+    color: var(--v-primary-base);
+  }
+}
+:deep(.v-field__input) {
+  height: 28px;
+  padding: 0 0 0 10px;
+  font-size: 12px;
+  min-height: 28px;
+}
+</style>
+