Browse Source

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

lifanagju_citu 2 months ago
parent
commit
09a25173fc

+ 1 - 1
src/components/FormUI/TextInput/index.vue

@@ -91,7 +91,7 @@ const appendInnerClick = () => {
 }
 
 const handleClear = () => {
-  emit('enter', value.value)
+  emit('enter', value.value, 'clear')
 }
 
 const handleKeyup = () => {

+ 15 - 60
src/router/modules/components/recruit/enterprise.js

@@ -376,81 +376,36 @@ const enterprise = [
     ]
   },
   {
-    path: '/recruit/enterprise/membershipPackage',
+    path: '/recruit/enterprise/talentMap',
     component: Layout,
-    name: 'membershipPackage',
+    name: 'TalentMap',
     meta: {
-      title: '会员套餐',
-      enName: 'Membership Benefits',
-      icon: 'mdi-wallet-membership'
+      title: '人才地图',
+      enName: 'Talent Map',
+      icon: 'mdi-map-marker-account-outline'
     },
     children: [
       {
-        path: '/recruit/enterprise/membershipPackage',
+        path: '/recruit/enterprise/talentMap',
         show: true,
-        component: () => import('@/views/recruit/enterprise/membershipPackage/index.vue')
+        component: () => import('@/views/recruit/enterprise/newTalentMap/search/index.vue')
       }
     ]
   },
-  // {
-  //   path: '/recruit/enterprise/newlyAppointed',
-  //   component: Layout,
-  //   name: 'Newly Appointed',
-  //   meta: {
-  //     title: '门墩儿新任命',
-  //     enName: 'Newly Appointed',
-  //     icon: 'mdi-new-box'
-  //   },
-  //   children: [
-  //     {
-  //       path: '/recruit/enterprise/newlyAppointed',
-  //       show: true,
-  //       component: () => import('@/views/recruit/enterprise/newlyAppointed/index.vue')
-  //     }
-  //   ]
-  // },
   {
+    path: '/recruit/enterprise/newlyAppointed',
     component: Layout,
-    path: '/recruit/enterprise/talentMap',
-    redirect: '/recruit/enterprise/talentMap/newlyAppointed',
-    name: 'TalentMap',
+    name: 'Newly Appointed',
     meta: {
-      title: '人才地图',
-      enName: 'Talent Map',
-      icon: 'mdi-map-marker-account-outline',
+      title: '门墩儿新任命',
+      enName: 'Newly Appointed',
+      icon: 'mdi-new-box'
     },
     children: [
       {
-        path: '/recruit/enterprise/talentMap/newlyAppointed',
-        meta: {
-          title:'门墩儿新任命',
-          enName: 'Newly Appointed'
-        },
-        component: () => import('@/views/recruit/enterprise/newTalentMap/newlyAppointed/index.vue')
-      },
-      {
-        path: '/recruit/enterprise/talentMap/search',
-        meta: {
-          title: '人才搜索',
-          enName: 'Talent Search'
-        },
-        component: () => import('@/views/recruit/enterprise/newTalentMap/search/index.vue')
-      },
-      {
-        path: '/recruit/enterprise/talentMap/labeling',
-        meta: {
-          title: '人才标注',
-          enName: 'Talent labeling '
-        },
-        component: () => import('@/views/recruit/enterprise/newTalentMap/labeling/index.vue')
-      },
-      {
-        path: '/recruit/enterprise/talentMap/tagManagement',
-        meta: {
-          title: '标签管理',
-          enName: 'Tag Management '
-        },
-        component: () => import('@/views/recruit/enterprise/newTalentMap/tag/index.vue')
+        path: '/recruit/enterprise/newlyAppointed',
+        show: true,
+        component: () => import('@/views/recruit/enterprise/newlyAppointed/index.vue')
       }
     ]
   },

+ 1 - 1
src/version.js

@@ -1,2 +1,2 @@
 // 版本号
-export const vue_version = 'v25.05.08.1531'
+export const vue_version = 'v25.05.16.1812'

+ 1 - 1
src/views/recruit/enterprise/newTalentMap/labeling/index.vue

@@ -121,7 +121,7 @@ const loading = ref(false)
 const showDialog = ref(false)
 const items = ref([])
 const headers = [
-  // { title: 'ID', key: 'id', sortable: false },
+  { title: 'ID', key: 'id', sortable: false },
   { title: '姓名', key: 'name_zh', sortable: false },
   // { title: '英文名', key: 'name_en', sortable: false },
   { title: '职位', key: 'title_zh', sortable: false },

+ 43 - 122
src/views/recruit/enterprise/newTalentMap/search/index.vue

@@ -1,15 +1,16 @@
 <template>
 	<div>
-		<v-card elevation="5" class="pa-10">
+		<v-card elevation="5" class="px-10 py-10 d-flex align-center" :height="items.length ? 'auto' : '300px'">
 			<TextInput
         v-model="content"
         :item="textItem"
         @enter="handleSearch"
         @appendInnerClick="handleSearch"
       ></TextInput>
+      <v-btn color="primary" width="100" class="ml-5" :loading="loading" @click="handleSearch">搜 索</v-btn>
 		</v-card>
 
-		<v-card elevation="5" class="mt-3">
+		<v-card v-if="items && items.length" elevation="5" class="mt-3">
 			<CtTable
 				:items="items"
 				class="pa-3"
@@ -18,7 +19,6 @@
 				:disable-sort="true"
 				:elevation="0"
 				:isTools="false"
-				:noDataText="!content ? '请先输入您的描述信息定位人才' : '暂无数据'"
 				:items-per-page="-1"
 				height="calc(100vh - 400px)"
 				:showFixedLastItem="true"
@@ -31,6 +31,11 @@
 		</v-card>
 
 		<v-navigation-drawer v-model="showDetail" absolute location="right" rounded temporary width="700" class="pa-5">
+      <!-- 名片 -->
+      <div v-if="previewUrl">
+        <div class="color-primary font-size-18 font-weight-bold">名片</div>
+		    <img width="100%" :src="previewUrl" />
+      </div>
       <!-- 基本信息 -->
       <baseInfo :data="detail"></baseInfo>
       <!-- 职业轨迹 -->
@@ -38,120 +43,28 @@
 		</v-navigation-drawer>
 	</div>
 
-	<Loading :visible="annotationLoading"></Loading>
+	<Loading :visible="detailLoading"></Loading>
 </template>
 
 <script setup>
 defineOptions({ name: 'NewTalentMapSearch' })
 import { ref } from 'vue'
 import { getTalentList, getBusinessCardDetails } from '@/api/recruit/enterprise/talentMap/search'
+import { getTalentCardByImagePath } from '@/api/recruit/enterprise/talentMap/labeling'
 import Snackbar from '@/plugins/snackbar'
 import baseInfo from './components/baseInfo.vue'
 import careerPath from './components/careerPath.vue'
 
 const loading = ref(false)
-const annotationLoading = ref(false)
+const detailLoading = ref(false)
 const content = ref('')
-// const items = ref([])
-const items = ref([
-  {
-    brand_group_english_name: null, 
-    brand_group_name: null, 
-    chinese_name: "陈静", 
-    email: "angela.chen@dossen.com", 
-    english_name: "Angela Chen", 
-    hotel_chinese_name: "东呈集团", 
-    hotel_english_name: "DOSSEN", 
-    hotel_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    hotel_updated: "2025-05-13 20:12:47", 
-    mobile: "+86 138 2502 1012, +852 92651012", 
-    position_chinese: "国际事业部资深副总裁", 
-    position_english: "Senior Vice President of International Business Department", 
-    talent_id: 33, 
-    talent_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    talent_updated: "2025-05-13 20:12:47", 
-    work_relation_updated: "2025-05-13 20:12:47"
-  }, 
-  {
-    brand_group_english_name: null, 
-    brand_group_name: null, 
-    chinese_name: "陈玮", 
-    email: "cw928383712@163.com", 
-    english_name: null, 
-    hotel_chinese_name: "苏州木渎古镇 ROSSO酒店", 
-    hotel_english_name: "ROSSO Hotel Suzhou Mudu Ancient Town", 
-    hotel_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    hotel_updated: "2025-05-13 20:05:03", 
-    mobile: "13073381364", 
-    position_chinese: "销售总监", 
-    position_english: "Sales Director", 
-    talent_id: 30, 
-    talent_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    talent_updated: "2025-05-13 20:05:03", 
-    work_relation_updated: "2025-05-13 20:05:03"
-  }, 
-  {
-    brand_group_english_name: null, 
-    brand_group_name: null, 
-    chinese_name: "陈静", 
-    email: "angela.chen@dossen.com", 
-    english_name: "Angela Chen", 
-    hotel_chinese_name: "东呈集团", 
-    hotel_english_name: "DOSSEN", 
-    hotel_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    hotel_updated: "2025-05-13 18:11:38", 
-    mobile: "+86 138 2502 1012, +852 92651012", 
-    position_chinese: "国际事业部资深副总裁", 
-    position_english: "Senior Vice President of International Business Department", 
-    talent_id: 29, 
-    talent_tags: [
-      {
-        tag_category: null, 
-        tag_en_name: null, 
-        tag_name: null
-      }
-    ], 
-    talent_updated: "2025-05-13 18:11:38", 
-    work_relation_updated: "2025-05-13 18:11:38"
-  }
-])
+const items = ref([])
 const headers = [
-  { title: '姓名', key: 'chinese_name', sortable: false },
-  { title: '酒店名称', key: 'hotel_chinese_name', sortable: false },
-  { title: '职位', key: 'position_chinese', sortable: false },
-  { title: '邮箱', key: 'email', sortable: false },
+  { title: '中文名', key: 'name_zh', sortable: false },
+  { title: '英文名', key: 'name_en', sortable: false },
   { title: '联系电话', key: 'mobile', sortable: false },
-  { title: '更新时间', key: 'talent_updated', sortable: false },
+  { title: '电子邮箱', key: 'email', sortable: false },
+  { title: '更新时间', key: 'updated_at', sortable: false },
   { title: '操作', key: 'actions', sortable: false, align: 'center' }
 ]
 const textItem = ref({
@@ -170,41 +83,49 @@ const getList = async () => {
 	try {
 		const data = await getTalentList({ query_requirement: content.value })
 		items.value = data || []
+    if (!data || !data.length) Snackbar.warning('暂无数据,请更换查询条件后再试')
 	} finally {
 		loading.value = false
 	}
 }
-// getList()
-
 
 // 查看详情
 const showDetail = ref(false)
 const detail = ref({})
+const previewUrl = ref(null)
 const handleDetail = async (item) => {
-	if (!item?.talent_id) {
+	if (!item?.pg_id) {
 		return
 	}
-	const result = await getBusinessCardDetails(item.talent_id)
-	if (!result || !Object.keys(result).length) return Snackbar.warning('暂无详细信息,去查看其他人的信息吧~') 
-	detail.value = result
-	showDetail.value = true
-}
 
+  detailLoading.value = true
+	try {
+    const result = await getBusinessCardDetails(item.pg_id)
+    if (!result || !Object.keys(result).length) return Snackbar.warning('暂无详细信息,去查看其他人的信息吧~')
+    detail.value = result
+
+    // 获取名片预览
+    if (result?.image_path) {
+      const data = await getTalentCardByImagePath(result.image_path)
+      previewUrl.value = URL.createObjectURL(data)
+    }
+
+    showDetail.value = true
+  } finally {
+    detailLoading.value = false
+  }
+}
 
 // 搜索
-const handleSearch = async () => {
-	if (!content.value) return Snackbar.warning('请输入您的描述信息定位人才')
-	getList()
+const handleSearch = async (value, type) => {
+  if (type === 'clear') {
+    items.value = []
+    return
+  }
+  if (!type && !content.value) return Snackbar.warning('请输入您的描述信息定位人才')
+  getList()
 }
 </script>
 
 <style scoped lang="scss">
-.base-info {
-	background-color: #f7f8fa;
-	border-radius: 6px;
-}
-.common-width {
-	width: 25%;
-	max-width: 25%;
-}
 </style>

+ 40 - 17
src/views/recruit/enterprise/resume/components/table.vue

@@ -132,17 +132,10 @@ const headers = ref([
   { title: '状态', key: 'status', sortable: false },
   { title: '操作', value: 'actions', sortable: false }
 ])
-// const unfit = { title: '类型', key: 'unfitType', sortable: false, value: item => item.type && item.type === '0' ? '简历不适合' : '面试不适合' }
-// const delivery = { title: '类型', key: 'deliveryType', sortable: false, value: item => item?.job?.hire ? '赏金职位' : '普通职位' }
 
 watch(
   () => props.tab,
   (val) => {
-    // const obj = val !== 4 ? delivery : unfit
-    // const index = headers.value.indexOf(obj)
-    // if (index === -1) headers.value.splice(-1, 0, obj)
-    // else headers.value.splice(index, 1)
-
     // 不合适不需要展示状态
     if (val === 4) {
       const obj = headers.value.find(e => e.key === 'status')
@@ -154,7 +147,9 @@ watch(
 )
 
 // 人才详情
-const handleToPersonDetail = async ({ userId, id }) => {
+const handleToPersonDetail = async (item) => {
+  const userId = item.userId
+  const id = props.tab === 0 ? item.id : item.cvRel.id
   if (!userId || !id) return
   // 改变状态
   try {
@@ -196,6 +191,7 @@ const handleEliminate = async (item) => {
       bizId: item.id,
       jobId: item.job.id,
       userId: item.userId,
+      jobCvRelId: props.tab === 0 ? item.id : item.cvRel?.id,
       type: props.tab === 0 ? '0' : '1' // 投递简历0 已邀约1
     }
     // 招聘会职位则带id
@@ -217,7 +213,9 @@ const handleCancelEliminate = async (item) => {
 }
 
 // 查看简历
-const handlePreviewResume = async ({ url, id }) => {
+const handlePreviewResume = async (item) => {
+  const url = props.tab === 0 ? item.url : item.cvRel.url
+  const id = props.tab === 0 ? item.id : item.cvRel.id
   if (!url || !id) return Snackbar.warning('简历不存在')
   try {
     const res = await personJobCvLook(id)
@@ -233,14 +231,14 @@ const handlePreviewResume = async ({ url, id }) => {
 // 邀请面试
 const itemData = ref({})
 const handleInterviewInvite = (item) => {
-  if (item.interViewStatus) return
-  if (item?.jobClosed) return Snackbar.warning('职位已关闭') // 职位已关闭
+  if (item.handleStatus) return
+  if (item?.jobClosed) return // 职位已关闭
   itemData.value = item
   showInvite.value = true
 }
 
 const handleToCommunicate = async (item) => {
-  if (item?.jobClosed) return Snackbar.warning('职位已关闭') // 职位已关闭
+  if (item?.jobClosed) return // 职位已关闭
   const userId = item.userId
   await talkToUser({userId, text: defaultTextEnt})
   let url = `/recruit/enterprise/chatTools?id=${userId}`
@@ -258,6 +256,8 @@ const handleEditSubmit = async () => {
   const query = inviteRef.value.getQuery()
   if (!query?.time) return Snackbar.warning('请选择面试时间')
 
+  query.jobCvRelId = itemData.value.id
+
   formLoading.value = true
   try {
     await saveInterviewInvite(query)
@@ -289,22 +289,45 @@ const handleToInterviewManagement = () => {
 
 // 下载附件
 const handleDownloadAttachment = (k) => {
-  if (!k.url) return
-  getBlob(k.url).then(blob => {
-    saveAs(blob, k.title)
+  const url = props.tab === 0 ? k.url : k.cvRel?.url
+  if (!url) return
+  getBlob(url).then(blob => {
+    saveAs(blob, props.tab === 0 ? k.title : k.cvRel?.title)
   })
 }
 
 const actionItems = (item) => {
   const arr = []
-  if (props.tab === 0) arr.push({ title: item.interViewStatus ? '邀请面试(当前投递记录已邀约面试)' : '邀请面试', disabled: item.interViewStatus, color: 'success', click: handleInterviewInvite, icon: 'mdi-account-clock-outline' }, { title: '立即沟通', color: 'primary', click: handleToCommunicate, icon: 'mdi-comment-processing-outline' })
+  // 有返回简历信息的才展示查看简历&下载简历
+  if ((props.tab === 0 && item.url) || (props.tab !== 0 && item?.cvRel && item.cvRel?.url)) arr.push(
+    { title: '查看附件', color: 'warning', click: handlePreviewResume, icon: 'mdi-eye-outline' }, 
+    { title: '下载附件', color: 'error', click: handleDownloadAttachment, icon: 'mdi-arrow-down-bold-circle-outline' }
+  )
+  if (props.tab === 0) {
+    arr.push(
+      {
+        title: item?.jobClosed ? '邀请面试(职位已关闭)' : (item.handleStatus ? '邀请面试(已邀面试)' : '邀请面试'),
+        disabled: item?.jobClosed || item.handleStatus,
+        color: 'success',
+        click: handleInterviewInvite,
+        icon: 'mdi-account-clock-outline'
+      }, 
+      {
+        title: item?.jobClosed ? '立即沟通(职位已关闭)' : '立即沟通',
+        color: 'primary',
+        disabled: item?.jobClosed,
+        click: handleToCommunicate,
+        icon: 'mdi-comment-processing-outline'
+      }
+    )
+  }
   if ([0, 1].includes(props.tab)) arr.push({ title: '不合适', color: 'indigo', click: handleEliminate, icon: 'mdi-account-remove-outline' })
   if (props.tab === 4) arr.push({ title: '取消不合适', color: 'light-blue', click: handleCancelEliminate, icon: 'mdi-account-check-outline' })
   if (props.tab === 2 && item?.job?.hire) arr.push({ title: '结算', click: handleSettlement, icon: 'mdi-currency-cny' })
   if (props.tab === 1 && ['3', '4'].includes(item.status)) arr.push({ title: '入职', click: handleEnterByEnterprise, icon: 'mdi-account-arrow-right-outline' })
   // 面试后才能够加入储备
   if ([1, 2, 3].includes(props.tab) && !item.inTalentPool) arr.push({ title: '加入储备', color: '#00897B', click: handleJoinToTalentPool, icon: 'mdi-account-star-outline' })
-  return [{ title: '查看附件', color: 'warning', click: handlePreviewResume, icon: 'mdi-eye-outline' }, { title: '下载附件', color: 'error', click: handleDownloadAttachment, icon: 'mdi-arrow-down-bold-circle-outline' }, ...arr]
+  return arr
 }
 </script>