|
@@ -1,273 +0,0 @@
|
|
-<!-- 在招职位 -->
|
|
|
|
-<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="var(--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 v-if="!val.job.payFrom && !val.job.payTo" class="salary">面议</p>
|
|
|
|
- <p v-else class="salary">{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}{{ val.job.payName ? '/' + 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 '@/utils/position'
|
|
|
|
-import { getJobAdvertisedPositionCount, getJobAreaByEnterpriseId, getJobAdvertisedSearch } from '@/api/position'
|
|
|
|
-import MPagination from '@/components/CtPagination'
|
|
|
|
-import expType from '@/views/recruit/personal/position/components/conditionFilter/expType.vue'
|
|
|
|
-import educationType from '@/views/recruit/personal/position/components/conditionFilter/educationType.vue'
|
|
|
|
-import payScope from '@/views/recruit/personal/position/components/conditionFilter/payScope.vue'
|
|
|
|
-import areaType from '@/views/recruit/personal/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/personal/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: var(--v-error-base);
|
|
|
|
- line-height: 22px;
|
|
|
|
- flex: none;
|
|
|
|
-}
|
|
|
|
-.tag-text {
|
|
|
|
- color: var(--color-222);
|
|
|
|
- font-size: 14px;
|
|
|
|
-}
|
|
|
|
-.update-time {
|
|
|
|
- color: var(--color-666);
|
|
|
|
- font-size: 14px;
|
|
|
|
- line-height: 40px;
|
|
|
|
-}
|
|
|
|
-.account-info {
|
|
|
|
- line-height: 52px;
|
|
|
|
- .account-label {
|
|
|
|
- color: var(--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: var(--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>
|
|
|
|
-
|
|
|