소스 검색

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

zhengnaiwen_citu 10 달 전
부모
커밋
66d5eaf9b9
63개의 변경된 파일575개의 추가작업 그리고 264개의 파일을 삭제
  1. 1 0
      components.d.ts
  2. 15 0
      src/api/recruit/enterprise/personnel/index.js
  3. 23 0
      src/api/recruit/personal/personalCenter/index.js
  4. 14 0
      src/api/recruit/personal/resume/index.js
  5. 1 1
      src/components/AreaSelect/index.vue
  6. 1 1
      src/components/CtDialog/index.vue
  7. 1 1
      src/components/CtForm/index copy.vue
  8. 1 1
      src/components/CtForm/index.vue
  9. 1 1
      src/components/CtPagination/index.vue
  10. 1 1
      src/components/FormUI/TextInput/index.vue
  11. 1 1
      src/components/FormUI/autocomplete/index.vue
  12. 19 16
      src/components/FormUI/checkbox/index.vue
  13. 1 1
      src/components/FormUI/combobox/index.vue
  14. 1 1
      src/components/FormUI/comboboxZhAndEn/index.vue
  15. 1 1
      src/components/FormUI/datePicker/index.vue
  16. 8 2
      src/components/FormUI/nestedListGroup/components/listGroup.vue
  17. 1 1
      src/components/FormUI/nestedListGroup/index.vue
  18. 1 1
      src/components/FormUI/radioGroup/index.vue
  19. 1 1
      src/components/FormUI/textArea/index.vue
  20. 78 0
      src/components/Upload/img.vue
  21. 1 1
      src/components/VerificationCode/index.vue
  22. 1 1
      src/components/jobTypeCard/index.vue
  23. 1 1
      src/layout/personal/navBar.vue
  24. 3 1
      src/locales/en.js
  25. 3 1
      src/locales/zh-CN.js
  26. 28 0
      src/router/modules/common.js
  27. 0 28
      src/router/modules/components/recruit/personal.js
  28. 1 1
      src/views/login/components/passwordPage.vue
  29. 1 1
      src/views/login/index.vue
  30. 33 2
      src/views/recruit/enterprise/informationManagement/informationSettingsComponents/authentication.vue
  31. 19 11
      src/views/recruit/enterprise/interview/index.vue
  32. 17 3
      src/views/recruit/enterprise/personnelManagement/components/screen.vue
  33. 32 6
      src/views/recruit/enterprise/personnelManagement/components/table.vue
  34. 12 5
      src/views/recruit/enterprise/personnelManagement/index.vue
  35. 8 1
      src/views/recruit/enterprise/positionManagement/components/add.vue
  36. 38 78
      src/views/recruit/enterprise/positionManagement/components/baseInfo.vue
  37. 1 1
      src/views/recruit/enterprise/positionManagement/components/item.vue
  38. 18 5
      src/views/recruit/enterprise/register/inReview.vue
  39. 16 3
      src/views/recruit/enterprise/register/register.vue
  40. 10 10
      src/views/recruit/enterprise/systemManagement/groupAccount/components/link.vue
  41. 0 1
      src/views/recruit/enterprise/systemManagement/groupAccount/index.vue
  42. 40 5
      src/views/recruit/enterprise/systemManagement/groupAccount/inviteConfirmEnt.vue
  43. 1 1
      src/views/recruit/enterprise/talentPool/components/details/baseInfo.vue
  44. 1 1
      src/views/recruit/enterprise/talentPool/components/details/jobIntention.vue
  45. 1 1
      src/views/recruit/enterprise/talentPool/components/details/projectExperience.vue
  46. 17 18
      src/views/recruit/enterprise/talentPool/components/details/vocationalSkills.vue
  47. 1 1
      src/views/recruit/enterprise/talentPool/components/details/workExperience.vue
  48. 4 3
      src/views/recruit/personal/PersonalCenter/components/interview/index.vue
  49. 32 0
      src/views/recruit/personal/PersonalCenter/components/interviewSchedule.vue
  50. 1 1
      src/views/recruit/personal/PersonalCenter/dynamic/left.vue
  51. 20 3
      src/views/recruit/personal/PersonalCenter/dynamic/right.vue
  52. 1 1
      src/views/recruit/personal/position/components/conditionFilter/JobType.vue
  53. 1 1
      src/views/recruit/personal/position/components/conditionFilter/areaType.vue
  54. 1 1
      src/views/recruit/personal/position/components/conditionFilter/educationType.vue
  55. 1 1
      src/views/recruit/personal/position/components/conditionFilter/expType.vue
  56. 1 1
      src/views/recruit/personal/position/components/conditionFilter/financingStatus.vue
  57. 1 1
      src/views/recruit/personal/position/components/conditionFilter/payScope.vue
  58. 1 1
      src/views/recruit/personal/position/components/conditionFilter/scale.vue
  59. 7 3
      src/views/recruit/personal/position/components/details.vue
  60. 1 1
      src/views/recruit/personal/position/components/jobDetails/promptToUpload.vue
  61. 1 1
      src/views/recruit/personal/position/components/jobDetails/selectResumeDialog.vue
  62. 26 25
      src/views/recruit/personal/remuse/components/vocationalSkills.vue
  63. 1 1
      src/views/recruit/personal/shareJob/components/login.vue

+ 1 - 0
components.d.ts

@@ -27,6 +27,7 @@ declare module 'vue' {
     Empty: typeof import('./src/components/Empty/index.vue')['default']
     HeadSearch: typeof import('./src/components/headSearch/index.vue')['default']
     HotPromoted: typeof import('./src/components/Enterprise/hotPromoted.vue')['default']
+    Img: typeof import('./src/components/Upload/img.vue')['default']
     'Index copy': typeof import('./src/components/CtForm/index copy.vue')['default']
     IndustryTypeCard: typeof import('./src/components/industryTypeCard/index.vue')['default']
     Info: typeof import('./src/components/Enterprise/info.vue')['default']

+ 15 - 0
src/api/recruit/enterprise/personnel/index.js

@@ -20,4 +20,19 @@ export const personEntryByEnterprise = async (ids) => {
   return await request.post({
     url: `/app-admin-api/menduner/system/person-cv/entry?ids=${ids}`
   })
+}
+
+// 招聘端-牛人管理-不合适
+export const personCvUnfitPage = async (params) => {
+  return await request.get({
+    url: '/app-admin-api/menduner/system/person-cv/unfitPage',
+    params
+  })
+}
+
+// 招聘端-牛人管理-取消不合适
+export const personCvUnfitCancel = async (id) => {
+  return await request.post({
+    url: `/app-admin-api/menduner/system/person-cv/unfit/cancellation?id=${id}`
+  })
 }

+ 23 - 0
src/api/recruit/personal/personalCenter/index.js

@@ -7,4 +7,27 @@ export const getInterestedMePage = async (params) => {
     url: '/app-api/menduner/system/job-cv-rel/get/job/cv/look/page',
     params
   })
+}
+
+// 获取面试日程分页
+export const getUserInterviewInvitePage = async (params) => {
+  return await request.get({
+    url: '/app-api/menduner/system/interview-invite/page',
+    params
+  })
+}
+
+// 同意邀约面试
+export const userInterviewInviteConsent = async (data) => {
+  return await request.post({
+    url: '/app-api/menduner/system/interview-invite/consent',
+    data
+  })
+}
+
+// 拒绝邀约面试
+export const userInterviewInviteReject = async (id) => {
+  return await request.post({
+    url: `/app-api/menduner/system/interview-invite/reject?id=${id}`
+  })
 }

+ 14 - 0
src/api/recruit/personal/resume/index.js

@@ -104,6 +104,20 @@ export const getResumeProjectExp = async () => {
   })
 }
 
+// 获取-技能列表
+export const getSkillList = async () => {
+  return await request.get({
+    url: '/app-api/menduner/system/skill/list'
+  })
+}
+
+// 获取-技能树形
+export const getSkillTree = async () => {
+  return await request.get({
+    url: '/app-api/menduner/system/skill/get/tree'
+  })
+}
+
 // 获取-职业技能
 export const getResumePersonSkill = async () => {
   return await request.get({

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

@@ -41,7 +41,7 @@
 
 <script setup>
 import { getDict } from '@/hooks/web/useDictionaries'
-import { reactive, ref, defineEmits } from 'vue';
+import { reactive, ref } from 'vue';
 defineOptions({ name:'common-components-jobTypeCard'})
 
 const emits = defineEmits(['handleAreaClick'])

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

@@ -57,7 +57,7 @@
 </template>
 
 <script setup>
-import { ref, defineEmits, computed, watch  } from 'vue'
+import { ref, computed, watch  } from 'vue'
 defineOptions({ name: 'components-ct-dialog' })
 const emits = defineEmits(['update:visible', 'close', 'submit'])
 

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

@@ -246,7 +246,7 @@
 
 <script setup>
 // import DatePicker from '@/components/Form/datePicker.vue'
-import { ref, defineEmits  } from 'vue'
+import { ref  } from 'vue'
 defineOptions({ name: 'components-ct-form-copy' })
 const props = defineProps({items: Object})
 const inputUpdateValue = ref('')

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

@@ -115,7 +115,7 @@ import checkboxUI from './../FormUI/checkbox'
 import textareaUI from './../FormUI/textArea'
 import nestedListGroupUI from './../FormUI/nestedListGroup'
 import DatePicker from '@/components/DatePicker'
-import { ref, defineEmits, defineExpose } from 'vue'
+import { ref, defineExpose } from 'vue'
 const emit = defineEmits(['change', 'inputUpdateAutocomplete'])// 定义一个或多个自定义事件
 const props = defineProps({items: Object})
 const valid = ref(false)

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

@@ -30,7 +30,7 @@
 </template>
 
 <script setup>
-import { computed, watch, ref, defineEmits } from 'vue'
+import { computed, watch, ref } from 'vue'
 defineOptions({ name: 'components-ct-pagnation' })
 const props = defineProps({
   total: {

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

@@ -35,7 +35,7 @@
 </template>
 <script setup>
 import { debounce } from 'lodash'
-import { defineEmits, ref, watch } from 'vue';
+import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-text-field'})
 
 const props = defineProps({item: Object, modelValue: [String, Number]})

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

@@ -27,7 +27,7 @@
 </template>
 <script setup>
 import { debounce } from 'lodash'
-import { ref, defineEmits, watch } from 'vue';
+import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-autocomplete'})
 
 const props = defineProps({item: Object, modelValue: [String, Number, Boolean]})

+ 19 - 16
src/components/FormUI/checkbox/index.vue

@@ -1,24 +1,27 @@
 <template>
-  <v-checkbox
-    v-model="value"
-    v-for="k in item.items"
-    :key="k.key"
-    :label="k.label"
-    :value="k.value"
-    :disabled="k.disabled"
-    :color="item.color || 'primary'"
-    :density="k.density || 'compact'"
-    :multiple="k.multiple === false ? false : true"
-    class="mr-3"
-    hide-details
-    @update:modelValue="modelValueUpDate"
-  ></v-checkbox>
+  <div class="d-flex align-center">
+    <div class="mr-5 color-999" :style="`width: ${item.width || 120}px;`">{{ item.label }}</div>
+    <v-checkbox
+      v-model="value"
+      v-for="k in item.items"
+      :key="k.key"
+      :label="k.label"
+      :value="k.value"
+      :disabled="k.disabled"
+      :color="item.color || 'primary'"
+      :density="k.density || 'compact'"
+      :multiple="k.multiple === false ? false : true"
+      class="mr-3"
+      hide-details
+      @update:modelValue="modelValueUpDate"
+    ></v-checkbox>
+  </div>
 </template>
 <script setup>
-import { ref, defineEmits } from 'vue';
+import { ref } from 'vue';
 defineOptions({ name:'FormUI-v-checkbox'})
 
-const props = defineProps({item: Object, modelValue: [String, Number, Boolean]})
+const props = defineProps({item: Object, modelValue: Array})
 const emit = defineEmits(['update:modelValue', 'change'])
 const item = props.item
 const value = ref(props.modelValue)

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

@@ -21,7 +21,7 @@
 </template>
 <script setup>
 import { debounce } from 'lodash'
-import { ref, defineEmits } from 'vue';
+import { ref } from 'vue';
 defineOptions({ name:'FormUI-v-combobox'})
 
 const props = defineProps({item: Object, modelValue: [String, Number]})

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

@@ -20,7 +20,7 @@
   </div>
 </template>
 <script setup>
-import { ref, defineEmits } from 'vue';
+import { ref } from 'vue';
 defineOptions({ name:'FormUI-v-combobox'})
 
 const props = defineProps({item: Object, modelValue: [String, Number]})

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

@@ -17,7 +17,7 @@
   </div>
 </template>
 <script setup>
-import { defineEmits, ref, watch } from 'vue';
+import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-date-input'})
 
 const props = defineProps({item: Object, modelValue: String})

+ 8 - 2
src/components/FormUI/nestedListGroup/components/listGroup.vue

@@ -62,8 +62,14 @@ const option = propsData.option
 
 const handleClick = (val) => {
   val.levelUI = propsData.levelUI
-  if (val.levelUI >= option.selectLevel) {
-    emit('clickUpdate', val)
+  if (option.selectLevel === -1) {
+    // 只能选最后一级
+    if (!val.children?.length) emit('clickUpdate', val)
+  } else {
+    // 自定义可选层级数
+    if (val.levelUI >= option.selectLevel) {
+      emit('clickUpdate', val)
+    }
   }
 }
 

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

@@ -56,7 +56,7 @@
 
 <script setup>
 import listGroup from './components/listGroup'
-import { defineEmits, ref } from 'vue';
+import { ref } from 'vue';
 defineOptions({ name:'FormUI-nestedListGroup'})
 const propsData = defineProps({item: Object, modelValue: [String, Number]})
 const item = propsData.item

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

@@ -25,7 +25,7 @@
 </template>
 
 <script setup>
-import { ref, defineEmits, watch } from 'vue';
+import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-radio-group'})
 
 const props = defineProps({item: Object, modelValue: [String, Number, Boolean]})

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

@@ -21,7 +21,7 @@
   </div>
 </template>
 <script setup>
-import { defineEmits, ref, watch } from 'vue';
+import { ref, watch } from 'vue';
 defineOptions({ name:'FormUI-v-textarea'})
 
 const props = defineProps({item: Object, modelValue: [String, Number]})

+ 78 - 0
src/components/Upload/img.vue

@@ -0,0 +1,78 @@
+<template>
+  <div v-if="!src" class="upload d-flex align-center justify-center" @click="openFileInput">
+    <v-icon color="#ccc" size="50">mdi-plus</v-icon>
+    <input
+      type="file"
+      ref="fileInput"
+      accept="image/*"
+      style="display: none;"
+      @change="handleUploadFile"
+    />
+  </div>
+  <div v-else style="position: relative;">
+    <v-img :src="src" width="120" height="120" rounded></v-img>
+    <v-icon color="primary" class="close" @click="handleClose">mdi-close-circle</v-icon>
+  </div>
+</template>
+
+<script setup>
+// 图片上传
+defineOptions({ name: 'upload-img'})
+import { ref } from 'vue'
+import { uploadFile } from '@/api/common'
+import { useI18n } from '@/hooks/web/useI18n'
+import Snackbar from '@/plugins/snackbar'
+
+const emit = defineEmits(['success', 'delete'])
+
+const { t } = useI18n()
+const src = ref('')
+
+// 选择文件
+const fileInput = ref()
+const clicked = ref(false)
+const openFileInput = () => {
+  if (clicked.value) return
+  clicked.value = true
+  fileInput.value.click()
+  clicked.value = false
+}
+
+// 文件上传
+const handleUploadFile = async (e) => {
+  const file = e.target.files[0]
+  const size = file.size
+  if (size / (1024*1024) > 10) {
+    Snackbar.warning(t('common.fileSizeExceed'))
+    return
+  }
+  const formData = new FormData()
+  formData.append('file', file)
+  const { data } = await uploadFile(formData)
+  if (!data) return Snackbar.error('上传失败')
+  src.value = data
+  Snackbar.success(t('common.uploadSucMsg'))
+  emit('success', data)
+}
+
+const handleClose = () => {
+  src.value = ''
+  emit('delete')
+}
+</script>
+
+<style scoped lang="scss">
+.upload {
+  width: 120px;
+  height: 120px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  cursor: pointer;
+}
+.close {
+  position: absolute;
+  top: -10px;
+  right: -10px;
+  cursor: pointer;
+}
+</style>

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

@@ -40,7 +40,7 @@
 
 <script setup>
 defineOptions({ name: 'verification-code' })
-import { ref, reactive, defineExpose, defineEmits } from 'vue'
+import { ref, reactive, defineExpose } from 'vue'
 import { setCodeTime } from '@/utils/code'
 import { sendSmsCode } from '@/api/common/index'
 import { useI18n } from '@/hooks/web/useI18n'

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

@@ -44,7 +44,7 @@
 <script setup>
 import { getDict } from '@/hooks/web/useDictionaries'
 import { buryingPoint } from '@/hooks/web/buryingPoint'
-import { reactive, ref, defineEmits } from 'vue';
+import { reactive, ref } from 'vue';
 defineOptions({ name:'common-components-jobTypeCard'})
 
 const emits = defineEmits(['handleJobClick', 'jobClick'])// 定义一个或多个自定义事件

+ 1 - 1
src/layout/personal/navBar.vue

@@ -28,7 +28,7 @@
         
         <div class="d-flex user-nav">
           <div class="btns d-flex align-center" v-if="!getToken()">
-            <v-btn class="half-button" border color="primary" size="small" @click="handleLogin">{{ $t('login.register') }}</v-btn>
+            <v-btn class="half-button" border color="primary" size="small" @click="handleLogin">{{ $t('login.loginOrRegister') }}</v-btn>
           </div>
           
           <!-- 头像用户名 -->

+ 3 - 1
src/locales/en.js

@@ -87,7 +87,8 @@ export default {
     password: 'Password',
     login: 'Sign in',
     reLogin: 'Sign in again',
-    register: 'Sign in or Register',
+    loginOrRegister: 'Sign in or Register',
+    register: 'Register',
     checkPassword: 'Confirm password',
     mobileNumber: 'Mobile Number',
     mobileNumberPlaceholder: 'Please Enter Mobile Number',
@@ -236,6 +237,7 @@ export default {
     currentAddress: 'Current address',
     topResume: 'Top resume',
     refreshResume: 'Refresh resume',
+    interviewSchedule: 'Interview schedule',
     increaseMoreExposure: 'Increase more exposure',
     enhanceResumeActivity: 'Enhance resume activity',
     attachmentResume: 'Attachment resume',

+ 3 - 1
src/locales/zh-CN.js

@@ -87,7 +87,8 @@ export default {
     password: '密码',
     login: '登录',
     reLogin: '重新登录',
-    register: '登录/注册',
+    loginOrRegister: '登录/注册',
+    register: '注册',
     checkPassword: '确认密码',
     mobileNumber: '手机号码',
     mobileNumberPlaceholder: '请输入手机号码',
@@ -236,6 +237,7 @@ export default {
     currentAddress: '现居地址',
     topResume: '置顶简历',
     refreshResume: '刷新简历',
+    interviewSchedule: '面试日程',
     increaseMoreExposure: '增加更多曝光度',
     enhanceResumeActivity: '提升简历活跃度',
     attachmentResume: '附件简历',

+ 28 - 0
src/router/modules/common.js

@@ -51,6 +51,34 @@ const common = [
     },
     component: () => import('@/views/recruit/enterprise/systemManagement/groupAccount/inviteConfirmEnt.vue')
   },
+  {
+    path: '/recruit/enterprise/register',
+    // component: Layout,
+    name: 'enterpriseRegister',
+    children: [
+      {
+        path: '/recruit/enterprise/register',
+        component: () => import('@/views/recruit/enterprise/register/register.vue'),
+        meta: {
+          title: '注册新企业'
+        },
+      },
+      {
+        path: '/recruit/enterprise/register/joiningEnterprise',
+        component: () => import('@/views/recruit/enterprise/register/joiningEnterprise'),
+        meta: {
+          title: '加入企业'
+        }
+      },
+      {
+        path: '/recruit/enterprise/register/inReview',
+        component: () => import('@/views/recruit/enterprise/register/inReview.vue'),
+        meta: {
+          title: '申请信息'
+        }
+      }
+    ]
+  },
 ]
 
 export default common

+ 0 - 28
src/router/modules/components/recruit/personal.js

@@ -74,34 +74,6 @@ const personal = [
       }
     ]
   },
-  {
-    path: '/recruit/enterprise/register',
-    component: Layout,
-    name: 'enterpriseRegister',
-    children: [
-      {
-        path: '/recruit/enterprise/register',
-        component: () => import('@/views/recruit/enterprise/register/register.vue'),
-        meta: {
-          title: '注册新企业'
-        },
-      },
-      {
-        path: '/recruit/enterprise/register/joiningEnterprise',
-        component: () => import('@/views/recruit/enterprise/register/joiningEnterprise'),
-        meta: {
-          title: '加入企业'
-        }
-      },
-      {
-        path: '/recruit/enterprise/register/inReview',
-        component: () => import('@/views/recruit/enterprise/register/inReview.vue'),
-        meta: {
-          title: '申请信息'
-        }
-      }
-    ]
-  },
   {
     path: '/publicRecruitment',
     component: Layout,

+ 1 - 1
src/views/login/components/passwordPage.vue

@@ -35,7 +35,7 @@
 </template>
 
 <script setup name="passwordPage">
-import { ref, reactive, defineExpose, defineEmits } from 'vue'
+import { ref, reactive, defineExpose } from 'vue'
 defineOptions({ name: 'password-form' })
 import { useI18n } from '@/hooks/web/useI18n'
 const { t } = useI18n()

+ 1 - 1
src/views/login/index.vue

@@ -61,7 +61,7 @@
           <qr-code></qr-code>
         </div>
         <v-btn v-if="!isPhone" :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click="handleLogin">
-          {{ tab === 1 ? $t('login.register') : $t('login.login') }}
+          {{ tab === 1 ? $t('login.loginOrRegister') : $t('login.login') }}
         </v-btn>
         <div class="login-tips mt-3">
           {{ $t('login.agreeLogin') }}

+ 33 - 2
src/views/recruit/enterprise/informationManagement/informationSettingsComponents/authentication.vue

@@ -13,8 +13,19 @@
   <div v-else>
     <div class="topTip">为了您在平台有更好的操作体验,请进行实名认证</div>
     <div class="d-flex align-center justify-center flex-column">
-      <CtForm ref="CtFormRef" :items="formItems" style="width: 300px;"></CtForm>
-      <v-btn class="buttons" color="primary" @click="authentication = !authentication">{{ $t('common.submit') }}</v-btn>
+      <CtForm ref="CtFormRef" :items="formItems" style="width: 300px;">
+        <template #idCardImg1="{ item }">
+          <div class="color-666 font-size-14 mr-5">{{ item.label }}</div>
+          <Img @success="val => item.value = val" @delete="item.value = ''"></Img>
+        </template>
+        <template #idCardImg2="{ item }">
+          <div class="mt-5 d-flex">
+            <div class="color-666 font-size-14 mr-5">{{ item.label }}</div>
+            <Img @success="val => item.value = val" @delete="item.value = ''"></Img>
+          </div>
+        </template>
+      </CtForm>
+      <v-btn class="buttons mt-5" color="primary" @click="authentication = !authentication">{{ $t('common.submit') }}</v-btn>
     </div>
   </div>
 </template>
@@ -42,9 +53,22 @@ const formItems = ref({
       value: '',
       label: '身份证号码 *',
       rules: [v => !!v || '请输入您的身份证号码']
+    },
+    {
+      slotName: 'idCardImg1',
+      value: '',
+      label: '身份证-国徽照 *',
+      rules: [v => !!v || '请上传']
+    },
+    {
+      slotName: 'idCardImg2',
+      value: '',
+      label: '身份证-人像照 *',
+      rules: [v => !!v || '请上传']
     }
   ]
 })
+
 </script>
 
 <style scoped lang="scss">
@@ -62,4 +86,11 @@ const formItems = ref({
   font-size: 14px;
   padding: 25px;
 }
+.upload {
+  width: 120px;
+  height: 120px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  cursor: pointer;
+}
 </style>

+ 19 - 11
src/views/recruit/enterprise/interview/index.vue

@@ -96,14 +96,15 @@
                 <span>{{ statusList.find(e => e.value === item.status)?.label }}</span>
               </div>
               <div>
-                <span v-if="editStatus.indexOf(item.status)" class="font-size-15 color-primary" @click="handleActionClick(2, item)">修改面试</span>
+                <span v-if="editStatus.indexOf(item.status) !== -1" class="font-size-15 color-primary" @click="handleActionClick(2, item)">修改面试</span>
+                <span v-if="againStatus.indexOf(item.status) !== -1" class="font-size-15 color-primary" @click="handleActionClick(2, item)">重新邀约</span>
                 <v-menu>
                   <template v-slot:activator="{ props }">
                     <v-icon v-bind="props" class="mx-3" size="20" color="primary">mdi-dots-horizontal</v-icon>
                   </template>
                   <v-list>
                     <v-list-item
-                      v-for="(k, index) in actionItems"
+                      v-for="(k, index) in actionItems(item.status)"
                       :key="index"
                       :value="index"
                       color="primary"
@@ -130,7 +131,7 @@
   </v-card>
 
   <!-- 修改面试 -->
-  <CtDialog :visible="showInvite" :widthType="2" titleClass="text-h6" title="面试邀请" @close="handleClose" @submit="handleSubmit">
+  <CtDialog :visible="showInvite" :widthType="2" titleClass="text-h6" title="面试信息" @close="handleClose" @submit="handleSubmit">
     <InvitePage v-if="showInvite" ref="inviteRef" :itemData="itemData" :position="positionItems"></InvitePage>
   </CtDialog>
 
@@ -149,6 +150,7 @@ import Snackbar from '@/plugins/snackbar'
 import { getJobAdvertised } from '@/api/enterprise'
 import { dealDictArrayData } from '@/utils/position'
 import { timesTampChange, getStartAndEndOfDay } from '@/utils/date'
+import cloneDeep from 'lodash/cloneDeep'
 
 const cancelInvite = ref(false)
 const showInvite = ref(false)
@@ -158,15 +160,13 @@ const cancelQuery = ref({
   id: null,
   reason: null
 })
-const editStatus = ['99', '1', '0']
+const editStatus = ['1', '0'] // 修改面试状态
+const againStatus = ['98', '99'] // 重新邀约状态
 const statusList = ref()
 const itemData = ref({})
-// 状态
-const actionItems = ref([
-  // { title: '沟通', value: 1 },
-  // { title: '修改面试', value: 2 },
-  { title: '取消面试', value: 3 },
-  // { title: '面试记录', value: 4 }
+const actions = ref([
+  { title: '沟通', value: 1 },
+  { title: '面试记录', value: 4 }
 ])
 const total = ref(0)
 const query = ref({
@@ -182,6 +182,14 @@ const textItems = ref({
   clearable: true
 })
 
+// 操作状态
+// status:0待接受 1待面试 2即将面试 3已完成 4已反馈 5未能爽约 98拒绝 99已取消
+const actionItems = (status) => {
+  const data = cloneDeep(actions.value)
+  if (status === '0') data.splice(-1, 0, { title: '取消面试', value: 3 })
+  return data
+}
+
 // 状态字典
 const getStatusList = async () => {
   const { data } = await getDict('menduner_interview_invite_status')
@@ -251,7 +259,7 @@ getPositionList()
 
 // 操作按钮
 const handleActionClick = (value, item) => {
-  // 修改
+  // 修改、重新邀约
   if (value === 2) {
     itemData.value = item
     showInvite.value = true

+ 17 - 3
src/views/recruit/enterprise/personnelManagement/components/screen.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <div class="d-flex align-center">
     <CommonStyle v-for="(val, i) in list" :key="i" :btnTitle="val.title">
       <v-list>
         <v-list-item
@@ -14,23 +14,31 @@
         </v-list-item>
       </v-list>
     </CommonStyle>
+    <div class="mr-5" v-if="props.tab === 0">
+      <v-radio-group v-model="selected" inline style="height: 28px;" @update:modelValue="handleChangeSelected">
+        <v-radio v-model="selected" label="新投递" value="0" color="primary" hide-details density="compact" class="mr-3"></v-radio>
+        <v-radio v-model="selected" label="已查看" value="1" color="primary" hide-details density="compact"></v-radio>
+      </v-radio-group>
+    </div>
     <span class="reset-text cursor-pointer ml-3" @click="handleReset">重置</span>
   </div>
 </template>
 
 <script setup>
 defineOptions({ name: 'screen-page'})
-import { ref, defineProps, defineEmits, watch } from 'vue'
+import { ref, watch } from 'vue'
 import { getJobAdvertised } from '@/api/enterprise'
 import { getDict } from '@/hooks/web/useDictionaries'
 import { dealDictArrayData } from '@/utils/position'
 import CommonStyle from './commonStyle.vue'
 
-const emit = defineEmits(['search', 'reset'])
+const emit = defineEmits(['search', 'reset', 'select'])
 const props = defineProps({
   tab: Number
 })
 
+const selected = ref()
+
 const list = ref([
   {
     title: '应聘岗位',
@@ -101,9 +109,15 @@ const handleReset = () => {
     e.title = e.defaultTitle
     return e
   })
+  selected.value = ''
   emit('reset')
 }
 
+// 新投递&已查看选择
+const handleChangeSelected = (e) => {
+  emit('select', e)
+}
+
 watch(
   () => props.tab,
   () => {

+ 32 - 6
src/views/recruit/enterprise/personnelManagement/components/table.vue

@@ -33,9 +33,10 @@
         </div>
         <v-btn v-if="tab === 0 || tab === 1" color="primary" variant="text" @click="handleEliminate(item)">不合适</v-btn>
         <div v-if="tab === 1">
-          <v-btn color="primary" variant="text" @click="handleInterviewInvite(item)">邀请面试</v-btn>
+          <!-- <v-btn color="primary" variant="text" @click="handleInterviewInvite(item)">邀请面试</v-btn> -->
           <v-btn color="primary" variant="text" @click="handleAction('', 0, item)">入职</v-btn>
         </div>
+        <v-btn v-if="tab === 4" color="primary" variant="text" @click="handleCancelEliminate(item)">取消不合适</v-btn>
       </template>
     </v-data-table>
   </div>
@@ -43,9 +44,9 @@
 
 <script setup>
 defineOptions({ name: 'table-page'})
-import { ref, computed } from 'vue'
+import { ref, computed, watch } from 'vue'
 import { previewFile } from '@/utils'
-import { personJobCvLook, joinEliminate, personEntryByEnterprise } from '@/api/recruit/enterprise/personnel'
+import { personJobCvLook, joinEliminate, personEntryByEnterprise, personCvUnfitCancel } from '@/api/recruit/enterprise/personnel'
 import { useI18n } from '@/hooks/web/useI18n'
 import Snackbar from '@/plugins/snackbar'
 
@@ -73,6 +74,22 @@ const headers = ref([
   { title: '岗位薪资', key: 'job', value: item => `${item.job.payFrom}-${item.job.payTo}/${item.job.payName}`, sortable: false },
   { title: '操作', value: 'actions', sortable: false }
 ])
+const unfit = { title: '类型', key: 'unfitType', sortable: false, value: item => item.type === '0' ? '简历不合适' : '面试不合适' }
+const delivery = { title: '类型', key: 'deliveryType', sortable: false, value: item => item.status === '0' ? '新投递' : '已查看' }
+
+const list = [0, 4]
+watch(
+  () => props.tab,
+  (val) => {
+    if (list.indexOf(val) !== -1) {
+      headers.value.splice(-1, 0, val === 0 ? delivery : unfit)
+    } else {
+      const index = headers.value.findIndex(item => item.key === val === 0 ? 'deliveryType' : 'unfitType')
+      if (index > -1) headers.value.splice(index, 1)
+    }
+  },
+  { immediate: true }
+)
 
 // 人才详情
 const handleToPersonDetail = ({ userId, id }) => {
@@ -99,6 +116,7 @@ const handleEliminate = async (item) => {
   const query = {
     bizId: item.id,
     jobId: item.job.id,
+    userId: item.userId,
     type: props.tab === 0 ? '0' : '1' // 投递简历0 已邀约1
   }
   await joinEliminate(query)
@@ -106,6 +124,14 @@ const handleEliminate = async (item) => {
   emit('refresh')
 }
 
+// 取消不合适
+const handleCancelEliminate = async (item) => {
+  if (!item.id) return
+  await personCvUnfitCancel(item.id)
+  Snackbar.success(t('common.operationSuccessful'))
+  emit('refresh')
+}
+
 // 查看简历
 const handlePreviewResume = async ({ url, id }) => {
   if (!url || !id) return
@@ -113,9 +139,9 @@ const handlePreviewResume = async ({ url, id }) => {
   previewFile(url)
 }
 
-const handleInterviewInvite = (item) => {
-  console.log(item, 'item')
-}
+// const handleInterviewInvite = (item) => {
+//   console.log(item, 'item')
+// }
 </script>
 
 <style scoped lang="scss">

+ 12 - 5
src/views/recruit/enterprise/personnelManagement/index.vue

@@ -1,13 +1,13 @@
 <!-- 精英管理 -->
 <template>
-  <v-card class="pa-5 card-box">
+  <v-card class="pa-3 card-box">
     <div class="d-flex justify-space-between">
       <v-tabs v-model="tab" align-tabs="start" color="primary" bg-color="#f7f8fa">
         <v-tab v-for="k in tabList" :value="k.value" :key="k.value">{{ k.label }}</v-tab>
       </v-tabs>
       <TextInput v-model="textItems.value" :item="textItems" @appendInnerClick="handleSearch" @enter="handleSearch"></TextInput>
     </div>
-    <Screen :tab="tab" @search="handleScreen" @reset="handleScreenReset"></Screen>
+    <Screen :tab="tab" @search="handleScreen" @reset="handleScreenReset" @select="handleSelect"></Screen>
 
     <v-window v-model="tab" class="mt-1">
       <v-window-item v-for="k in tabList" :value="k.value" :key="k.value">
@@ -28,6 +28,7 @@
 defineOptions({ name: 'enterprise-personnelManagement-management'})
 import { ref } from 'vue'
 import { getPersonCvPage } from '@/api/enterprise'
+import { personCvUnfitPage } from '@/api/recruit/enterprise/personnel'
 import { dealDictObjData } from '@/utils/position'
 import { getInterviewInvitePage } from '@/api/recruit/enterprise/interview'
 import TablePage from './components/table.vue'
@@ -46,7 +47,7 @@ const tabList = ref([
   { label: '已邀约', value: 1, api: getInterviewInvitePage, status: '0' },
   { label: '已发offer', value: 2, api: getInterviewInvitePage, status: '1' },
   { label: '已入职', value: 3, api: getInterviewInvitePage, status: '2' },
-  { label: '不合适', value: 4 },
+  { label: '不合适', value: 4, api: personCvUnfitPage },
 ])
 const textItems = ref({
   type: 'text',
@@ -60,9 +61,8 @@ const textItems = ref({
 // 获取牛人列表
 const items = ref([])
 const getList = async () => {
-  if (tab.value === 4) return
   const api = tabList.value[tab.value].api
-  query.value.status = tab.value === 0 ? null : tabList.value[tab.value].status
+  if (tab.value !== 0) query.value.status = tabList.value[tab.value].status
   const { list, total: number } = await api(query.value)
   if (!list.length) {
     items.value = []
@@ -107,9 +107,16 @@ const handleScreenReset = () => {
     pageNo: 1,
     status: tab.value
   }
+  if (tab.value === 0) query.value.status = null
   if (textItems.value.value) query.value.name = textItems.value.value
   getList()
 }
+
+const handleSelect = (e) => {
+  query.value.pageNo = 1
+  query.value.status = e
+  getList()
+}
 </script>
 
 <style scoped lang="scss">

+ 8 - 1
src/views/recruit/enterprise/positionManagement/components/add.vue

@@ -98,8 +98,15 @@ const handleSave = async () => {
   const baseInfo = await baseInfoRef.value[0].getQuery()
   const requirement = await jobRequirementsRef.value[0].getQuery()
   if (!baseInfo || !requirement) return Snackbar.warning('请将信息填写完整')
+  // 判断是否有选择众聘岗位,选择了是否有填赏金或积分
+  if (baseInfo.hire) {
+    if (!baseInfo.hirePrice && !baseInfo.hirePoint) return Snackbar.warning('您选择的是众聘岗位,请填写奖励赏金或积分!')
+    if (Number(baseInfo.hirePrice) === 0 && Number(baseInfo.hirePoint) === 0) return Snackbar.warning('填写的赏金/积分不得小于1')
+  }
+
   const query = Object.assign(baseInfo, requirement)
-  // 有id则为编辑
+
+  // // 有id则为编辑
   if (route.query && route.query.id) query.id = route.query.id
   try {
     await saveJobAdvertised(query)

+ 38 - 78
src/views/recruit/enterprise/positionManagement/components/baseInfo.vue

@@ -1,15 +1,21 @@
 <template>
   <div>
-    <CtForm ref="formPageRef" :items="items" style="width: 600px;">
+    <CtForm ref="formPageRef" :items="items" style="width: 650px;">
       <template #explain>
-        <span style="color: var(--v-error-base); cursor: pointer;" @click="handleViewRule">
-          <v-icon size="25" color="error">mdi-help-circle-outline</v-icon>
-          众聘岗位规则说明
-        </span>
+        <div class="d-flex align-center font-size-13">
+          <div style="color: var(--v-error-base); cursor: pointer;" @click="handleViewRule">
+            <v-icon size="20" color="error">mdi-help-circle-outline</v-icon>
+            众聘岗位规则说明;
+          </div>
+          <div class=" ml-5" style="color: var(--v-error-base);">
+            众聘岗位分配比例:推荐人占比{{ ratio.recommendRate }}%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 平台占比{{ ratio.headhuntRate }}%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 投递人占比{{ ratio.cvRate }}%
+          </div>
+        </div>
       </template>
-      <template #ratio>
-        <div class="font-size-13 mb-3" style="color: red;">
-          众聘岗位分配比例:平台占比{{ ratio.headhuntRate }}%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 推荐人占比{{ ratio.recommendRate }}%&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 投递人占比{{ ratio.cvRate }}%
+      <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>
       </template>
       <template #positionId="{ item }">
@@ -40,6 +46,7 @@ import { reactive, ref, defineExpose, watch } from 'vue'
 import textUI from '@/components/FormUI/TextInput'
 import jobTypeCard from '@/components/jobTypeCard'
 import RulePage from './rule.vue'
+import { commissionCalculation } from '@/utils/position'
 import { getPublicRatio } from '@/api/recruit/enterprise/position'
 
 const props = defineProps({
@@ -49,42 +56,26 @@ const props = defineProps({
 const show = ref(false)
 const ratio = ref({})
 
-const getValue = (key) => {
-  return items.value.options.find(e => e.key === key)
+// 按分配比例计算金额积分
+const calculation = (key, type) => {
+  const value = items.value.options.find(e => e.key === key).value
+  return commissionCalculation(value, type)
 }
 
-// 众聘奖励类型
-const handleChangeHireType = () => {
-  const hireType = getValue('hireType')
-  let hirePrice = getValue('hirePrice')
-  let hirePoint = getValue('hirePoint')
-  if (hireType.value) {
-    hirePrice.hide = false
-    hirePoint.hide = true
-    hirePoint.value = null
-  } else {
-    hirePoint.hide = false
-    hirePrice.hide = true
-    hirePrice.value = null
-  }
+const getValue = (key) => {
+  return items.value.options.find(e => e.key === key)
 }
 
 // 是否众聘岗位
 const handleChangePublic = (val) => {
-  let hireType
   items.value.options.forEach(e => {
     if (!val && Object.prototype.hasOwnProperty.call(e, 'hide')) {
       e.hide = true
       e.value = null
       return
     }
-    if (e.key === 'hireType') {
-      e.hide = !val
-      e.value = props.itemData && props.itemData.hirePoint ? false : true
-      hireType = e
-    }
-    if (Object.prototype.hasOwnProperty.call(e, 'show')) {
-      if (hireType.value === e.show) e.hide = false
+    if (val && Object.prototype.hasOwnProperty.call(e, 'show')) {
+      e.hide = false
       return
     }
     if (e.slotName === 'explain') e.hide = val ? false : true
@@ -118,68 +109,37 @@ const items = ref({
       hide: true,
       flexStyle: 'mb-3'
     },
-    {
-      type: 'ifRadio',
-      key: 'hireType',
-      value: null,
-      label: '众聘奖励类型 *',
-      width: 120,
-      hide: true,
-      disabled: false,
-      noParam: true,
-      hideDetails: true,
-      items: [
-        { label: '赏金', value: true },
-        { label: '积分', value: false }
-      ],
-      change: handleChangeHireType
-    },
-    {
-      slotName: 'ratio',
-      noParam: true,
-      show: true,
-      hide: true
-    },
     {
       type: 'number',
       key: 'hirePrice',
       value: null,
-      label: '众聘赏金 *',
+      label: '众聘赏金',
       suffix: '元',
       hide: true,
       show: true,
-      rules: [
-        value => {
-          if (value) return true
-          return '请填写众聘赏金'
-        },
-        value => {
-          if (value >= 1) return true
-          return '赏金金额不得小于1'
-        }
-      ]
+      disabled: false,
+      hideDetails: true,
+      col: 6,
+      flexStyle: 'mr-3'
     },
     {
       type: 'number',
       key: 'hirePoint',
       value: null,
-      label: '众聘奖励积分数 *',
+      label: '众聘奖励积分数',
       suffix: '点',
       hide: true,
+      col: 6,
       disabled: false,
-      show: false,
-      rules: [
-        value => {
-          if (value) return true
-          return '请填写众聘众聘奖励积分数'
-        },
-        value => {
-          if (value >= 1) return true
-          return '积分数不得小于1'
-        }
-      ]
+      hideDetails: true,
+      show: false
+    },
+    {
+      slotName: 'numericalValue',
+      noParam: true,
+      show: true,
+      hide: true
     },
-    
     {
       type: 'text',
       key: 'name',

+ 1 - 1
src/views/recruit/enterprise/positionManagement/components/item.vue

@@ -75,7 +75,7 @@
 <script setup>
 import { commissionCalculation } from '@/utils/position'
 defineOptions({ name: 'enterprise-position-item'})
-import { defineEmits, ref, watch } from 'vue'
+import { ref, watch } from 'vue'
 import { useRouter } from 'vue-router'
 import { timesTampChange } from '@/utils/date'
 import { useI18n } from '@/hooks/web/useI18n'

+ 18 - 5
src/views/recruit/enterprise/register/inReview.vue

@@ -1,8 +1,9 @@
 <!-- 注册企业进度 -->
 <template>
   <div class="pt-5">
-    <v-card class="default-width pa-5">
-      <div style="width: 600px;margin: 80px auto;">
+    <v-card class="pa-5" :class="isMobile? 'mobileBox' : 'default-width'" :elevation="isMobile? '0' : '3'">
+
+      <div style="margin: 80px auto;" :style="{width: isMobile ? '' : '600px'}">
 
         <!-- 提交企业注册以后跳转显示页面 -->
         <div v-if="!applyInfo || !(Object.keys(applyInfo).length)">
@@ -34,8 +35,7 @@
         <div v-else-if="applyInfo.status === '1'">
           <span>审核通过</span>
         </div>
-        
-        <div class="text-center">
+        <div class="text-center" v-if="!isMobile">
           <v-btn class="mt-16" color="warning" to="/recruitHome">{{ $t('common.toHome') }}</v-btn>
           <v-btn v-if="applyInfo.status === '2'" class="mt-16 ml-12" color="primary" to="/recruit/enterprise/register">{{ $t('common.resubmit') }}</v-btn>
         </div>
@@ -47,11 +47,18 @@
 <script setup>
 import { timesTampChange } from '@/utils/date'
 import { getUserRegisterEnterpriseApply } from '@/api/personal/user'
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
 defineOptions({name: 'enterprise-enterpriseRegister-inReview'})
 
 const applyInfo = ref({})
 
+// 组件挂载后添加事件监听器  
+const isMobile = ref(false)
+onMounted(() => {
+  const userAgent = navigator.userAgent
+  isMobile.value = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(userAgent)
+})
+
 // 查看用户是否有在申请中的数据
 const getApplyInfo = async () => {
   const data = await getUserRegisterEnterpriseApply() // 已经有数据说明已经申请过了
@@ -69,4 +76,10 @@ getApplyInfo()
 
 </script>
 <style lang="scss" scoped>
+.mobileBox {
+  width: 100vw;
+  .resume-header {
+    margin-bottom: 12px;
+  }
+}
 </style>

+ 16 - 3
src/views/recruit/enterprise/register/register.vue

@@ -1,12 +1,12 @@
 <template>
   <div class="pt-5">
-    <v-card class="default-width pa-5">
+    <v-card class="pa-5" :class="isMobile? 'mobileBox' : 'default-width'" :elevation="isMobile? '0' : '3'">
       <!-- 标题 -->
       <div class="resume-header">
         <div class="resume-title">{{ $t('enterprise.registeringNewEnterprise') }}</div>
       </div>
       <!-- 表单 -->
-      <div class="CtFormClass" style="width: 600px;">
+      <div class="CtFormClass" :style="{width: isMobile ? '' : '600px'}">
         <CtForm ref="CtFormRef" :items="formItems" style="width: 100%;"></CtForm>
         <!-- 上传照片 -->
         <div style="color: var(--color-999);">
@@ -68,7 +68,7 @@ import { uploadFile } from '@/api/common'
 import { useI18n } from '@/hooks/web/useI18n'
 import { useRouter } from 'vue-router'
 import { enterpriseRegisterApply } from '@/api/personal/user'
-import { ref } from 'vue';
+import { onMounted, ref } from 'vue';
 defineOptions({name: 'enterprise-enterpriseRegister-register'})
 const { t } = useI18n()
 const CtFormRef = ref()
@@ -76,6 +76,13 @@ const router = useRouter()
 const fileVerify = ref(false)
 const loginLoading = ref(false)
 
+// 组件挂载后添加事件监听器  
+const isMobile = ref(false)
+onMounted(() => {
+  const userAgent = navigator.userAgent
+  isMobile.value = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(userAgent)
+})
+
 const formItems = ref({
   options: [
     {
@@ -194,4 +201,10 @@ if (info && Object.keys(info).length) {
     .icon { color: var(--v-error-base); }
   }
 }
+.mobileBox {
+  width: 100vw;
+  .resume-header {
+    margin-bottom: 12px;
+  }
+}
 </style>

+ 10 - 10
src/views/recruit/enterprise/systemManagement/groupAccount/components/link.vue

@@ -7,10 +7,10 @@
         <span v-if="code">{{ shareUrlTxt }}</span>
         <span v-else class="color-666">点击刷新生成邀请链接</span>
       </div>
-      <v-btn color="primary" class="mr-3" @click="copy()">{{ $t('common.copy') }}</v-btn>
+      <!-- <v-btn color="primary" class="mr-3" @click="copy()">{{ $t('common.copy') }}</v-btn> -->
       <v-btn color="green" variant="outlined" @click="refresh()">{{ $t('common.refresh') }}</v-btn>
     </div>
-    <div class="mt-5 color-777">链接{{ day }}天内有效</div>
+    <div class="mt-5 color-777">请复制链接进行分享,链接{{ day }}天内有效</div>
   </div>
 </template>
 
@@ -78,14 +78,14 @@ const refresh = async () => {
   }
 }
 
-const copy = async () => {
-  try {
-    await navigator.clipboard.writeText(shareUrlTxt.value)
-    Snackbar.success('复制成功')
-  } catch (err) {
-    Snackbar.error('复制失败,请手动复制。')
-  }
-}
+// const copy = async () => {
+//   try {
+//     await navigator.clipboard.writeText(shareUrlTxt.value)
+//     Snackbar.success('复制成功')
+//   } catch (err) {
+//     Snackbar.error('复制失败,请手动复制。')
+//   }
+// }
 
 </script>
 <style lang="scss" scoped>

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

@@ -214,5 +214,4 @@ const handleSubmit = async () => {
 </script>
 
 <style scoped lang="scss">
-
 </style>

+ 40 - 5
src/views/recruit/enterprise/systemManagement/groupAccount/inviteConfirmEnt.vue

@@ -25,10 +25,24 @@
           <div v-show="!showCompanySelect">
             <phoneFrom ref="phoneRef" @handleEnter="handleClick()" :style="{'width': isMobile ? '100%' : '350px' }"></phoneFrom>
             <v-btn :loading="loginLoading" color="warning" class="white--text mt-3" min-width="350" @click="handleConfirmJoin" :style="{'width': isMobile ? '100%' : '350px' }">
-              {{ $t('common.confirmJoin') }}
+              {{ quickRegister ? $t('login.register') : $t('common.confirmJoin') }}
             </v-btn>
             <div class="mt-3" style="font-size: 13px;text-align: center;">
               <div>注:请使用已经申请好的企业账户加入集团</div>
+              <div style="color: red; cursor: pointer;">
+                <span
+                  v-if="quickRegister"
+                  @click="quickRegister = false"
+                >
+                  已有企业账号,去登录
+                </span>
+                <span
+                  v-else
+                  @click="handleRegister"
+                >
+                  没有企业账号?去注册
+                </span>
+              </div>
             </div>
           </div>
         </template>
@@ -39,11 +53,12 @@
 
 <script setup>
 defineOptions({ name: 'inviteConfirmEnt'})
+import { useRouter } from 'vue-router'; const router = useRouter()
 import { ref, onMounted, reactive } from 'vue'
 import { useRoute } from 'vue-router'; const route = useRoute()
 import { enterpriseInviteRecordConsent, getEnterpriseInfoByCode } from '@/api/recruit/enterprise/enterpriseInvite.js'
 import Snackbar from '@/plugins/snackbar'
-import { getUserBindEnterpriseList } from '@/api/personal/user'
+import { getUserBindEnterpriseList, getUserRegisterEnterpriseApply } from '@/api/personal/user'
 import companySelect from '@/views/login/components/companySelect.vue'
 import phoneFrom from '@/components/VerificationCode'
 import { getToken, setToken, setRefreshToken } from '@/utils/auth'
@@ -74,8 +89,10 @@ const handleConfirmJoin = async () => {
     const res = await smsLogin(phoneParams)
     setToken(res.accessToken)
     setRefreshToken(res.refreshToken)
-    localStorage.setItem('loginType', 'enterprise') // 不存在时刷新会出现重定向,值没有影响
-    getEnterpriseList()
+    localStorage.setItem('loginType', 'personal') // 不存在时刷新会出现重定向
+    quickRegister.value ? getApplyInfo() : getEnterpriseList()
+    // if (quickRegister.value) getApplyInfo()
+    // else getEnterpriseList()
   } catch (error) {
     Snackbar.error('查询用户数据失败')
   } finally {
@@ -90,7 +107,11 @@ const getEnterpriseList = async() => {
     loginLoading.value = true
     enterpriseList.value = []
     const data = await getUserBindEnterpriseList() // 申请通过才有数据,否则空数组
-    if (!data?.length) return Snackbar.warning('未查询到该用户下存在企业')
+    if (!data?.length) {
+      // Snackbar.warning('未查询到该用户下存在企业')
+      getApplyInfo()
+      return
+    }
     if (data.length > 1) {
       showCompanySelect.value = true
       enterpriseList.value = data
@@ -105,6 +126,15 @@ const getEnterpriseList = async() => {
   }
 }
 
+// 查看用户是否有在申请中的数据
+const getApplyInfo = async () => {
+  const data = await getUserRegisterEnterpriseApply()
+  const bool = data && Object.keys(data).length // 已经有数据说明已经申请过了
+  const path = bool ? '/recruit/enterprise/register/inReview' : '/recruit/enterprise/register'
+  router.push({ path })
+  if (!bool) Snackbar.warning('未查询到该用户下存在企业,请优先提交企业申请')
+}
+
 // 执行加入操作
 const join = async (enterpriseId) => {
   if (!enterpriseId) return Snackbar.warning('请选择要加入的企业')
@@ -126,6 +156,11 @@ const join = async (enterpriseId) => {
   }
 }
 
+const quickRegister = ref(false)
+const handleRegister = () => {
+  quickRegister.value = true
+}
+
 const logoutFun = async () => {
   if (!getToken()) {
     localStorage.clear()

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

@@ -65,7 +65,7 @@
 
 <script setup>
 defineOptions({name: 'enterprise-talentPool-details-baseInfo'})
-import { ref, defineProps } from 'vue'
+import { ref } from 'vue'
 import { timesTampChange } from '@/utils/date'
 import { dealDictObjData } from '@/utils/position'
 

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

@@ -21,7 +21,7 @@
 </template>
 
 <script setup>
-import { ref, defineProps } from 'vue'
+import { ref } from 'vue'
 import { dealJobData } from './dict'
 defineOptions({name: 'enterprise-talentPool-details-jobIntention'})
 

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

@@ -22,7 +22,7 @@
 <script setup>
 defineOptions({name: 'enterprise-talentPool-details-projectExperience'})
 import { timesTampChange } from '@/utils/date'
-import { ref, defineProps } from 'vue'
+import { ref } from 'vue'
 
 const props = defineProps({
   data: Array

+ 17 - 18
src/views/recruit/enterprise/talentPool/components/details/vocationalSkills.vue

@@ -5,7 +5,7 @@
       v-for="(k, i) in dataList" 
       :key="i" 
     >
-      <span >{{ getText(k.skillId, skills) }}</span>
+      <span >{{ getText(k.skillId, skillList, 'nameCn', 'id') }}</span>
       <span class="septal-line"></span>
       <span style="color: var(--color-999);">{{ getText(k.level, skillLevelArr) }}</span>
     </div>
@@ -15,31 +15,30 @@
 <script setup>
 import { getText } from '@/utils/getText'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { getSkillList } from '@/api/recruit/personal/resume'
 import { ref } from 'vue'
 defineOptions({name: 'enterprise-talentPool-details-vocationalSkills'})
+const props = defineProps({
+  data: Array
+})
+
+const dataList = ref([])
+if (props.data?.length) dataList.value = props.data
 
-const skills = [{ label: '英语四级', value: '0' }, { label: '英语六级', value: '1' }, { label: 'office办公软件', value: '2' }]
-const dataList = ref([
-  {
-    id: "1795704760633024513", 
-    skillId: "0", 
-    level: "2", 
-    createTime: 1716964352000, 
-    updateTime: 1716964352000
-  }, 
-  {
-    id: "1795741375308914690", 
-    skillId: "2", 
-    level: "3", 
-    createTime: 1716973082000, 
-    updateTime: 1716973082000
-  }
-])
 const skillLevelArr = ref([])
 getDict('menduner_skill_level').then(({ data }) => { // 字典
   data = data?.length && data || []
   skillLevelArr.value = data
 })
+
+const skillList = ref([])
+// 获取 职业技能列表(一维数组回显用)
+const getSkillListFunc = async () => {
+  const data = await getSkillList()
+  skillList.value = data || []
+}
+getSkillListFunc()
+
 </script>
 <style lang="scss" scoped>
 .dataList-item {

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

@@ -28,7 +28,7 @@
 <script setup>
 defineOptions({name: 'enterprise-talentPool-details-workExperience'})
 import { timesTampChange } from '@/utils/date'
-import { ref, defineProps } from 'vue'
+import { ref } from 'vue'
 
 const props = defineProps({
   data: Array

+ 4 - 3
src/views/recruit/personal/PersonalCenter/components/interview/index.vue

@@ -2,9 +2,9 @@
   <div>
     <v-divider></v-divider>
       <v-tabs v-model="tabVal" align-tabs="start" color="primary" bg-color="#fff">
-        <v-tab :value="0">待面试</v-tab>
-        <v-tab :value="1">已完成</v-tab>
-        <v-tab :value="2">未面试</v-tab>
+        <v-tab :value="0">待接受</v-tab>
+        <v-tab :value="1">待面试</v-tab>
+        <v-tab :value="2">已完成</v-tab>
         <v-tab :value="3">已取消</v-tab>
       </v-tabs>
       <Empty class="mt-3"></Empty>
@@ -15,6 +15,7 @@
 // 面试
 defineOptions({ name: 'interview-index'})
 import { ref } from 'vue'
+// import { getUserInterviewInvitePage } from '@/api/recruit/personal/personalCenter'
 
 const tabVal = ref(0)
 </script>

+ 32 - 0
src/views/recruit/personal/PersonalCenter/components/interviewSchedule.vue

@@ -0,0 +1,32 @@
+<!-- 面试日程 -->
+<template>
+  <div style="height: 100%; overflow: hidden;">
+    <div class="white-bgc pa-3 pt-5 mb-3" style="font-size: 16px; display: flex; justify-content: space-between;">
+      <div>面试日程</div>
+      <div class="defaultLink" @click="null">查看全部</div>
+    </div>
+    <!-- 滚动区域 -->
+     <div class="mr-1" style="height: calc(100% - 100px); background-color: var(--default-bgc); overflow-y: auto;">
+      
+     </div>
+  </div>
+</template>
+
+<script setup>
+defineOptions({name: 'PersonalCenter-interviewSchedule'})
+</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>

+ 1 - 1
src/views/recruit/personal/PersonalCenter/dynamic/left.vue

@@ -83,7 +83,7 @@ const list = [
   { title: t('position.interested'), path: interested },
   { title: t('position.haveSeenMe'), path: seenMe }
 ]
-const tab = ref(1)
+const tab = ref(2)
 const selectVal = ref('0')
 const items = ref([])
 const userStore = useUserStore()

+ 20 - 3
src/views/recruit/personal/PersonalCenter/dynamic/right.vue

@@ -19,7 +19,7 @@
     </div>
 
     <div class="resume d-flex">
-      <div v-for="val in resumeList" :key="val.title" class="topping white-bgc radius">
+      <div v-for="val in resumeList" :key="val.title" class="topping white-bgc radius" @click="resumeClick(val)">
         <v-icon color="primary">{{ val.icon }}</v-icon>
         <div class="ml-1">
           <div class="title-text">{{ val.title }}</div>
@@ -53,6 +53,15 @@
       </div>
       <div v-else class="more-text d-flex justify-center">暂无简历,请先上传</div>
     </div>
+    <v-navigation-drawer
+      v-model="showInterviewSchedule"
+      style="height: 100vh; overflow: hidden;"
+      temporary
+      location="right"
+      width="700"
+    >
+      <interviewSchedule></interviewSchedule>
+    </v-navigation-drawer>
   </div>
 </template>
 
@@ -67,6 +76,7 @@ import { useI18n } from '@/hooks/web/useI18n'
 import { useUserStore } from '@/store/user'
 import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
+import interviewSchedule from './../components/interviewSchedule.vue'
 
 const { t } = useI18n()
 const router = useRouter()
@@ -82,9 +92,16 @@ userStore.$subscribe((mutation, state) => {
 })
 
 const resumeList = [
-  { icon: 'mdi-upload', title: t('resume.topResume'), desc: t('resume.increaseMoreExposure') },
-  { icon: 'mdi-refresh', title: t('resume.refreshResume'), desc: t('resume.enhanceResumeActivity') }
+  // { icon: 'mdi-upload', title: t('resume.topResume'), desc: t('resume.increaseMoreExposure') },
+  { name: 'refresh', icon: 'mdi-refresh', title: t('resume.refreshResume'), desc: t('resume.enhanceResumeActivity') },
+  { name: 'interview', icon: 'mdi-account-multiple-check-outline', title: t('resume.interviewSchedule'), desc: '有2个待面试' },
 ]
+const showInterviewSchedule = ref(false)
+const resumeClick = (val) => {
+  if (val.name === 'interview') {
+    showInterviewSchedule.value = true
+  }
+}
 
 // 获取附件
 const attachmentList = ref([])

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

@@ -18,7 +18,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 
 defineOptions({name: 'conditionFilter-JobType'})
 const emits = defineEmits(['inputChange'])

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

@@ -19,7 +19,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 
 defineOptions({name: 'conditionFilter-area-type'})
 const emits = defineEmits(['inputChange'])

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

@@ -18,7 +18,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 defineOptions({name: 'conditionFilter-educationType'})
 const emits = defineEmits(['inputChange'])
 const query = inject('routeQuery')

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

@@ -18,7 +18,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 
 defineOptions({name: 'conditionFilter-expType'})
 const emits = defineEmits(['inputChange'])

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

@@ -18,7 +18,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 defineOptions({name: 'conditionFilter-financingStatus'})
 const emits = defineEmits(['inputChange'])
 const query = inject('routeQuery')

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

@@ -18,7 +18,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 defineOptions({name: 'conditionFilter-payScope'})
 const emits = defineEmits(['inputChange'])
 const query = inject('routeQuery')

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

@@ -19,7 +19,7 @@
 <script setup>
 import commonStyle from './commonStyle.vue'
 import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, defineEmits, inject } from 'vue';
+import { ref, inject } from 'vue';
 defineOptions({name: 'conditionFilter-scale'})
 const emits = defineEmits(['inputChange'])
 const query = inject('routeQuery')

+ 7 - 3
src/views/recruit/personal/position/components/details.vue

@@ -22,8 +22,11 @@
       </div>
       <div class="d-flex justify-space-between mb-5">
         <div>
-          <v-chip v-if="info.hire && info.hirePrice && info.hirePrice > 0" label color="primary">赏金:{{ commissionCalculation(info.hirePrice, 1) }}元</v-chip>
-          <v-chip v-if="info.hire && info.hirePoint && info.hirePoint > 0" label color="primary">积分:{{ commissionCalculation(info.hirePoint, 1) }}点</v-chip>
+          <div>
+            <v-chip v-if="info.hire && info.hirePrice && info.hirePrice > 0" label color="primary">赏金:{{ commissionCalculation(info.hirePrice, 1) }}元</v-chip>
+            <v-chip v-if="info.hire && info.hirePoint && info.hirePoint > 0" label color="primary" class="ml-1">积分:{{ commissionCalculation(info.hirePoint, 1) }}点</v-chip>
+          </div>
+          <div v-if="info?.hire" class="font-size-14 mt-3 color-error">推荐好友入职成功即可获得赏金</div>
         </div>
         <div class="banner-tools-btns">
           <v-btn
@@ -32,10 +35,11 @@
             color="error"
             prepend-icon="mdi-share-outline"
             style="height: 36px;"
-            v-if="info?.hire && info?.hirePoint && info?.hirePoint > 0"
+            v-if="info?.hire"
             @click="handleShare"
           >我要赏金</v-btn>
           <v-btn
+            v-else
             class="radius mr-2 button-item"
             variant="outlined"
             color="error"

+ 1 - 1
src/views/recruit/personal/position/components/jobDetails/promptToUpload.vue

@@ -15,7 +15,7 @@
 </template>
 
 <script setup>
-import { defineEmits, watch, computed } from 'vue'
+import { watch, computed } from 'vue'
 defineOptions({name: 'position-details-promptToUpload'})
 
 const props = defineProps({ modelValue: [Boolean, Number] })

+ 1 - 1
src/views/recruit/personal/position/components/jobDetails/selectResumeDialog.vue

@@ -17,7 +17,7 @@
 
 <script setup>
 import Dialog from '@/components/CtDialog'
-import { defineEmits, watch, computed, ref } from 'vue'
+import { watch, computed, ref } from 'vue'
 defineOptions({name: 'position-details-selectResumeDialog'})
 
 const props = defineProps({

+ 26 - 25
src/views/recruit/personal/remuse/components/vocationalSkills.vue

@@ -12,17 +12,17 @@
         <v-btn color="primary" class="half-button" @click="handleSave">{{ $t('common.save') }}</v-btn>
       </div>
     </div>
-    <!-- 展示 -->
     <div v-else-if="!dataList?.length" class="resumeNoDataText">{{ $t('resume.dataDefaultPrompt') }}{{ $t('resume.vocationalSkills') }}...</div>
+    <!-- 展示 -->
     <div v-else>
-      <div 
+      <div
         :class="['dataList-item']" 
         v-for="(k, i) in dataList" 
         :key="i" 
         @mouseenter="k.active = true" 
         @mouseleave="k.active = false"
       >
-        <span >{{ getText(k.skillId, skills) }}</span>
+        <span>{{ getText(k.skillId, skillList, 'nameCn', 'id') }}</span>
         <span class="septal-line"></span>
         <span style="color: var(--color-999);">{{ getText(k.level, skillLevelArr) }}</span>
         <span class="float-right" v-if="k.active">
@@ -36,7 +36,7 @@
 
 <script setup name="vocationalSkills">
 import { ref } from 'vue'
-import { saveResumePersonSkill, getResumePersonSkill, deleteResumePersonSkill } from '@/api/recruit/personal/resume'
+import { saveResumePersonSkill, getResumePersonSkill, deleteResumePersonSkill, getSkillList, getSkillTree,  } from '@/api/recruit/personal/resume'
 import CtForm from '@/components/CtForm'
 import Snackbar from '@/plugins/snackbar'
 import Confirm from '@/plugins/confirm'
@@ -47,39 +47,23 @@ const isEdit = ref(false)
 const formPageRef = ref()
 const type = ref('')
 const editId = ref(null)
-const skills = [{ label: '英语四级', value: '0' }, { label: '英语六级', value: '1' }, { label: 'office办公软件', value: '2' }]
+// const skills = [{ label: '英语四级', value: '0' }, { label: '英语六级', value: '1' }, { label: 'office办公软件', value: '2' }]
 
-// const skills = [
-//   { label: '一级-1', value: '0' },
-//   { label: '财务-1', value: '1',
-//     children: [
-//       { 
-//         label: '会计-2', value: '22222',
-//         children: [
-//           { label: '注册会计师一级-3', value: '33333', },
-//           { label: '注册会计师二级-3', value: '33334', }
-//         ]
-//       },
-//       { label: '出纳-2', value: '498640' },
-//     ]
-//   },
-//   { label: '其他一级-1', value: '2' }
-// ]
 const formItems = ref({
   options: [
     {
-      type: 'autocomplete', // nestedListGroup autocomplete
+      type: 'nestedListGroup', // nestedListGroup autocomplete
       key: 'skillId',
       value: null,
       default: null,
       label: '技能名称 *',
       outlined: true,
-      itemText: 'label',
-      itemValue: 'value',
+      itemText: 'nameCn',
+      itemValue: 'id',
       flexStyle: 'mr-3',
       col: 8,
       rules: [v => !!v || '请选择技能名称'],
-      items: skills,
+      items: [],
     },
     {
       type: 'autocomplete',
@@ -97,6 +81,22 @@ const formItems = ref({
   ]
 })
 
+const skillList = ref([])
+// 获取 职业技能列表(一维数组回显用)
+const getSkillListFunc = async () => {
+  const data = await getSkillList()
+  skillList.value = data || []
+}
+getSkillListFunc()
+
+// 获取 职业技能选项
+const getSkillTreeFunc = async () => {
+  const data = await getSkillTree()
+  const obj = formItems.value.options.find(e => e.key === 'skillId')
+  if (obj) obj.items = data || []
+}
+getSkillTreeFunc()
+
 // 获取 职业技能
 const dataList = ref([])
 const getData = async () => {
@@ -141,6 +141,7 @@ const handleDelete = ({ id }) => {
   })
 }
 
+
 const skillLevelArr = ref([])
 getDict('menduner_skill_level').then(({ data }) => { // 字典
   data = data?.length && data || []

+ 1 - 1
src/views/recruit/personal/shareJob/components/login.vue

@@ -11,7 +11,7 @@
     <div class="my-5">
       <phoneFrom ref="phoneRef" @handleEnter="handleLogin"></phoneFrom>
       <v-btn :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click="handleLogin">
-        {{ $t('login.register') }}
+        {{ $t('login.loginOrRegister') }}
       </v-btn>
     </div>
   </CtDialog>