Browse Source

招聘会

Xiao_123 3 months ago
parent
commit
3cda9a8d98

+ 9 - 0
src/api/recruit/personal/jobFair.js

@@ -0,0 +1,9 @@
+import request from '@/config/axios'
+
+// 招聘会企业分页查询
+export const getJobFairEnterprisePage = async (params) => {
+	return await request.get({
+		url: '/app-api/menduner/system/job-fair/enterprise/page',
+		params
+	})
+}

+ 8 - 0
src/router/modules/recruit.js

@@ -189,6 +189,14 @@ const recruit = [
         meta: {
           title: '在招职位'
         }
+      },
+      {
+        path: '/recruit/personal/jobFair/entDetails/:id',
+        component: () => import('@/views/recruit/personal/jobFair/position/index.vue'),
+        name: 'jobFairEntDetails',
+        meta: {
+          title: '招聘会详情'
+        }
       }
     ]
   },

+ 0 - 1
src/views/recruit/personal/companyDetail/components/positions.vue

@@ -47,7 +47,6 @@
                 <v-icon color="var(--color-666)" size="15">{{ k.mdi }}</v-icon>
                 <span class="ml-1 tag-text">
                   {{ k.value === 'areaName' ? !val.job.areaId ? '全国' : val.job.area?.str : val.job[k.value] }}
-                  <!-- {{ (k.value === 'areaName' && !val.job.areaId) ? '全国' : val.job[k.value] }} -->
                 </span>
               </span>
             </span>

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

@@ -69,7 +69,7 @@ const list = ref([
 
 const handleJoin = (val) => {
 	if (!val?.id) return
-	const path = '/recruit/personal/jobFair/details/' + val.id
+	const path = '/recruit/personal/jobFair/entDetails/' + val.id
 	// 面包屑储存
 	let text = val.title ? val.title.replace(/<[^>]+>/g, ' ') : '' // 去掉所有 HTML 标签
 	text = text ? text.replace(/\s+/g, ' ').trim() : '' // 去掉多余的空格

+ 55 - 0
src/views/recruit/personal/jobFair/position/components/entCard.vue

@@ -0,0 +1,55 @@
+<template>
+	<v-hover v-slot="{ isHovering, props }" v-for="(val, index) in list" :key="val.id">
+		<v-card v-bind="props" :elevation="isHovering ? 7 : 3" class="cursor-pointer mb-3" :class="{'active': chosenIndex === index}" width="500" @click="handleClickEnterprise(val, index)">
+			<div class="d-flex pa-4 pb-2">
+				<img :src="val.enterprise.logoUrl" style="width: 80px; height: 80px; border-radius: 4px;" />
+				<div style="max-width: 390px;">
+					<h3 v-ellipse-tooltip class="enterprise-name ml-3">{{ formatName(val.enterprise.name) }}</h3>
+					<p class="font-size-14 color-666 mt-1 mb-2 ml-3">{{ val.enterprise.industryName }}</p>
+					<div class="flex-nowrap overflow-hidden pl-3" style="height: 35px;">
+						<!-- <v-hover v-slot="{ isHovering, props }" v-for="(job, index) in val.lastJobTop5" :key="index">
+							<v-chip v-bind="props" :class="isHovering ? 'elevation-5' : 'elevation-1'" class="mr-2 mb-4 display-inline-block" variant="flat" color="primary" size="small">{{ formatName(job.name) }}</v-chip>
+						</v-hover> -->
+						<v-chip v-for="(job, index) in val.lastJobTop5" :key="index" class="mr-2 mb-4 display-inline-block" variant="flat" color="primary" size="small">
+							{{ formatName(job.name) }}
+						</v-chip>
+					</div>
+				</div>
+			</div>
+			<div class="card-bottom">{{ val.jobCount }}个在线职位招聘中</div>
+		</v-card>
+	</v-hover>
+</template>
+
+<script setup>
+defineOptions({ name: 'jobFairDetails' })
+import { formatName } from '@/utils/getText'
+import { ref } from 'vue'
+
+const emit = defineEmits(['selectChange'])
+defineProps({
+	list: Array
+})
+
+const chosenIndex = ref(0)
+
+const handleClickEnterprise = (val, index) => {
+	chosenIndex.value = index
+	emit('selectChange', val)
+}
+</script>
+
+<style scoped lang="scss">
+.card-bottom {
+	height: 40px;
+	line-height: 40px;
+	color: #fff;
+	text-align: center;
+	font-size: 15px;
+	background: linear-gradient(to right, #12ebb0, #427daa);
+}
+
+.active {
+	border: 1px solid var(--v-primary-base);
+}
+</style>

+ 118 - 0
src/views/recruit/personal/jobFair/position/components/jobCard.vue

@@ -0,0 +1,118 @@
+<template>
+	<div class="resume-header mb-2">
+    <div class="resume-title">{{ enterpriseName }}</div>
+  </div>
+	<div v-if="items.length > 0" v-loading="loading">
+		<v-hover v-slot="{ isHovering, props }" v-for="val in items" :key="val.job.id">
+			<v-card  class="cursor-pointer mb-3 pa-3" v-bind="props" :elevation="isHovering ? 7 : 3" @click="handleClick(val.job.id)">
+				<div class="d-flex justify-space-between">
+					<p class="job-name" v-ellipse-tooltip>{{ formatName(val.job.name) }}</p>
+					<p v-if="!val.job.payFrom && !val.job.payTo" class="salary">面议</p>
+					<p v-else class="salary ml-3">{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}{{ val.job.payName ? '/' + val.job.payName : '' }}</p>
+				</div>
+				<div class="d-flex justify-space-between mt-3">
+					<div class="color-666 font-size-14">
+						<span v-for="k in desc" :key="k.mdi">
+							<span v-if="val.job[k.value] || k.value === 'areaName'" class="mr-5">
+								<v-icon color="var(--color-666)" size="15">{{ k.mdi }}</v-icon>
+								<span class="ml-1 tag-text">
+									{{ k.value === 'areaName' ? !val.job.areaId ? '全国' : val.job.area?.str : val.job[k.value] }}
+								</span>
+							</span>
+						</span>
+					</div>
+					<div class="font-size-14 color-999">{{ timesTampChange(val.job.updateTime) }} 刷新</div>
+				</div>
+			</v-card>
+		</v-hover>
+		<CtPagination
+      :total="total"
+      :page="query.pageNo"
+      :limit="query.pageSize"
+      @handleChange="handleChangePage"
+    ></CtPagination>
+	</div>
+	<Empty v-else :elevation="false" message="该企业暂无在招职位,换个企业试试吧"></Empty>
+</template>
+
+<script setup>
+defineOptions({ name: 'jobFairDetails' })
+import { ref, watch, reactive } from 'vue'
+import { formatName } from '@/utils/getText'
+import { useRouter, useRoute } from 'vue-router'; const router = useRouter(); const route = useRoute()
+import { getJobAdvertisedSearch } from '@/api/position'
+import { dealDictObjData } from '@/utils/position'
+import { timesTampChange } from '@/utils/date'
+
+const props = defineProps({
+	enterpriseId: [String, Number],
+	enterpriseName: String
+})
+
+const loading = ref(false)
+const items = ref([])
+const query = reactive({
+	pageNo: 1,
+	pageSize: 10
+})
+const total = ref(0)
+// 城市、学历、工作经验
+const desc = [
+  { mdi: 'mdi-map-marker-outline', value: 'areaName' },
+  { mdi: 'mdi-school-outline', value: 'eduName' },
+  { mdi: 'mdi-clock-time-ten-outline', value: 'expName' }
+]
+
+const getPositionList = async () => {
+	loading.value = true
+	try {
+		const { list, total: number } = await getJobAdvertisedSearch(query)
+		if (!list || !list.length) {
+			items.value = []
+			total.value = 0
+			return
+		}
+		total.value = number
+		items.value = list.map(e => {
+			e.job = dealDictObjData({}, e.job)
+			return e
+		})
+		loading.value = false
+	} catch {}
+}
+
+const handleChangePage = (index) => {
+  query.pageNo = index
+  getPositionList()
+}
+
+watch(
+	() => props.enterpriseId,
+	(val) => {
+		query.enterpriseId = '158258417071427584'
+		getPositionList()
+	},
+	{ immediate: true }
+)
+
+const handleClick = (id) => {
+	window.open(`/recruit/personal/position/details/${id}`)
+}
+</script>
+
+<style scoped lang="scss">
+.salary {
+	color: #cec149;
+	font-weight: 700;
+}
+.job-name {
+	color: #345768;
+	font-weight: 700;
+	max-width: 420px;
+}
+.v-card:hover {
+	.job-name {
+		color: var(--v-primary-base)
+	}
+}
+</style>

+ 254 - 0
src/views/recruit/personal/jobFair/position/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <div class="default-width">
+    <div style="background-color: #fff; position: sticky;" class="pb-4">
+      <buttons :current="3"></buttons>
+			<v-breadcrumbs v-if="breadcrumbs?.length" :items="breadcrumbs">
+				<template v-slot:item="{ item, index }">
+					<span class="breadcrumbsText" :class="{ active: !item.disabled && index !== breadcrumbs.length-1 }" @click="breadcrumbsClickDeal({ e: item, breadcrumbs, index })">{{ item.text }}</span>
+				</template>
+			</v-breadcrumbs>
+			<headSearch v-model="content" placeholder="搜索公司关键字" @handleSearch="handleSearch"></headSearch>
+    </div>
+    <Empty v-if="!items.length" :message="loadingType === 1 ? loadingText[loadingType] : '该招聘会暂无企业参与,前往其他招聘会看看吧~'" class="mt-3 py-15"></Empty>
+    <template v-else>
+      <div class="d-flex">
+        <div class="mt-3">
+          <EntCard :list="items" @selectChange="selectChange" />
+          <div class="loading defaultLink-i" @click="handleLoadMore">查看更多</div>
+          <div v-if="showLoadingMore" :class="['loading', {'defaultLink-i': !loadingType}]" @click="handleChangePage">{{ loadingText[loadingType] }}</div>
+        </div>
+        <div class="position-details ml-3" style="flex: 1; overflow: hidden;">
+          <div class="position-content pa-3">
+						<JobCard :enterpriseId="enterpriseId" :enterpriseName="enterpriseName" />
+          </div>
+        </div>
+      </div>
+    </template>
+  </div>
+
+</template>
+
+<script setup>
+defineOptions({ name: 'personalPositionRecommend'})
+import buttons from '@/views/recruit/personal/components/buttons.vue'
+import { ref, reactive } from 'vue'
+import { getJobFairEnterprisePage } from '@/api/recruit/personal/jobFair'
+
+import EntCard from './components/entCard.vue'
+import JobCard from './components/jobCard.vue'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { breadcrumbsClickDeal, getJobFairBreadcrumbs } from '@/utils/index'
+import { formatName } from '@/utils/getText'
+
+const showLoadingMore = ref(false)
+const breadcrumbs = ref(getJobFairBreadcrumbs(route?.query) || [])
+
+// 切换企业选中
+const enterpriseId = ref('')
+const enterpriseName = ref('')
+const selectChange = (val) => {
+	enterpriseId.value = val.enterprise.id
+	enterpriseName.value = formatName(val.enterprise.anotherName || val.enterprise.name)
+}
+
+const total = ref(0)
+const content = ref('')
+const query = reactive({
+  pageNo: 1,
+  pageSize: 10,
+	jobFairId: route.params.id
+})
+
+const items = ref([
+	// {
+	// 	"jobFairId": 1,
+	// 	"enterprise": {
+	// 			"id": "158258417071427584",
+	// 			"name": "苏州希尔顿酒店",
+	// 			"anotherName": "苏州希尔顿酒店",
+	// 			"website": "http://ilovechao.com/",
+	// 			"introduce": "CHAO\r\nCreate the Good Life Together\r\n品质生活发生地\r\n\r\n\r\nThrough all that we do, we want to attract and connect like-minded people to join our community, to discover, share and create a meaningful life and create the good life together.\r\n\r\nWe’ve created a series of venues and services to support every context of living the Good Life: work and leisure, recreation and socializing, travel and living, art and cultural discovery.\r\n\r\nCHAO,一个关于品质生活各种可能性的发生地。拥有酒店、会员及会员俱乐部、艺术中心,并通过独立媒体平台创造和分享优质的生活体验,同时推出品位卓越的生活方式产品。我们希望聚集趣味相投的高知人群,与CHAO共创品质生活。\r\n\r\n \r\n\r\nCHAO SANLITUN\r\n三里屯新地标\r\n\r\nLaunched at the end of 2016, our flagship property in the Sanlitun district of Beijing features a 180-room hotel, a 15,000m2 Clubhouse space with 2 F&B outlets as well as a 3000m2 Art Center featuring the city's most exciting exhibitions and events.\r\n\r\nCHAO was created to be a nesting place for our community of members and guests, providing them the opportunity to come together and share ideas, to build things together, to help each other developm",
+	// 			"contact": " 王东媛",
+	// 			"phone": "18618488218",
+	// 			"logoUrl": "https://www.mendunerhr.com/images/1572837192000_158258417071427584_mini.jpg",
+	// 			"industryId": null,
+	// 			"industryName": null,
+	// 			"financingStatus": null,
+	// 			"scale": null,
+	// 			"scaleName": null,
+	// 			"welfareList": null,
+	// 			"tagList": null,
+	// 			"vipFlag": null
+	// 	},
+	// 	"lastJobTop5": [
+	// 			{"name": "管理实习生-人力资源方向 Management Intern - HR"},
+	// 			{"name": "财务文员 Finance Clerk"},
+	// 			{"name": "财务实习生 Finance Intern"},
+	// 			{"name": "品牌部实习生 Brand & Communication Intern"},
+	// 			{"name": "市场销售实习生 Sales & Marketing Intern"}
+	// 	],
+	// 	"jobCount": 2
+	// },
+	// {
+	// 	"jobFairId": 1,
+	// 	"enterprise": {
+	// 			"id": "158258417071427584",
+	// 			"name": "天津生态城世茂希尔顿酒店",
+	// 			"anotherName": "天津生态城世茂希尔顿酒店",
+	// 			"website": "http://ilovechao.com/",
+	// 			"introduce": "CHAO\r\nCreate the Good Life Together\r\n品质生活发生地\r\n\r\n\r\nThrough all that we do, we want to attract and connect like-minded people to join our community, to discover, share and create a meaningful life and create the good life together.\r\n\r\nWe’ve created a series of venues and services to support every context of living the Good Life: work and leisure, recreation and socializing, travel and living, art and cultural discovery.\r\n\r\nCHAO,一个关于品质生活各种可能性的发生地。拥有酒店、会员及会员俱乐部、艺术中心,并通过独立媒体平台创造和分享优质的生活体验,同时推出品位卓越的生活方式产品。我们希望聚集趣味相投的高知人群,与CHAO共创品质生活。\r\n\r\n \r\n\r\nCHAO SANLITUN\r\n三里屯新地标\r\n\r\nLaunched at the end of 2016, our flagship property in the Sanlitun district of Beijing features a 180-room hotel, a 15,000m2 Clubhouse space with 2 F&B outlets as well as a 3000m2 Art Center featuring the city's most exciting exhibitions and events.\r\n\r\nCHAO was created to be a nesting place for our community of members and guests, providing them the opportunity to come together and share ideas, to build things together, to help each other developm",
+	// 			"contact": " 王东媛",
+	// 			"phone": "18618488218",
+	// 			"logoUrl": "https://www.mendunerhr.com/images/1572837192000_158258417071427584_mini.jpg",
+	// 			"industryId": null,
+	// 			"industryName": null,
+	// 			"financingStatus": null,
+	// 			"scale": null,
+	// 			"scaleName": null,
+	// 			"welfareList": null,
+	// 			"tagList": null,
+	// 			"vipFlag": null
+	// 	},
+	// 	"lastJobTop5": [
+	// 			{"name": "行政总厨"},
+	// 			{"name": "销售经理"},
+	// 			{"name": "实习厨师"}
+	// 	],
+	// 	"jobCount": 3
+	// },
+	// {
+	// 		"jobFairId": 1,
+	// 		"enterprise": {
+	// 				"id": "158258417071427584",
+	// 				"name": "济南鲁能希尔顿酒店及公寓",
+	// 				"anotherName": "济南鲁能希尔顿酒店及公寓",
+	// 				"website": "http://ilovechao.com/",
+	// 				"introduce": "CHAO\r\nCreate the Good Life Together\r\n品质生活发生地\r\n\r\n\r\nThrough all that we do, we want to attract and connect like-minded people to join our community, to discover, share and create a meaningful life and create the good life together.\r\n\r\nWe’ve created a series of venues and services to support every context of living the Good Life: work and leisure, recreation and socializing, travel and living, art and cultural discovery.\r\n\r\nCHAO,一个关于品质生活各种可能性的发生地。拥有酒店、会员及会员俱乐部、艺术中心,并通过独立媒体平台创造和分享优质的生活体验,同时推出品位卓越的生活方式产品。我们希望聚集趣味相投的高知人群,与CHAO共创品质生活。\r\n\r\n \r\n\r\nCHAO SANLITUN\r\n三里屯新地标\r\n\r\nLaunched at the end of 2016, our flagship property in the Sanlitun district of Beijing features a 180-room hotel, a 15,000m2 Clubhouse space with 2 F&B outlets as well as a 3000m2 Art Center featuring the city's most exciting exhibitions and events.\r\n\r\nCHAO was created to be a nesting place for our community of members and guests, providing them the opportunity to come together and share ideas, to build things together, to help each other developm",
+	// 				"contact": " 王东媛",
+	// 				"phone": "18618488218",
+	// 				"logoUrl": "https://www.mendunerhr.com/images/1572837192000_158258417071427584_mini.jpg",
+	// 				"industryId": null,
+	// 				"industryName": null,
+	// 				"financingStatus": null,
+	// 				"scale": null,
+	// 				"scaleName": null,
+	// 				"welfareList": null,
+	// 				"tagList": null,
+	// 				"vipFlag": null
+	// 		},
+	// 		"lastJobTop5": [
+	// 				{"name": "行政总厨"},
+	// 				{"name": "销售经理"},
+	// 				{"name": "实习厨师"}
+	// 		],
+	// 		"jobCount": 6
+	// },
+	// {
+	// 	"jobFairId": 1,
+	// 	"enterprise": {
+	// 			"id": "158258417071427584",
+	// 			"name": "苏州华贸姑苏里服务公寓",
+	// 			"anotherName": "苏州华贸姑苏里服务公寓",
+	// 			"website": "http://ilovechao.com/",
+	// 			"introduce": "CHAO\r\nCreate the Good Life Together\r\n品质生活发生地\r\n\r\n\r\nThrough all that we do, we want to attract and connect like-minded people to join our community, to discover, share and create a meaningful life and create the good life together.\r\n\r\nWe’ve created a series of venues and services to support every context of living the Good Life: work and leisure, recreation and socializing, travel and living, art and cultural discovery.\r\n\r\nCHAO,一个关于品质生活各种可能性的发生地。拥有酒店、会员及会员俱乐部、艺术中心,并通过独立媒体平台创造和分享优质的生活体验,同时推出品位卓越的生活方式产品。我们希望聚集趣味相投的高知人群,与CHAO共创品质生活。\r\n\r\n \r\n\r\nCHAO SANLITUN\r\n三里屯新地标\r\n\r\nLaunched at the end of 2016, our flagship property in the Sanlitun district of Beijing features a 180-room hotel, a 15,000m2 Clubhouse space with 2 F&B outlets as well as a 3000m2 Art Center featuring the city's most exciting exhibitions and events.\r\n\r\nCHAO was created to be a nesting place for our community of members and guests, providing them the opportunity to come together and share ideas, to build things together, to help each other developm",
+	// 			"contact": " 王东媛",
+	// 			"phone": "18618488218",
+	// 			"logoUrl": "https://www.mendunerhr.com/images/1572837192000_158258417071427584_mini.jpg",
+	// 			"industryId": null,
+	// 			"industryName": null,
+	// 			"financingStatus": null,
+	// 			"scale": null,
+	// 			"scaleName": null,
+	// 			"welfareList": null,
+	// 			"tagList": null,
+	// 			"vipFlag": null
+	// 	},
+	// 	"lastJobTop5": [
+	// 			{"name": "行政总厨"},
+	// 			{"name": "销售经理"},
+	// 			{"name": "实习厨师"}
+	// 	],
+	// 	"jobCount": 1
+	// }
+])
+const loadingText = ['加载更多', '加载中...', '没有更多数据了']
+const loadingType = ref(0)
+
+// 参与招聘会的企业
+const getList = async () => {
+	loadingType.value = 1
+	try {
+		const { list, total } = await getJobFairEnterprisePage(query)
+		console.log(list, '企业列表')
+		if (list.length) {
+			items.value = items.value.concat(list)
+			loadingType.value = list.length  === query.pageSize ? 0 : 2
+			enterpriseId.value = items.value[0].enterprise.id
+			enterpriseName.value = formatName(items.value[0].enterprise.anotherName || items.value[0].enterprise.name)
+			getPositionList()
+		} else {
+			loadingType.value = 2
+		}
+	} catch {}
+}
+getList()
+
+const handleSearch = (val) => {}
+
+const handleChangePage = () => {
+  if (loadingType.value) return // 没有更多数据了
+  // 加载更多
+  query.pageNo++
+  getList()
+}
+
+const handleLoadMore = () => {
+
+}
+
+</script>
+
+<style scoped lang="scss">
+.position-details {
+  position: sticky;
+  top: 62px;
+  border-radius: 12px;
+  background-color: #fff;
+  margin-top: 12px;
+  height: calc(100vh - 127px);
+  widows: 100%;
+  overflow: hidden;
+  .position-content {
+    height: 100%;
+    width: 100%;
+    padding-right: 4px;
+    overflow-y: auto;
+  }
+}
+.loading {
+  margin-top: 8px;
+  text-align: center;
+  font-size: 13px;
+  color: gray;
+}
+.breadcrumbsText {
+  color: var(--color-999);
+  font-size: 15px;
+  &.active {
+    color: var(--v-primary-base);
+    cursor: pointer;
+  }
+}
+::-webkit-scrollbar {
+  width: 4px;
+  height: 10px;
+}
+::-webkit-scrollbar-thumb, .temporaryAdd ::-webkit-scrollbar-thumb, .details_edit ::-webkit-scrollbar-thumb {
+  // 滚动条-颜色
+  background: #c3c3c379;
+}
+::-webkit-scrollbar-track, .temporaryAdd ::-webkit-scrollbar-track, .details_edit ::-webkit-scrollbar-track {
+  // 滚动条-底色
+  background: #e5e5e58f;
+}
+</style>