Ver código fonte

人才详情

lifanagju_citu 11 meses atrás
pai
commit
3d4353da13

+ 9 - 0
src/router/modules/enterprise.js

@@ -21,6 +21,15 @@ const enterprise = [
         path: '/enterprise/talentPool',
         show: true,
         component: () => import('@/views/enterprise/talentPool/index.vue')
+      },
+      {
+        path: '/enterprise/talentPool/details/:id',
+        show: true,
+        component: () => import('@/views/enterprise/talentPool/components/details'),
+        name: 'talentPoolDetails',
+        meta: {
+          title: '人才详情'
+        }
       }
     ]
   },

+ 1 - 1
src/views/enterprise/enterpriseCenter/index.vue

@@ -3,7 +3,7 @@
   <div class="default-width banner pa-6" style="position: relative;">
     <!-- header -->
     <div class="d-flex align-center">
-      <v-avatar class="mx-4" size=80 :image="baseInfo?.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
+      <v-avatar class="mx-4" size=80 :image="info?.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
       <div>
         <div class="contact-name">
           <span>苏州识喜识谊酒店管理有限公司</span>

+ 83 - 0
src/views/enterprise/talentPool/components/details.vue

@@ -0,0 +1,83 @@
+<!-- 人才库 - 人才详情 -->
+<template>
+  <div class="white-bgc py-2 d-flex justify-center" style="width: 100%;">
+    <div style="width: 940px;overflow-y: auto;background: none;" class=" pa-3 mr-3">
+      <!-- 基本信息 -->
+      <baseInfo class="mt-5"></baseInfo>
+      <!-- 个人优势 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.personalAdvantages') }}</span>
+        <div style="flex: 1; white-space: pre-line; font-size: 15px;" v-if="advantage" v-html="advantage"></div>
+      </div>
+      <!-- 职业技能 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.vocationalSkills') }}</span>
+        <!-- <vocationalSkills style="flex: 1;"></vocationalSkills> -->
+      </div>
+      <!-- 求职意向 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.jobIntention') }}</span>
+        <jobIntention style="flex: 1;" :list="[]"></jobIntention>
+      </div>
+      <!-- 工作经历 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.workExperience') }}</span>
+        <workExperience style="flex: 1;"></workExperience>
+      </div>
+      <!-- 项目经历 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.projectExperience') }}</span>
+        <!-- <projectExperience style="flex: 1;"></projectExperience> -->
+      </div>
+      <!-- 培训经历 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.trainingExperience') }}</span>
+        <!-- <trainingExperience style="flex: 1;"></trainingExperience> -->
+      </div>
+      <!-- 教育经历 -->
+      <div class="d-flex mt-8">
+        <span class="mr-6">{{ $t('resume.educationExp') }}</span>
+        <!-- <educationExp style="flex: 1;"></educationExp> -->
+      </div>
+      <!--  -->
+    </div>
+    <div class="operate pa-3">
+      <v-list>
+        <!-- <v-list-subheader class="title">简历助手</v-list-subheader> -->
+        <v-list-item
+          v-for="(item, i) in operateItems" :key="'简历助手' + i"
+          color="primary"
+          :prepend-icon="item.icon"
+          :title="item.text"
+          @click="{}"
+        >
+        </v-list-item>
+      </v-list>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import baseInfo from './details/baseInfo.vue'
+import jobIntention from './details/jobIntention.vue'
+import workExperience from './details/workExperience.vue'
+defineOptions({name: 'enterprise-talentPool-details'})
+
+const advantage = "1、熟悉 Java  技术平台,并稳定形成生产力,CCF 中国计算机学会会员,获得微软 MCP、MCSA 认证。 \n2、熟悉通用缓存/DB /搜索引擎/消息队列等中间件。对业内高可用高并发及分布式技术解决方案有充分理解。\n3、同时具备常用大数据解决方案实践经验,包括实时计算(Storm/Flink )及离线计算(Hive/ETL/Spark)。 \n4、对搜索推荐/订单交易等业务方向具备多年实践经验。\n5、上班。"
+const operateItems = [
+  { text: '邀请面试', icon: 'mdi-account-check' },
+  { text: '不合适', icon: 'mdi-close-circle-outline' },
+  { text: '发起对话', icon: 'mdi-chat-processing-outline' },
+  { text: '加入人才库', icon: 'mdi-tab-plus' },
+]
+</script>
+<style lang="scss" scoped>
+.operate {
+  width: 240px;
+  height: 500px; // 272px
+  position: sticky;
+  top: 60px;
+  // background-color: var(--default-bgc);
+  background-color: #f7f8fa;
+}
+</style>

+ 150 - 0
src/views/enterprise/talentPool/components/details/baseInfo.vue

@@ -0,0 +1,150 @@
+<!-- 基本信息 -->
+<template>
+  <div class="d-flex">
+    <!-- 头像 -->
+    <div class="avatarsBox" @mouseover="showIcon = true" @mouseleave="showIcon = false">
+      <v-badge 
+        bordered 
+        offset-x="-25" 
+        offset-y="33" 
+        :color="info?.sex ? (info?.sex === '1' ? '#1867c0' : 'error') : 'error'" 
+        :icon="info?.sex ? (info?.sex === '1' ? 'mdi-gender-male' : 'mdi-gender-female') : 'mdi-gender-female'">
+        <v-avatar size=80 :image="info?.avatar || 'https://minio.citupro.com/dev/menduner/7.png'">
+        </v-avatar>
+      </v-badge>
+    </div>
+    <!-- 信息 -->
+    <div style="flex: 1;">
+      <span style="font-size: 20px; font-weight: 600;color: #666;">{{ info?.name }}</span>
+      <div class="mt-3 d-flex">
+        <div class="listBox" :style="{ height: isExpand ? 'auto' : '68px' }">
+          <div>
+            <span class="mdi mdi-map-marker-outline"></span>
+            <span>{{ info?.areaName || '暂无' }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-phone-outline"></span>
+            <span>{{ info?.phone }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-email-outline"></span>
+            <span>{{ info?.email }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-calendar-blank-outline"></span>
+            <span>{{ info?.expTypeText }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-school-outline"></span>
+            <span>{{ info?.eduTypeText }}</span>
+          </div>
+          <!-- <div>
+            <span class="mdi mdi-briefcase-outline"></span>
+            <span>{{ info?.jobTypeText }}</span>
+          </div> -->
+          <div>
+            <span class="mdi mdi-tag-outline"></span>
+            <span>{{ info?.jobStatusText }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-cake-variant-outline"></span>
+            <span>{{ info?.birthdayText }}</span>
+          </div>
+          <div>
+            <span class="mdi mdi-account-heart"></span>
+            <span>{{ info?.maritalText }}</span>
+          </div>
+          <div>
+            <span>{{ $t('resume.firstWorkTime') }}:</span>
+            <span>{{ info?.firstWorkTimeText }}</span>
+          </div>
+        </div>
+      </div>
+      <div class="mt-4">
+        <span style="font-size: 15px;">个人画像:</span>
+        <v-chip size="small" label v-for="(k, i) in welfareList.slice(0, 8)" :key="i" class="mr-2" color="primary">{{ k }}</v-chip>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+defineOptions({name: 'enterprise-talentPool-details-baseInfo'})
+
+const welfareList = ref(['响应', '改变', '诚信', '进取精神', '信任', '卓越'])
+let info = ref(
+  {
+    id: "1793583467288223745", 
+    userId: "1", 
+    name: "安琪", 
+    sex: "1", 
+    avatar: "http://menduner.citupro.com:6868/admin-api/infra/file/24/get/241e594d4473872eabb312673f42241a2e9598298cb7d9d791cc9c8cb65fb058.jpg", 
+    phone: "13229740091", 
+    email: "citupro.com", 
+    wxCode: null, 
+    birthday: 946656000000, 
+    maritalStatus: "3", 
+    areaId: "110101", 
+    jobType: "3", 
+    jobStatus: "2", 
+    firstWorkTime: 1020182400000, 
+    expType: "7", 
+    eduType: "99", 
+    createTime: 1716487396000, 
+    birthdayText: "2000-01-01", 
+    firstWorkTimeText: "2002-05-01", 
+    areaName: "东城区", 
+    eduTypeText: "其他", 
+    expTypeText: "10年以上", 
+    sexTypeText: "男", 
+    jobTypeText: "实习", 
+    jobStatusText: "在职-考虑机会", 
+    maritalText: "保密",
+  }
+)
+</script>
+<style lang="scss" scoped>
+.avatarsBox {
+  height: 80px;
+  width: 80px;
+  position: relative;
+  cursor: pointer;
+  // margin: 32px;
+  margin-right: 40px;
+  .img {
+    width: 100%;
+    height: 100%;
+  }
+  .mdi {
+    font-size: 42px;
+    color: #fff;
+  }
+  div {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    border-radius: 50%;
+  }
+}
+.listBox {
+  display: flex;
+  flex-wrap: wrap; /* 允许换行 */
+  width: 100%; /* 设置容器宽度 */
+  // height: 68px;
+  overflow: hidden;
+  color: #666;
+  div {
+    margin-right: 50px;
+    span {
+      height: 32px;
+      line-height: 32px;
+    }
+    .mdi {
+      font-size: 22px;
+      margin-right: 8px;
+    }
+  }
+}
+</style>

+ 74 - 0
src/views/enterprise/talentPool/components/details/dict.js

@@ -0,0 +1,74 @@
+import { reactive } from 'vue'
+import { getDict } from '@/hooks/web/useDictionaries'
+
+const dictObj = reactive({})
+const dictList = [
+  { 
+    type: 'positionData', 
+    apiType: 'positionData', 
+    key: 'positionId', 
+    label: 'position', 
+    value: 'positionTypeData', 
+    itemKey: 'id', 
+    itemText: 'nameCn'
+  },
+  { 
+    type: 'industryList', 
+    apiType: 'industryList', 
+    key: 'industryIdList', 
+    label: 'industry', 
+    isArray: true, 
+    value: 'industryTypeData', 
+    itemKey: 'id', 
+    itemText: 'nameCn' 
+  },
+  { 
+    type: 'menduner_area_type',
+    apiType: 'areaList',
+    key: 'workAreaId',
+    label: 'workArea',
+    value: 'areaTypeData',
+    itemKey: 'id',
+    itemText: 'name'
+  },
+  { 
+    type: 'menduner_job_type',
+    key: 'jobType',
+    label: 'jobTypeName',
+    value: 'jobTypeData',
+    itemKey: 'value',
+    itemText: 'label'
+  }
+]
+
+// 字典
+const getDictList = async () => {
+  dictList.forEach(async (val) => {
+    const { data } = await getDict(val.type, val.params, val.apiType)
+    dictObj[val.value] = data
+  })
+}
+
+const getData = async () => {
+  await getDictList()
+}
+getData()
+
+export const dealJobData = (list) => {
+  let res = {}
+  dictList.forEach(item => {
+    res = list.map(e => {
+      let obj = {}
+      if (item.isArray) {
+        e[item.label] = e[item.key].map(val => {
+          return obj = dictObj[item.value].find(i => i[item.itemKey] === val)
+        })
+      } else {
+        obj = dictObj[item.value].find(k => Number(k[item.itemKey]) === Number(e[item.key]))
+        e[item.label] = obj[item.itemText]
+      }
+      return e
+    })
+  })
+  return res
+}

+ 161 - 0
src/views/enterprise/talentPool/components/details/jobIntention.vue

@@ -0,0 +1,161 @@
+<template>
+  <div v-if="interestList.length">
+    <div
+      :class="['position-item', 'mb-1']" 
+      v-for="(k, i) in interestList" 
+      :key="'jobIntention' + i"
+      @mouseenter="k.active = true" 
+      @mouseleave="k.active = false"
+    >
+      <div class="d-flex">
+        <div>{{ k.position }}</div>
+        <div class="line">|</div>
+        <div>{{k.payFrom}}-{{k.payTo}}</div>
+        <div class="line">|</div>
+        <div class="grey-text text-box">{{ k.industry.map(e => e.nameCn).join('、') }}</div>
+        <div class="line">|</div>
+        <div class="grey-text">{{ k.jobTypeName }}</div>
+        <div class="line">|</div>
+        <div class="grey-text">{{ k.workArea }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import { dealJobData } from './dict'
+defineOptions({name: 'enterprise-talentPool-details-jobIntention'})
+const props = defineProps({
+  list: {
+    type: Array,
+    default: () => []
+  }
+})
+// 获取求职意向
+const interestList = ref([
+  {
+    id: "1793832094791270402", 
+    jobType: "2", 
+    positionId: "14", 
+    industryIdList: [
+      "2", 
+      "4"
+    ], 
+    payFrom: 14000, 
+    payTo: 17000, 
+    workAreaId: "140171", 
+    interestedAreaIdList: [
+      "440106", 
+      "440105"
+    ], 
+    createTime: 1716546674000, 
+    updateTime: 1716970523000, 
+    position: "区块链工程师", 
+    industry: [
+      {
+        id: "2", 
+        nameCn: "互联网", 
+        nameEn: null
+      }, 
+      {
+        id: "4", 
+        nameCn: "计算机软件", 
+        nameEn: null
+      }
+    ], 
+    workArea: "山西转型综合改革示范区", 
+    jobTypeName: "临时"
+  }, 
+  {
+    id: "1795405184893648897", 
+    jobType: "2", 
+    positionId: "4", 
+    industryIdList: [
+      "2", 
+      "4", 
+      "6"
+    ], 
+    payFrom: 8000, 
+    payTo: 12000, 
+    workAreaId: "110101", 
+    interestedAreaIdList: null, 
+    createTime: 1716892928000, 
+    updateTime: 1716900602000, 
+    position: "C/C++", 
+    industry: [
+      {
+        id: "2", 
+        nameCn: "互联网", 
+        nameEn: null
+      }, 
+      {
+        id: "4", 
+        nameCn: "计算机软件", 
+        nameEn: null
+      }, 
+      {
+        id: "6", 
+        nameCn: "企业服务", 
+        nameEn: null
+      }
+    ], 
+    workArea: "东城区", 
+    jobTypeName: "临时"
+  }, 
+  {
+    id: "1795643155882860545", 
+    jobType: "0", 
+    positionId: "346", 
+    industryIdList: [
+      "16", 
+      "17"
+    ], 
+    payFrom: 8000, 
+    payTo: 10000, 
+    workAreaId: "500101", 
+    interestedAreaIdList: null, 
+    createTime: 1716949664000, 
+    updateTime: 1716949664000, 
+    position: "税务外勤会计", 
+    industry: [
+      {
+        id: "16", 
+        nameCn: "物联网", 
+        nameEn: null
+      }, 
+      {
+        id: "17", 
+        nameCn: "新零售", 
+        nameEn: null
+      }
+    ], 
+    workArea: "万州区", 
+    jobTypeName: "全职"
+  }
+])
+if (props.list?.length) interestList.value = dealJobData(props.list)
+</script>
+<style lang="scss" scoped>
+.position-item {
+  display: flex;
+  justify-content: space-between;
+  // cursor: pointer;
+  border-radius: 6px;
+  // line-height: 40px;
+  font-size: 15px;
+  // &:hover {
+  //   background-color: #f8f8f8;
+  // }
+  span {
+    font-size: 15px;
+  }
+  .grey-text {
+    color: #999;
+  }
+  .line {
+    color: #e0e0e0;
+    margin: 0 10px;
+  }
+}
+</style>

+ 90 - 0
src/views/enterprise/talentPool/components/details/workExperience.vue

@@ -0,0 +1,90 @@
+<!-- 工作经历 -->
+<template>
+  <div>
+    <div
+      v-for="(item, index) in dataList" :key="'workExperience' + index"
+      :class="[' mx-n2', {'mt-3': index }]"
+    >
+      <div class="educExpItem" @mouseenter="item.active = true" @mouseleave="item.active = false">
+        <div class="level1 d-flex align-center justify-space-between mb-2">
+          <div>
+            <span>{{ item.enterpriseName }}</span>
+            <span class="color6 font15 ml-5">
+              <span>{{ timesTampChange(item.startTime).slice(0, 10) }}</span>
+              <span class="mx-1">至</span>
+              <span>{{ timesTampChange(item.endTime).slice(0, 10) }}</span>
+            </span>
+            <span class="color6 font15 ml-5">{{ item.positionName }}</span>
+          </div>
+        </div>
+        <!-- <div class="level2 my-2">
+          <span class="color6 font15">{{ item.positionName }}</span>
+        </div> -->
+        <div class="level3">
+          <span class="color6 font15">工作内容:{{ item.content }}</span>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { timesTampChange } from '@/utils/date'
+import { ref } from 'vue';
+defineOptions({name: 'enterprise-talentPool-details-workExperience'})
+
+const dataList = ref([
+  {
+    id: "1800817427231723521", 
+    enterpriseId: null, 
+    enterpriseName: "门墩儿信息科技有限公司", 
+    industryId: null, 
+    deptName: null, 
+    positionId: null, 
+    positionName: "后端开发", 
+    startTime: 1706716800000, 
+    endTime: 1732982400000, 
+    content: "1,根据产品需求说明书,编写测试计划,编写测试用例,根据测试用例执行情况,修改完善测试\n用例\n2,测试云卡通平台功能是否正确\n3,使用 postman 测试支付接口,消费接口等接口测试工作\n4,使用 sqlserver 查找设备通讯,白名单下传标识等\n5,使用 adb、安卓开发工具查看日志\n5,使用 jmeter 模拟多人操作云卡通平台等压力测试工作\n6,对软件缺陷进行登录,跟踪,分析,并提交软件缺陷报告给开发人员\n7,完成项目归纳,编写以维护云卡通平台等的产品说明书等技术文档\n8,负责维护版本迭代,提高用户体验。\n1,根据产品需求说明书,编写测试计划,编写测试用例,根据测试用例执行情况,修改完善测试\n用例\n2,测试云卡通平台功能是否正确\n3,使用 postman 测试支付接口,消费接口等接口测试工作\n4,使用 sqlserver 查找设备通讯,白名单下传标识等\n5,使用 adb、安卓开发工具查看日志\n5,使用 jmeter 模拟多人操作云卡通平台等压力测试工作\n6,对软件缺陷进行登录,跟踪,分析,并提交软件缺陷报告给开发人员\n7,完成项目归纳,编写以维护云卡通平台等的产品说明书等技术文档\n8,负责维护版本迭代,提高用户体验。", 
+    achievement: null, 
+    pay: null, 
+    payUnit: null, 
+    currencyType: null, 
+    skillList: null, 
+    createTime: 1718183307000, 
+    updateTime: 1718184370000
+  }, 
+  {
+    id: "1800817561520754690", 
+    enterpriseId: null, 
+    enterpriseName: "门墩儿信息科技有限公司", 
+    industryId: null, 
+    deptName: null, 
+    positionId: null, 
+    positionName: "Java", 
+    startTime: 1675180800000, 
+    endTime: 1682870400000, 
+    content: "1、测试终端app,web端网页的基本功能\n2、编写测试用例,完善测试用例;\n3、根据 API 文档进行接口测试;\n4、使用Python编程语言构建/维护UI、接口自动化脚本;\n5、 使用fiddler抓包工具辅助日常测试工作;\n6、 使用Navicat工具操作数据库;\n7、根据文档对接口进行压力测试并输出文档;\n8、 使用Appscan工具进行安全测试并输出文档;\n9、负责跟踪与回归禅道上的 bug;\n10、 完成领导交代的其他事项。", 
+    achievement: null, 
+    pay: null, 
+    payUnit: null, 
+    currencyType: null, 
+    skillList: null, 
+    createTime: 1718183339000, 
+    updateTime: 1718184332000
+  }
+])
+</script>
+<style lang="scss" scoped>
+.font15 { font-size: 15px;; }
+.color9 { color: #999; }
+.color6 { color: #666; }
+.color3 { color: #333; }
+.educExpItem {
+  // cursor: pointer;
+  border-radius: 6px;
+  padding: 2px 10px 8px;
+  &:hover {
+    background-color: #f8f8f8;
+  }
+}
+</style>

+ 10 - 3
src/views/enterprise/talentPool/index.vue

@@ -21,7 +21,7 @@
           <span class="mx-10">加入时间:{{ val.createTime }}</span>
           <span>人才分类:{{ val.type }}</span>
         </div>
-        <div class="px-5 py-3 d-flex justify-space-between align-center">
+        <div @click.stop="talentPoolDetails(val)" class="px-5 py-3 d-flex justify-space-between align-center">
           <div class="d-flex">
             <v-badge
               bordered
@@ -42,8 +42,8 @@
             </div>
           </div>
           <div>
-            <v-btn color="primary" variant="tonal">和TA聊聊</v-btn>
-            <v-btn class="ml-3" color="primary">邀请面试</v-btn>
+            <v-btn color="primary" variant="tonal" @click.stop="{}">和TA聊聊</v-btn>
+            <v-btn class="ml-3" color="primary" @click.stop="{}">邀请面试</v-btn>
           </div>
         </div>
         <div class="d-flex mx-5 bottom">
@@ -89,6 +89,8 @@
 </template>
 
 <script setup>
+// import { useRouter } from 'vue-router'
+// const router = useRouter()
 defineOptions({ name: 'enterprise-talent-pool'})
 import { ref } from 'vue'
 import TextUI from '@/components/FormUI/TextInput'
@@ -227,6 +229,11 @@ const handleChangePage = () => {
     if (obj) obj.select = true
   })
 }
+
+// 职位详情
+const talentPoolDetails = (val) => {
+  window.open(`/enterprise/talentPool/details/${val.id}`)
+}
 </script>
 
 <style scoped lang="scss">