Explorar o código

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

zhengnaiwen_citu hai 9 meses
pai
achega
14e1461a7b
Modificáronse 31 ficheiros con 266 adicións e 240 borrados
  1. 0 127
      public/static/sharingPage.html
  2. 8 0
      src/api/recruit/enterprise/statistics/index.js
  3. 1 1
      src/components/CtForm/index.vue
  4. 10 0
      src/components/DatePicker/index.vue
  5. 4 2
      src/components/Enterprise/components/introduction.vue
  6. 22 7
      src/components/Enterprise/components/positions.vue
  7. 8 1
      src/components/FormUI/TextInput/index.vue
  8. 5 2
      src/components/Position/item.vue
  9. 18 0
      src/layout/enterprise.vue
  10. 15 2
      src/plugins/curtain/components/point.vue
  11. 8 0
      src/views/publicRecruitment/myRecommendation.vue
  12. 6 1
      src/views/recruit/enterprise/informationManagement/informationSettings.vue
  13. 5 1
      src/views/recruit/enterprise/informationManagement/informationSettingsComponents/basicInfo.vue
  14. 8 6
      src/views/recruit/enterprise/informationManagement/informationSettingsComponents/enterpriseAlbum.vue
  15. 1 0
      src/views/recruit/enterprise/informationManagement/informationSettingsComponents/enterpriseLogo.vue
  16. 1 1
      src/views/recruit/enterprise/informationSetting/index.vue
  17. 16 2
      src/views/recruit/enterprise/positionManagement/components/baseInfo.vue
  18. 3 3
      src/views/recruit/enterprise/positionManagement/components/item.vue
  19. 1 0
      src/views/recruit/enterprise/positionManagement/index.vue
  20. 1 1
      src/views/recruit/enterprise/register/register.vue
  21. 54 23
      src/views/recruit/enterprise/statistics/components/overview.vue
  22. 1 1
      src/views/recruit/enterprise/statistics/overallAnalysis.vue
  23. 39 6
      src/views/recruit/enterprise/systemManagement/groupAccount/components/record.vue
  24. 1 1
      src/views/recruit/enterprise/systemManagement/groupAccount/components/simplePageForm.vue
  25. 4 4
      src/views/recruit/enterprise/talentPool/components/details.vue
  26. 9 33
      src/views/recruit/personal/PersonalCenter/components/interview/item.vue
  27. 11 11
      src/views/recruit/personal/company/index.vue
  28. 3 1
      src/views/recruit/personal/position/components/conditionFilter/areaType.vue
  29. 1 1
      src/views/recruit/personal/remuse/components/basicInfo.vue
  30. 1 1
      src/views/recruit/personal/shareJob/form/simpleInfo.vue
  31. 1 1
      src/views/recruit/personal/shareJob/form/upload.vue

+ 0 - 127
public/static/sharingPage.html

@@ -1,127 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-    <title>分享职位</title>
-  </head>
-  <style type="text/css">
-    #app {
-      height: 100vh; /* 占据整个视口高度 */
-      width: 100%;
-      padding: 0;
-      margin: 0;
-      overflow: hidden;
-      font-size: 16px;
-      background-color: #fff;
-    }
-    #app .loadingCss {
-      display: flex;  
-      justify-content: center;  
-      align-items: center;  
-      height: 100%;
-      background-color: #f0f0f0;
-    }
-    #app .content {
-      padding: 10px 15px;
-      display: flex;  
-      flex-direction: column;
-      /* justify-content: center;   */
-      align-items: center;  
-      height: 100%;
-      width: 100%;
-      overflow: auto;
-      margin-top: 50px;
-    }
-    body {
-      width: 100%;
-      margin: 0;
-      padding: 0;
-    }
-  </style>
-  <body>
-  <div id="app" v-cloak>
-    <div v-if="loading && !loadFail" class="loadingCss">加载中...</div>
-    <div v-else-if="loading && loadFail" class="loadingCss">加载失败...</div>
-    <div v-else class="content">
-      <div class="banner-title">
-        <h1 class="ellipsis">{{ info?.name || '数据错误' }}</h1>
-        <span class="salary">{{ info?.payFrom || '数据错误' }}-{{ info?.payTo || '数据错误' }}/月</span>
-      </div>
-      <div class="banner-tags mt-4">
-        <span v-for="k in desc" :key="k.mdi" style="margin-right: 15px;">
-          <span class="ml-1">{{ k.value }}</span>
-        </span>
-      </div>
-      <div class="banner-tools my-4">
-      </div>
-      <div class="">
-        <div class="">
-          <span style="margin-right: 15px;">立即沟通</span>
-          <span>投递简历</span>
-        </div>
-      </div>
-    </div>
-  </div>
-  </body>
-  <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>  
-  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
-  <script type="text/javascript">
-    const { nextTick, createApp, ref } = Vue
-    const loading = ref(true)
-    const loadFail = ref(false)
-    const app = createApp({
-      setup() {
-        const url = window.location.href
-        // const urlTest = 'http://menduner.citupro.com:7878/app-api/detail?id=1802541269864042498&name=2&phone=3&file=4'
-        const queryStr = url.split('?') && url.split('?')[1] // 提取URL的查询字符串部分
-        const query = { id: '', name: '', phone: '', file: '' }
-        
-        if (queryStr) queryStr.split('&').forEach(function (pair) { // 分割查询字符串为键值对数组
-          const parts = pair.split('=') // 分割每个键值对
-          query[parts[0]] = parts[1] || '' // 赋值到对象上,注意处理undefined情况
-        })
-
-        // 请求分享的详情数据
-        let info = ref(null)
-        const fetchData = async () => {
-          function alertFun (val) {
-            loadFail.value = true
-            // alert('获取详情失败,' + val)
-          }
-          try {
-            const url = 'http://menduner.citupro.com:7878/app-api/menduner/system/job/advertised/get/detail'
-            const params = { id: query.id }
-            const res = await axios.get(url, { params })
-            if (res && res.status !== 200) return alertFun(res.statusText)
-            // 处理数据
-            const { data } = res.data
-            if (data) {
-              info.value = data
-              loading.value = false
-            } else {
-              alertFun(res.data.msg)
-            }
-          } catch (error) {
-            console.error(error)
-          }
-        }
-        // 设置请求头
-        axios.defaults.headers.common['tenant-id'] = '155'
-        fetchData()
-        const desc = [
-          { mdi: 'mdi-map-marker-outline', value: '越秀区' }, // areaName
-          { mdi: 'mdi-school-outline', value: '高中' }, // eduName
-          { mdi: 'mdi-clock-time-ten-outline', value: '经验不限' } // expName
-        ]
-        return {
-          loading,
-          loadFail,
-          info,
-          desc
-        }
-      }
-    })
-    app.mount('#app')
-  </script>
-</html>

+ 8 - 0
src/api/recruit/enterprise/statistics/index.js

@@ -31,3 +31,11 @@ export const getJobCvSexCount = async (params) => {
     params
   })
 }
+
+// 联系我的和我联系的统计
+export const getRecentConversations = async (data) => {
+  return await request.post({
+    url: '/app-api/im/recent/conversations/statistics',
+    data
+  })
+}

+ 1 - 1
src/components/CtForm/index.vue

@@ -11,7 +11,7 @@
             <div class="d-flex mb-2" :class="item.flexStyle || 'flex-row'">
               <!-- <span>{{ item.value }}</span> -->
               <textUI
-                v-if="['text', 'password', 'number'].includes(item.type)"
+                v-if="['text', 'password', 'number', 'phoneNumber'].includes(item.type)"
                 v-model="item.value"
                 :item="item"
                 @blur="item.blur"

+ 10 - 0
src/components/DatePicker/index.vue

@@ -52,4 +52,14 @@ const time = computed(() => {
 :deep(.dp__input_icon_pad) {
   font-size: 14px;
 }
+::v-deep .dp__input {
+  border: 1px solid #ababab;
+  padding: 7px 30px;
+  &:hover {
+    border: 1px solid #444;
+  }
+  &:focus {
+    border: 1px solid var(--v-primary-base);
+  }
+}
 </style>

+ 4 - 2
src/components/Enterprise/components/introduction.vue

@@ -15,8 +15,10 @@
       <h4>公司相册</h4>
       <v-slide-group :show-arrows="true" class="mt-3 img-box cursor-pointer">
         <v-slide-group-item v-for="(val, i) in props.info.enterprise.albumList" :key="val">
-          <v-img v-if="checkIsImage(val)" class="mr-3" width="200" height="115" :src="val" cover rounded @click="handleClick(i)"></v-img>
-          <video v-else class="videos-radius mr-3" :src="val" controls height="118" width="200" preload="preload" @click="handleClick(i)"></video>
+          <div>
+            <v-img v-if="checkIsImage(val)" class="mr-3" width="200" height="115" :src="val" cover rounded @click="handleClick(i)"></v-img>
+            <video v-else class="videos-radius mr-3" :src="val" controls height="118" width="200" preload="preload" @click="handleClick(i)"></video>
+          </div>
         </v-slide-group-item>
       </v-slide-group>
     </div>

+ 22 - 7
src/components/Enterprise/components/positions.vue

@@ -40,15 +40,16 @@
         :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>
+          <p v-if="val.job.name.includes('style')" :class="['name', {'default-active': val.active }]" v-html="val.job.name" @click="handlePosition(val)"></p>
+          <p v-else :class="['name', {'default-active': val.active }]" @click="handlePosition(val)">{{ 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 v-for="k in desc" :key="k.mdi">
+              <span v-if="val.job[k.value]" 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>
             </span>
           </div>
         </div>
@@ -60,7 +61,7 @@
           <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>
+            <v-btn class="half-button" color="primary" size="small" @click="toDetails(val)">立即沟通</v-btn>
           </span>
         </div>
       </div>
@@ -82,6 +83,7 @@ import { useRoute, useRouter } from 'vue-router'
 import { timesTampChange } from '@/utils/date'
 import { getDict } from '@/hooks/web/useDictionaries'
 import { dealDictObjData } from '@/utils/position'
+import { prologue } from '@/hooks/web/useIM'
 import { getJobAdvertisedPositionCount, getJobAreaByEnterpriseId, getJobAdvertisedSearch } from '@/api/position'
 import MPagination from '@/components/CtPagination'
 import expType from '@/views/recruit/personal/position/components/conditionFilter/expType.vue'
@@ -204,6 +206,19 @@ const desc = [
   { mdi: 'mdi-school-outline', value: 'eduName' },
   { mdi: 'mdi-clock-time-ten-outline', value: 'expName' }
 ]
+
+const toDetails = async (info) => {
+  const userId = info.contact.userId
+  const enterpriseId = info.contact.enterpriseId
+  const text = '您好,我对该职位很感兴趣,希望能有机会与您进一步沟通。'
+  await prologue({userId, enterpriseId, text})
+  let url = `/recruit/personal/message?id=${info.job.id}`
+  if (info.contact.enterpriseId) {
+    url += `&enterprise=${info.contact.enterpriseId}`
+  }
+
+  router.push(url)
+}
 </script>
 
 <style scoped lang="scss">

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

@@ -4,7 +4,7 @@
       v-model="value"
       variant="outlined"
       :density="item.dense || 'compact'"
-      :type="item.type"
+      :type="item.type === 'phoneNumber' ? 'number' : item.type"
       :rules="item.rules"
       :disabled="item.disabled"
       :style="{width: item.width}"
@@ -34,6 +34,7 @@
   </div>
 </template>
 <script setup>
+import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import { debounce } from 'lodash'
 import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-text-field'})
@@ -86,6 +87,12 @@ const handleWheel = (event, item) => {
     item.value++
   }
 }
+
+if (item.type === 'phoneNumber') {
+  const phoneRules = [v => !v || v?.length <= 11 && /^1[3456789]\d{9}$/.test(v) || t('login.correctPhoneNumber')]
+  item.rules = item.rules ? [ ...phoneRules, ...item.rules] : phoneRules
+  item.counter = item.counter ? item.counter : 11
+}
 </script>
 <style lang="scss" scoped>
 

+ 5 - 2
src/components/Position/item.vue

@@ -1,8 +1,8 @@
 <template>
   <div class="d-flex">
     <div class="position-box">
-      <div class="sub-li" v-for="(item, index) in list" :key="index" @mouseenter="item.active = true" @mouseleave="item.active = false">
-        <div class="job-info" @click="handlePosition(item)">
+      <div class="sub-li" v-for="(item, index) in list" :key="index">
+        <div class="job-info" @click="handlePosition(item)" @mouseenter="item.active = true" @mouseleave="item.active = false">
           <div class="sub-li-top">
             <div class="sub-li-info">
               <p :class="['name', {'default-active': item.active }]">{{ item.name }}</p>
@@ -189,5 +189,8 @@ const height = ((210 * 2) + 12) + 'px'
 .names {
   color: var(--color-666);
   font-size: 13px;
+  &:hover {
+    color: var(--v-primary-base);
+  }
 }
 </style>

+ 18 - 0
src/layout/enterprise.vue

@@ -153,4 +153,22 @@ $top: 50px;
     cursor: pointer;
   }
 }
+/* 滚动条样式 */
+::-webkit-scrollbar {
+  -webkit-appearance: none;
+  width: 0px;
+  height: 0px;
+}
+/* 滚动条内的轨道 */
+::-webkit-scrollbar-track {
+  background: rgba(0, 0, 0, 0.1);
+  border-radius: 0;
+}
+/* 滚动条内的滑块 */
+::-webkit-scrollbar-thumb {
+  cursor: pointer;
+  border-radius: 5px;
+  background: rgba(0, 0, 0, 0.15);
+  transition: color 0.2s ease;
+}
 </style>

+ 15 - 2
src/plugins/curtain/components/point.vue

@@ -6,7 +6,7 @@
       max-width="400"
       :persistent="persistent || false"
     >
-      <div class="white-bgc pa-5" style="border-radius: 2px;">
+      <div class="white-bgc pa-5" style="border-radius: 2px; max-height: 600px; overflow-y: auto;">
         <template v-if="list?.length">
           <div class="d-flex align-center" v-for="(item, index) in list" :key="'curtainPoint' + index">
             <span style="color: darkorange; font-size: 44px;" class="mdi mdi-database-check-outline ml-2 mr-2"></span>
@@ -30,7 +30,7 @@ import { ref } from 'vue'
 defineOptions({name: 'curtain-point'})
 defineProps({
   message: String, // 单条数据,也可以用list['']
-  list: Array, // 多条数据一起展示传list
+  list: Array, // 多条数据一起展示传list['', '']
   persistent: Boolean, // false: 点击遮罩层关闭dialog
 })
 
@@ -38,4 +38,17 @@ const dialog = ref(true)
 
 </script>
 <style lang="scss" scoped>
+::-webkit-scrollbar {
+  width: 4px;
+  height: 10px;
+  // display: none;
+}
+::-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>

+ 8 - 0
src/views/publicRecruitment/myRecommendation.vue

@@ -33,12 +33,20 @@
 defineOptions({name: 'defineOptions-name'})
 import { ref } from 'vue'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { useUserStore } from '@/store/user'
 import { getHireJobCvRelCount, getHireJobCvRelPage } from '@/api/publicRecruitment'
 import TablePage from './components/table.vue'
 import bountyDisplay from './components/bountyDisplay.vue'
 
 const active = ref(0)
 
+// 更新账户信息
+const store = useUserStore()
+const updateAccountInfo = async () => {
+  await store.getUserAccountInfo()
+}
+updateAccountInfo()
+
 // 数据统计
 const statisticsList = ref([])
 const getData = async () => {

+ 6 - 1
src/views/recruit/enterprise/informationManagement/informationSettings.vue

@@ -7,7 +7,7 @@
       </v-tabs>
       <v-window v-model="tab" class="mt-3">
         <v-window-item :value="val.value" v-for="val in tabList" :key="val.value">
-          <component :is="val.path"></component>
+          <component :is="val.path" ref="tabRef"></component>
         </v-window-item>
       </v-window>
     </v-card>
@@ -33,6 +33,7 @@ const route = useRoute()
 // const router = useRouter()
 const { t } = useI18n()
 // tab
+const tabRef = ref()
 const tab = ref(1)
 const tabList = [
   { label: t('enterprise.infoSetting.basicInfo'), value: 1, path: basicInfo },
@@ -46,6 +47,10 @@ const tabList = [
 
 watch(() => route?.query?.tabKey, (newVal) => { if (newVal) tab.value = newVal - 0 })
 const handleTabClick = () => {
+  // 基本信息-获取企业管理员实名认证信息
+  if (tab.value === 1) {
+    tabRef.value[0].getAuthInfo()
+  }
   // router.push(`${route.path}?tabKey=${tab.value.toString()}`)
 }
 </script>

+ 5 - 1
src/views/recruit/enterprise/informationManagement/informationSettingsComponents/basicInfo.vue

@@ -80,7 +80,7 @@ const formItems = ref({
     },
     {
       type: 'text',
-      key: 'phone',
+      key: 'phoneNumber',
       value: '',
       col: 6,
       label: '联系电话'
@@ -241,6 +241,10 @@ const handleSave = async () => {
   Snackbar.success(t('common.saveMsg'))
   getBaseInfo()
 }
+
+defineExpose({
+  getAuthInfo
+})
 </script>
 
 <style lang="scss" scoped>

+ 8 - 6
src/views/recruit/enterprise/informationManagement/informationSettingsComponents/enterpriseAlbum.vue

@@ -3,7 +3,7 @@
   <div v-if="!imgList.length" class="text-center">
     <Empty :elevation="false" message="您还没有企业相册,马上去上传图片吧!"></Empty>
     <v-btn prepend-icon="mdi mdi-upload" color="primary" @click.stop="openFileInput">
-      {{ $t('common.uploadPictures') }}
+      上传图片/视频
       <input
         type="file"
         ref="fileInput"
@@ -16,7 +16,7 @@
   <div v-else>
     <div class="mb-3">
       <v-btn prepend-icon="mdi mdi-upload" color="primary" @click.stop="openFileInput">
-        {{ $t('common.uploadPictures') }}
+        上传图片/视频
         <input
           type="file"
           ref="fileInput"
@@ -26,9 +26,9 @@
         />
       </v-btn>
     </div>
-    <div class="imgItem" v-for="(item, index) in imgList" :key="index" @click="handleClick(index)">
-      <v-img v-if="checkIsImage(item)" width="100%" height="100%" :src="item"></v-img>
-      <video v-else class="videos-radius mr-3" :src="item" controls height="172" width="172" preload="preload"></video>
+    <div class="imgItem" v-for="(item, index) in imgList" :key="index">
+      <v-img v-if="checkIsImage(item)" width="100%" height="100%" :src="item" @click="handleClick(index)"></v-img>
+      <video v-else class="videos-radius mr-3" :src="item" controls height="172" width="172" preload="preload" @click="handleClick(index)"></video>
       <div class="operate">
         <span></span>
         <span class="mdi mdi-trash-can-outline" @click="handleDelete(item)"></span>
@@ -70,9 +70,10 @@ const handleClick = (index) => {
 const handleDelete = async (url) => {
   const index = imgList.value.indexOf(url)
   if (index === -1) return
-  imgList.value.splice(index, 1)
   Confirm('系统提示', '是否确认删除?').then(async () => {
     await updateEnterpriseAlbum({ albumList: imgList.value })
+    Snackbar.success('删除成功')
+    imgList.value.splice(index, 1)
   })
 }
 
@@ -88,6 +89,7 @@ const openFileInput = () => {
 
 // 上传
 const handleUploadFile = async (e) => {
+  if (!e.target.files.length) return
   const file = e.target.files[0]
   const size = file.size
   if (size / (1024*1024) > 10) {

+ 1 - 0
src/views/recruit/enterprise/informationManagement/informationSettingsComponents/enterpriseLogo.vue

@@ -65,6 +65,7 @@ const openFileInput = () => {
 // 上传
 const typeList = ['png', 'jpg', 'jpeg']
 const handleUploadFile = async (e) => {
+  if (!e.target.files.length) return
   const file = e.target.files[0]
   const size = file.size
   if (size / (1024*1024) > 10) {

+ 1 - 1
src/views/recruit/enterprise/informationSetting/index.vue

@@ -61,7 +61,7 @@ const formItems = ref({
       rules: [v => !!v || '请输入用户名']
     },
     {
-      type: 'text',
+      type: 'phoneNumber',
       key: 'phone',
       value: '',
       label: '手机号码 *',

+ 16 - 2
src/views/recruit/enterprise/positionManagement/components/baseInfo.vue

@@ -14,8 +14,18 @@
       </template>
       <template #numericalValue>
         <div class="font-size-14 color-error my-1">
-          <div>按众聘岗位分配比例计算后的赏金: 推荐人{{ calculation('hirePrice', 1) }}元、平台{{ calculation('hirePrice', 0) }}元、投递人{{ calculation('hirePrice', 2) }}元</div>
-          <div>按众聘岗位分配比例计算后的积分: 推荐人{{ calculation('hirePoint', 1) }}点、平台{{ calculation('hirePoint', 0) }}点、投递人{{ calculation('hirePoint', 2) }}点</div>
+          <div class="d-flex">
+            按众聘岗位分配比例计算后的赏金: 
+            <span class="calculation ml-3">推荐人{{ calculation('hirePrice', 1) }}元</span>
+            <span class="calculation">平台{{ calculation('hirePrice', 0) }}元</span>
+            <span class="calculation">投递人{{ calculation('hirePrice', 2) }}元</span>
+          </div>
+          <div class="d-flex">
+            按众聘岗位分配比例计算后的积分: 
+            <span class="calculation ml-3">推荐人{{ calculation('hirePoint', 1) }}点</span>
+            <span class="calculation">平台{{ calculation('hirePoint', 0) }}点</span>
+            <span class="calculation">投递人{{ calculation('hirePoint', 2) }}点</span>
+          </div>
         </div>
       </template>
       <template #positionId="{ item }">
@@ -282,4 +292,8 @@ defineExpose({
   top: -22px;
   left: 0;
 }
+.calculation {
+  display: block;
+  width: 120px;
+}
 </style>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 3 - 3
src/views/recruit/enterprise/positionManagement/components/item.vue


+ 1 - 0
src/views/recruit/enterprise/positionManagement/index.vue

@@ -68,6 +68,7 @@ const textItem = ref({
   width: 600,
   value: '',
   label: '请输入职位名称',
+  clearable: true,
   appendInnerIcon: 'mdi-magnify'
 })
 

+ 1 - 1
src/views/recruit/enterprise/register/register.vue

@@ -102,7 +102,7 @@ const formItems = ref({
       rules: [v => !!v || '请输入企业统一社会信用代码']
     },
     {
-      type: 'number',
+      type: 'phoneNumber',
       key: 'phone',
       value: '',
       label: '联系电话 *',

+ 54 - 23
src/views/recruit/enterprise/statistics/components/overview.vue

@@ -1,40 +1,63 @@
 <template>
-  <div class="overview my-5">
-    <div class="overview-item pa-5 color-666" v-for="(val, i) in overview" :key="i">
-      <div class="d-flex">
-        <div>{{ val.title }}</div>
-        <v-tooltip :text="val.desc" location="top">
-          <template v-slot:activator="{ props }">
-            <span v-bind="props" class="mdi mdi-information-outline ml-1"></span>
-          </template>
-        </v-tooltip>
-      </div>
-      <div class="overview-item-value my-3">{{ val.value }}</div>
-      <div class="font-size-14">
-        环比
-        <span class="color-error">0% ↑</span>
+  <div>
+    <div class="overview my-5">
+      <div class="overview-item pa-5 color-666" v-for="(val, i) in overview" :key="i">
+        <div class="d-flex">
+          <div>{{ val.title }}</div>
+          <v-tooltip :text="val.desc" location="top">
+            <template v-slot:activator="{ props }">
+              <span v-bind="props" class="mdi mdi-information-outline ml-1"></span>
+            </template>
+          </v-tooltip>
+        </div>
+        <div class="overview-item-value my-3">{{ overviewData[val.key] }}</div>
+        <div class="font-size-14">
+          环比
+          <span class="color-error">{{ typeof val.ratio === 'number' ? val.ratio : overviewData[val.ratio] }}% ↑</span>
+        </div>
       </div>
     </div>
+    <div id="myChart" style="width: 100%; height: 500px;background-color: #f7f8fa;border-radius: 8px;" class="pa-3"></div>
   </div>
-  <div id="myChart" style="width: 100%; height: 500px;background-color: #f7f8fa;border-radius: 8px;" class="pa-3"></div>
 </template>
 
 <script setup>
 defineOptions({ name: 'overview-page'})
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, watch } from 'vue'
 import * as echarts from 'echarts'
+import { getRecentConversations } from '@/api/recruit/enterprise/statistics'
+
+const props = defineProps({
+  query: Object
+})
 
+const overviewData = ref({
+  position: 0,
+  resume: 0,
+  viewResume: 0,
+  dealResume: 0,
+  interview: 0
+})
 // 数据概况
 const overview = ref([
-  { title: '职位浏览量', value: 86, desc: '指全部职位被候选人查看的人数总和' },
-  { title: '收到简历量', value: 12, desc: '指全部职位收到简历的总数' },
-  { title: '查看收到简历', value: 0, desc: '指查看候选人主动发送的简历数量' },
-  { title: '已处理简历', value: 4, desc: '指招聘方标记"通过筛选"与"不合适"的简历数' },
-  { title: '主动联系我的人', value: 0, desc: '指候选人主动发起沟通的人数' },
-  { title: '我主动联系的人', value: 5, desc: '指候选人主动发起沟通的人数' },
-  { title: '面试数量', value: 0, desc: '面试人数的总数' }
+  { title: '职位浏览量', key: 'position', ratio: 0, desc: '指全部职位被候选人查看的人数总和' },
+  { title: '收到简历量', key: 'resume', ratio: 0, desc: '指全部职位收到简历的总数' },
+  { title: '查看收到简历', key: 'viewResume', ratio: 0, desc: '指查看候选人主动发送的简历数量' },
+  { title: '已处理简历', key: 'dealResume', ratio: 0, desc: '指招聘方标记"通过筛选"与"不合适"的简历数' },
+  { title: '主动联系我的人', key: 'activeContactCount', ratio: 'qqactiveContactCount', desc: '指候选人主动发起沟通的人数' },
+  { title: '我主动联系的人', key: 'usContactCount', ratio: 'qqUsContactCount', desc: '指候选人主动发起沟通的人数' },
+  { title: '面试数量', key: 'interview', ratio: 0, desc: '面试人数的总数' }
 ])
 
+// 主动联系我的、我主动联系的人
+const accountInfo = localStorage.getItem('accountInfo') ? JSON.parse(localStorage.getItem('accountInfo')) : {}
+const getRecent = async () => {
+  if (!accountInfo || !accountInfo.userId) return
+  const data = await getRecentConversations({ userId: accountInfo.userId, ...props.query })
+  overviewData.value = Object.assign(overviewData.value, data)
+}
+getRecent()
+
 onMounted(() => {
   var chartDom = document.getElementById('myChart')
   var myChart = echarts.init(chartDom)
@@ -128,6 +151,14 @@ onMounted(() => {
   }
   option && myChart.setOption(option)
 })
+
+watch(
+  () => props.query,
+  (val) => {
+    if (val) getRecent()
+  },
+  { deep: true }
+)
 </script>
 
 <style scoped lang="scss">

+ 1 - 1
src/views/recruit/enterprise/statistics/overallAnalysis.vue

@@ -18,7 +18,7 @@
       <v-tabs v-model="tab" align-tabs="start" color="primary" bg-color="#f7f8fa">
         <v-tab :value="1">招聘进展</v-tab>
       </v-tabs>
-      <Overview class="mt-5"></Overview>
+      <Overview class="mt-5" :query="query"></Overview>
     </div>
     <div class="my-10">
       <v-tabs class="mb-5" v-model="tab" align-tabs="start" color="primary" bg-color="#f7f8fa">

+ 39 - 6
src/views/recruit/enterprise/systemManagement/groupAccount/components/record.vue

@@ -28,7 +28,7 @@ import { enterpriseInviteRecordPage } from '@/api/recruit/enterprise/enterpriseI
 defineOptions({name: 'groupAccount-component-record'})
 const props = defineProps({
   inviteType: {
-    type: String,
+    type: [String, Number],
     default: '0' // 类型 (0 邀请同事 | 1 邀请子公司),示例值(2)
   }
 })
@@ -38,25 +38,58 @@ const loading = ref(false)
 const query = ref({
   pageSize: 10,
   pageNo: 1,
-  type: props.inviteType
+  type: props.inviteType - 0
 })
 const headers = [
-  { title: '企业名称', key: 'enterpriseName' },
-  { title: '被邀请人', key: 'name' },
-  { title: t('enterprise.userManagement.invitationTime'), key: 'loginDate', value: item => timesTampChange(item.loginDate), sortable: false },
+  { title: '企业名称', key: 'showInfo.currentAccountEnterpriseAnotherName', sortable: false },
+  { title: '邀请人', key: 'showInfo.currentAccountUserName', sortable: false },
+  { title: 'invited', key: 'showInfo.invited', sortable: false },
+  { title: t('enterprise.userManagement.invitationTime'), key: 'showInfo.time', sortable: false },
 ]
+headers.forEach(e => { if (e.title === 'invited') e.title = props.inviteType - 0 ? '受邀企业' : '受邀人' })
+
 // 获取数据
 const getData = async () => {
   loading.value = true
   try {
+    const info = JSON.parse(localStorage.getItem('baseInfo')) || null
     const { list, total: number } = await enterpriseInviteRecordPage(query.value)
-    tableData.value = list
+    const invitedNames = await Promise.all(list.map(async () => getInvited()))
+    tableData.value = list.map((e, index) => {
+      const showInfo = {
+        currentAccountEnterpriseAnotherName: info?.enterpriseAnotherName || '--',
+        currentAccountUserName: info?.name || '--',
+        invited: invitedNames[index] || '--', // 使用预先获取的invited名称
+        time: e.createTime ? timesTampChange(e.createTime) : '--',
+      }
+      return { showInfo, ...e }
+    })
+    console.log('tableData.value', tableData.value)
     total.value = number
   } finally {
     loading.value = false
   }
 }
+
+const getInvited = async (val) => {
+  try {
+    if (val) {
+      const api = props.inviteType - 0 ? enterpriseInviteRecordPage: enterpriseInviteRecordPage
+      const { data } = await api(query.value)
+      return data.name
+    } else {
+      return '-占位-'
+    }
+  } catch (error) {
+    console.log('error', error)
+  }
+}
 getData()
+
+const handleChangePage = (index) => {
+  query.value.pageNo = index
+  getData()
+}
 </script>
 <style lang="scss" scoped>
 </style>

+ 1 - 1
src/views/recruit/enterprise/systemManagement/groupAccount/components/simplePageForm.vue

@@ -24,7 +24,7 @@ const items = ref({
       rules: [v => !!v || '请输入姓名']
     },
     {
-      type: 'text',
+      type: 'phoneNumber',
       key: 'phone',
       value: '',
       clearable: true,

+ 4 - 4
src/views/recruit/enterprise/talentPool/components/details.vue

@@ -1,7 +1,7 @@
 <!-- 人才库 - 人才详情 -->
 <template>
   <div class="d-flex justify-center mb-8">
-    <div v-if="Object.keys(cvData).length" style="width: 940px;overflow-y: auto;background: #fff;" class="px-8 pb-12 pt-3 my-n3 mr-3">
+    <div v-if="Object.keys(cvData).length" style="width: 940px;background: #fff;" class="px-8 pb-12 pt-3 my-n3 mr-3">
       <!-- 基本信息 -->
       <baseInfo class="mt-5" :data="cvData.person"></baseInfo>
       <!-- 个人优势 -->
@@ -45,9 +45,9 @@
         <attachmentResume style="flex: 1;"></attachmentResume>
       </div> -->
     </div>
-    <div class="operate pa-3">
+    <!-- <div class="operate pa-3">
       <v-list>
-        <!-- <v-list-subheader class="title">简历助手</v-list-subheader> -->
+        <v-list-subheader class="title">简历助手</v-list-subheader>
         <v-list-item
           v-for="(item, i) in operateItems" :key="'简历助手' + i"
           color="primary"
@@ -57,7 +57,7 @@
         >
         </v-list-item>
       </v-list>
-    </div>
+    </div> -->
   </div>
 </template>
 

+ 9 - 33
src/views/recruit/personal/PersonalCenter/components/interview/item.vue

@@ -41,15 +41,10 @@
         </div>
       </div>
   </div>
-
-  <CtDialog :visible="show" title="同意面试邀请" :footer="true" widthType="2" @close="handleClose" @submit="handleSubmit">
-    <TextInput v-model="query.phone" :item="textItem"></TextInput>
-  </CtDialog>
 </template>
 
 <script setup>
 defineOptions({ name: 'interview-item'})
-import { ref } from 'vue'
 import { useI18n } from '@/hooks/web/useI18n'
 import { timesTampChange } from '@/utils/date'
 import { userInterviewInviteReject, userInterviewInviteConsent } from '@/api/recruit/personal/personalCenter'
@@ -64,16 +59,6 @@ const props = defineProps({
     default: () => []
   }
 })
-const show = ref(false)
-const query = ref({
-  id: null,
-  phone: null
-})
-const textItem = ref({
-  type: 'text',
-  clearable: true,
-  label: '联系号码 *'
-})
 
 // 企业详情
 const handleToEnterprise = (item) => {
@@ -85,29 +70,20 @@ const handleToEnterprise = (item) => {
 // 同意
 const handleAgree = (val) => {
   if (!val.id) return
-  query.value.id = val.id
+  const query = {
+    id: val.id
+  }
   const baseInfo = localStorage.getItem('baseInfo')
   if (baseInfo) {
     const { phone } = JSON.parse(baseInfo)
-    query.value.phone = phone
+    query.phone = phone
   }
-  show.value = true
-}
 
-const handleClose = () => {
-  show.value = false
-  query.value = {
-    id: null,
-    phone: null
-  }
-}
-
-const handleSubmit = async () => {
-  if (!query.value.phone) return Snackbar.warning('请填写您的联系号码')
-  await userInterviewInviteConsent(query.value)
-  Snackbar.success(t('common.operationSuccessful'))
-  handleClose()
-  emits('refresh')
+  Confirm(t('common.confirmTitle'), '是否确定接收此面试邀请?').then(async () => {
+    await userInterviewInviteConsent(query)
+    Snackbar.success(t('common.operationSuccessful'))
+    emits('refresh')
+  })
 }
 
 // 拒绝

+ 11 - 11
src/views/recruit/personal/company/index.vue

@@ -14,8 +14,8 @@
       <companyItem class="mt-3" :list="items"></companyItem>
       <MPagination
         :total="total"
-        :page="pageInfo.pageNo"
-        :limit="pageInfo.pageSize"
+        :page="query.pageNo"
+        :limit="query.pageSize"
         @handleChange="handleChangePage"
       ></MPagination>
     </div>
@@ -43,12 +43,9 @@ const clear = ref(false)
 
 const total = ref(0)
 const items = ref([])
-const pageInfo = ref({
-  pageSize: 10,
-  pageNo: 1
-})
 const query = ref({
-  ...pageInfo.value
+  pageNo: 1,
+  pageSize: 12
 })
 
 const dealRouteQuery = (data) => {
@@ -74,15 +71,18 @@ const handleSearch = async (val, key) => {
 
 const getCompanyData = async () => {
   const { list, total: number } = await getEnterpriseSearch(query.value)
+  if (!list.length) {
+    list.value = []
+    total.value = 0
+    return
+  }
   total.value = number
   items.value = dealDictArrayData([], list)
 }
 
 const handleClear = () => {
   clear.value = true
-  query.value = {
-    ...pageInfo.value
-  }
+  query.value.pageNo = 1
   router.push(route.path)
   getCompanyData()
 }
@@ -103,7 +103,7 @@ if (Object.keys(route.query).length) {
 
 // 分页
 const handleChangePage = (index) => {
-  pageInfo.value.pageNo = index
+  query.value.pageNo = index
   getCompanyData()
 }
 </script>

+ 3 - 1
src/views/recruit/personal/position/components/conditionFilter/areaType.vue

@@ -35,7 +35,9 @@ let selectedItems = ref([])
 getDict('menduner_area_type', {}, 'areaList').then(({ data }) => {
   data = data?.length && data || []
   const arr = props.list.map(e => {
-    const { id, parentId, type, name: label } = data.find(k => Number(k.id) === Number(e.key))
+    const obj = data.find(k => Number(k.id) === Number(e.key))
+    if (!obj) return
+    const { id, parentId, type, name: label } = obj
     return { id, label, number: e.value, parentId, type }
   })
   items.value = [{ id: -1, label: '全部' }, ...arr]

+ 1 - 1
src/views/recruit/personal/remuse/components/basicInfo.vue

@@ -205,7 +205,7 @@ const items = ref({
       },
     },
     {
-      type: 'text',
+      type: 'phoneNumber',
       key: 'phone',
       value: null,
       default: null,

+ 1 - 1
src/views/recruit/personal/shareJob/form/simpleInfo.vue

@@ -24,7 +24,7 @@ const items = ref({
       rules: [v => !!v || '请输入姓名']
     },
     {
-      type: 'text',
+      type: 'phoneNumber',
       key: 'phone',
       value: '',
       clearable: true,

+ 1 - 1
src/views/recruit/personal/shareJob/form/upload.vue

@@ -50,7 +50,7 @@ const items = ref({
     //   rules: [v => !!v || '请填写姓名']
     // },
     // {
-    //   type: 'text',
+    //   type: 'phoneNumber',
     //   key: 'phone',
     //   value: '',
     //   clearable: true,

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio