Sfoglia il codice sorgente

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

zhengnaiwen_citu 7 mesi fa
parent
commit
8e06316788
63 ha cambiato i file con 747 aggiunte e 1254 eliminazioni
  1. 15 0
      src/api/common/index.js
  2. 1 0
      src/components/CtForm/index.vue
  3. 1 0
      src/components/DatePicker/index.vue
  4. 50 19
      src/components/Enterprise/components/positions.vue
  5. 1 1
      src/components/Enterprise/details.vue
  6. 1 1
      src/components/FormUI/TextInput/index.vue
  7. 14 12
      src/components/Position/item.vue
  8. 4 3
      src/components/Position/longStrip.vue
  9. 3 3
      src/components/industryTypeCard/index.vue
  10. 10 8
      src/config/axios/service.js
  11. 2 8
      src/layout/company/navBar.vue
  12. 5 1
      src/layout/personal/navBar.vue
  13. 1 1
      src/locales/zh-CN.js
  14. 23 3
      src/store/user.js
  15. 1 1
      src/utils/index.js
  16. 1 1
      src/utils/validate.js
  17. 2 3
      src/views/integral/pointsManagement/components/integralShow.vue
  18. 12 4
      src/views/login/components/editPassword.vue
  19. 33 14
      src/views/login/index.vue
  20. 1 1
      src/views/recruit/components/message/components/chatting.vue
  21. 13 8
      src/views/recruit/entRegister/inReview.vue
  22. 33 12
      src/views/recruit/entRegister/register.vue
  23. 1 0
      src/views/recruit/enterprise/entInfoSetting/index.vue
  24. 2 2
      src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/basicInfo.vue
  25. 0 71
      src/views/recruit/enterprise/enterpriseCenter/components/introduction.vue
  26. 0 273
      src/views/recruit/enterprise/enterpriseCenter/components/positions.vue
  27. 0 40
      src/views/recruit/enterprise/enterpriseCenter/components/video.vue
  28. 0 64
      src/views/recruit/enterprise/enterpriseCenter/index.vue
  29. 8 0
      src/views/recruit/enterprise/hirePosition/components/jobRequirements.vue
  30. 7 0
      src/views/recruit/enterprise/interviewManagement/components/invite.vue
  31. 7 0
      src/views/recruit/enterprise/personnelManagement/components/invite.vue
  32. 9 1
      src/views/recruit/enterprise/positionManagement/components/jobRequirements.vue
  33. 7 0
      src/views/recruit/enterprise/resume/components/invite.vue
  34. 1 1
      src/views/recruit/enterprise/resume/components/table.vue
  35. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/companyCollection.vue
  36. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/delivery.vue
  37. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/index.vue
  38. 7 5
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/item.vue
  39. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/positionCollection.vue
  40. 1 1
      src/views/recruit/personal/PersonalCenter/jobFeedback/components/seenMe.vue
  41. 23 32
      src/views/recruit/personal/PersonalCenter/resume/online/components/basicInfo.vue
  42. 0 2
      src/views/recruit/personal/PersonalCenter/resume/online/components/jobIntention.vue
  43. 7 1
      src/views/recruit/personal/PersonalCenter/resume/online/components/projectExperience.vue
  44. 4 2
      src/views/recruit/personal/PersonalCenter/resume/online/index.vue
  45. 6 0
      src/views/recruit/personal/PersonalCenter/wallet/myBalance/index.vue
  46. 5 7
      src/views/recruit/personal/home/components/advertisement/index.vue
  47. 11 10
      src/views/recruit/personal/home/index.vue
  48. 111 37
      src/views/recruit/personal/position/components/conditionFilter.vue
  49. 0 65
      src/views/recruit/personal/position/components/conditionFilter/JobType.vue
  50. 0 62
      src/views/recruit/personal/position/components/conditionFilter/areaType.vue
  51. 118 0
      src/views/recruit/personal/position/components/conditionFilter/commonPath.vue
  52. 0 42
      src/views/recruit/personal/position/components/conditionFilter/companyIndustry.vue
  53. 0 73
      src/views/recruit/personal/position/components/conditionFilter/educationType.vue
  54. 0 80
      src/views/recruit/personal/position/components/conditionFilter/expType.vue
  55. 0 63
      src/views/recruit/personal/position/components/conditionFilter/financingStatus.vue
  56. 0 59
      src/views/recruit/personal/position/components/conditionFilter/payScope.vue
  57. 0 42
      src/views/recruit/personal/position/components/conditionFilter/positionType.vue
  58. 0 64
      src/views/recruit/personal/position/components/conditionFilter/scale.vue
  59. 123 0
      src/views/recruit/personal/position/components/dict.js
  60. 30 37
      src/views/recruit/personal/position/index.vue
  61. 7 3
      src/views/recruit/personal/shareJob/sendResume/simple.vue
  62. 6 1
      src/views/register/company.vue
  63. 15 6
      src/views/register/person.vue

+ 15 - 0
src/api/common/index.js

@@ -16,6 +16,14 @@ export const sendSmsCode = async (data) => {
   })
 }
 
+// 个人注册并登录
+export const userRegister = async (data) => {
+  return await request.post({
+    url: '/app-api/menduner/system/auth/register',
+    data
+  })
+}
+
 // 验证码登录
 export const smsLogin = async (data) => {
   return await request.post({
@@ -58,6 +66,13 @@ export const passwordLogin = async (data) => {
   })
 }
 
+// 根据邮箱获取企业注册申请
+export const getEnterpriseRegisterApply = async (email) => {
+  return await request.get({
+    url: '/app-api/menduner/system/enterprise-register/by/email?email=' + email
+  })
+}
+
 // 退出登录
 export const logout = async () => {
   return await request.post({

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

@@ -16,6 +16,7 @@
                 :item="item"
                 @blur="item.blur"
                 @change="handleChange(item)"
+                @appendInnerClick="item.appendInnerClick"
               ></textUI>
               <autocompleteUI
                 v-if="item.type === 'autocomplete'"

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

@@ -11,6 +11,7 @@
       :placeholder="options.placeholder ?? '请选择'"
       auto-apply
       text-input
+      :disabled-dates="options.disabledDates || false"
       :show-now-button="options.showToday"
       now-button-label="今天"
       :enable-time-picker="options.enableTimePicker ?? false"

+ 50 - 19
src/components/Enterprise/components/positions.vue

@@ -12,10 +12,7 @@
       </div>
     </div>
     <div class="d-flex mt-3">
-      <areaType v-if="areaList.length" :list="areaList" @inputChange="val => handleSearch('areaIds', val)"></areaType>
-      <expType :isSingle="true" @inputChange="val => handleSearch('expType', val)"></expType>
-      <educationType :isSingle="true" @inputChange="val => handleSearch('eduType', val)"></educationType>
-      <payScope @input-change="val => handleSearch('payType', val)"></payScope>
+      <conditionFilter v-if="show" ref="conditionFilterRef" :showFilterList="showFilterList" @reset="handleReset" @change="handleQueryChange"></conditionFilter>
       <div style="width: 300px;">
         <v-text-field
           v-model="query.content"
@@ -79,7 +76,7 @@
 
 <script setup>
 defineOptions({ name: 'recruitment-positions'})
-import { reactive, ref, provide } from 'vue'
+import { reactive, ref } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { timesTampChange } from '@/utils/date'
 import { getDict } from '@/hooks/web/useDictionaries'
@@ -88,10 +85,7 @@ import { prologue, defaultText } from '@/hooks/web/useIM'
 import { getUserAvatar } from '@/utils/avatar'
 import { getJobAdvertisedPositionCount, getJobAreaByEnterpriseId, getJobAdvertisedSearch } from '@/api/position'
 import MPagination from '@/components/CtPagination'
-import expType from '@/views/recruit/personal/position/components/conditionFilter/expType.vue'
-import educationType from '@/views/recruit/personal/position/components/conditionFilter/educationType.vue'
-import payScope from '@/views/recruit/personal/position/components/conditionFilter/payScope.vue'
-import areaType from '@/views/recruit/personal/position/components/conditionFilter/areaType.vue'
+import conditionFilter from '@/views/recruit/personal/position/components/conditionFilter'
 
 const props = defineProps({
   info: {
@@ -107,9 +101,9 @@ const pageInfo = ref({
 })
 let query = reactive({})
 const route = useRoute(); const router = useRouter()
-const routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? route.query : null
-if (routeQuery?.content) query.content = routeQuery?.content
-provide('routeQuery', routeQuery)
+let routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? route.query : null
+if (routeQuery?.content) query.content = routeQuery?.content || ''
+// provide('routeQuery', routeQuery)
 if (routeQuery) query = routeQuery
 
 // 职位详情
@@ -125,12 +119,32 @@ const getDictData = async () => {
 }
 getDictData()
 
+const show = ref(false)
+const showFilterList = ref([
+  { key: 'expType', isSingle: false },
+  { key: 'eduType', isSingle: true },
+  { key: 'payScope', isSingle: true },
+])
+const getProvideData = (list) => {
+  if (!list?.length) return
+  getDict('menduner_area_type', {}, 'areaList').then(({ data }) => {
+    data = data?.length && data || []
+    const arr = list.map(e => {
+      const obj = data.find(k => k.id === e.key)
+      if (!obj) return
+      return { label: obj.name, value: obj.id }
+    }).filter(Boolean)
+    if (arr?.length) showFilterList.value.unshift({ key: 'areaIds', isSingle: true, provideData: arr})
+    show.value = true
+  })
+}
+
 // 职位类别&工作地点
 const positionCategory = ref([])
-const areaList = ref([])
 const getData = async () => {
   const data = await getJobAdvertisedPositionCount({ enterpriseId: props.info.enterprise.id })
-  areaList.value = await getJobAreaByEnterpriseId({ enterpriseId: props.info.enterprise.id })
+  const areaList = await getJobAreaByEnterpriseId({ enterpriseId: props.info.enterprise.id })
+  getProvideData(areaList)
   const list = data.map(val => {
     const value = industryList.value.find(e => Number(e.id) === Number(val.key))
     if (!value) return
@@ -148,8 +162,6 @@ const getPoAr = async () => {
 }
 getPoAr()
 
-
-
 // 职位类别选中
 const handleClickCategory = (k) => {
   positionCategory.value.map(e => e.active = false)
@@ -169,9 +181,12 @@ const dealRouteQuery = () => {
   if (str) router.replace(`${route.path}?${str}`)
 }
 
-const handleSearch = (key, { values }) => {
-  if (values === -1 || !values || values[0] === -1 || !values.length) delete query[key]
-  else query[key] = values
+const handleSearch = (key, { values = [] }) => {
+  if (key) {
+    if (values === -1 || !values || values[0] === -1 || !values.length) delete query[key]
+    else if (key === 'payScope') query[key] = values?.length ? values[values.length-1] : '' // 单选且传递字符串
+    else query[key] = values
+  }
   dealRouteQuery()
   getPositionList(true)
 }
@@ -202,6 +217,22 @@ const handleChangePage = (index) => {
   getPositionList()
 }
 
+// 参数改变
+const handleQueryChange = (key, val) => { // val为字符串,数组的话用_下划线分隔
+  pageInfo.value.pageNo = 1
+  const values = val ? val.split('_') : []
+  handleSearch(key, { values })
+}
+
+// 清空筛选条件
+const handleReset = async () => {
+  pageInfo.value.pageNo = 1
+  showFilterList.value.forEach(e => {
+    delete query[e.key]
+  })
+  handleSearch(null, {})
+}
+
 // 城市、学历、工作经验
 const desc = [
   { mdi: 'mdi-map-marker-outline', value: 'areaName' },

+ 1 - 1
src/components/Enterprise/details.vue

@@ -60,7 +60,7 @@
                 <div>{{ val.label }}</div>
                 <div class="business-value ellipsis">
                   {{ info?.business ? info.business[val.value] : '暂无' }}
-                  <span v-if="info?.business && val.value === 'registeredCapital' && info?.business[val.value]">万元</span>
+                  <span v-if="info?.business && val.value === 'registeredCapital' && info?.business[val.value] && info?.business[val.value].indexOf('万元') === -1">万元</span>
                 </div>
                 <div :class="['my-3']"></div>
               </div>

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

@@ -87,7 +87,7 @@ const appendClick = () => {
 }
 const appendInnerClick = () => {
   if (item.appendInnerClick) item.appendInnerClick(value.value)
-  emit('appendInnerClick', value.value)
+  else emit('appendInnerClick', value.value)
 }
 
 const handleClear = () => {

+ 14 - 12
src/components/Position/item.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="d-flex">
     <div class="position-box">
-      <div class="sub-li" v-for="(item, index) in list" :key="index" :style="{'height': tab === 3 && item.hire ? '180px' : '140px'}">
+      <div class="sub-li" v-for="(item, index) in list" :key="index" :style="{'height': tab === 3 && item.hire ? '180px' : '149px'}">
         <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">
@@ -26,6 +26,7 @@
             <v-chip v-if="item.hirePrice" size="small" label color="primary">赏金:{{ commissionCalculation(item.hirePrice, 1) }}元</v-chip>
             <v-chip v-if="item.hirePoint" size="small" label class="ml-1" color="primary">积分:{{ commissionCalculation(item.hirePoint, 1) }}点</v-chip>
           </div>
+          <div v-if="tab === 2" class="font-size-14 mb-3 text-end" style="color: #345768;">发布时间:{{ timesTampChange(item.updateTime, 'Y-M-D h:m') }}</div>
         </div>
         <div class="sub-li-bottom" @click="handleEnterprise(item)">
           <div class="user-info">
@@ -33,13 +34,15 @@
               <v-avatar size="35">
                 <v-img :src="item.logoUrl || 'https://minio.citupro.com/dev/menduner/company-avatar.png'" />
               </v-avatar>
-              <span class="names ml-2 font-size-14 ellipsis" style="max-width: 78%;">{{ item.anotherName }}</span>
+              <span class="names ml-2 font-size-14 ellipsis" style="max-width: 88%;">
+                {{ item.anotherName }}
+                <span class="color-999 font-size-13 ml-3">
+                  <span>{{ item.industryName }}</span>
+                  <span class="septal-line" v-if="item.industryName && item.scaleName"></span>
+                  <span>{{ item.scaleName }}</span>
+                </span>
+              </span>
             </div>
-            <p class="float-right color-999 font-size-13">
-              <span>{{ item.industryName }}</span>
-              <span class="septal-line" v-if="item.industryName && item.scaleName"></span>
-              <span>{{ item.scaleName }}</span>
-            </p>
           </div>
         </div>
       </div>
@@ -51,6 +54,7 @@
 defineOptions({ name: 'position-card-item' })
 import { ref, watch } from 'vue'
 import { commissionCalculation } from '@/utils/position'
+import { timesTampChange } from '@/utils/date'
 
 const props = defineProps({
   items: {
@@ -84,8 +88,6 @@ const handlePosition = (item) => {
 const handleEnterprise = (item) => {
   emits('enterprise', item)
 }
-
-const height = ((210 * 2) + 12) + 'px'
 </script>
 
 <style lang="scss" scoped>
@@ -182,10 +184,10 @@ const height = ((210 * 2) + 12) + 'px'
   border: none;
 }
 .user-info {
-  display: flex;
+  // display: flex;
   padding: 12px 20px;
-  align-items: center;
-  justify-content: space-between;
+  // align-items: center;
+  // justify-content: space-between;
 }
 .names {
   font-weight: 500;

+ 4 - 3
src/components/Position/longStrip.vue

@@ -1,7 +1,6 @@
 <template>
   <div>
     <div class="position-item mb-3 job-closed elevation-2" style="position: relative;" 
-      :class="{'close-position': val.job.status === '1'}"  
       v-for="(val, i) in props.items" :key="i" @mouseenter="val.active = true" @mouseleave="val.active = false"
     >
       <div class="info-header">
@@ -9,6 +8,7 @@
           <v-btn v-if="props.showCancelBtn" class="half-button ml-3" color="primary" size="small" @click="handleCancel(val)">取消收藏</v-btn>
           <v-btn class="half-button ml-3" color="primary" size="small" @click="toDetails(val)">立即沟通</v-btn>
         </div>
+        <div v-if="val.job.status === '1'" class="font-size-14 header-btn color-error">职位已关闭</div>
         <div class="img-box">
           <v-avatar :image="getUserAvatar(val.contact.avatar, val.contact.sex)" size="x-small"></v-avatar>
           <span class="name">
@@ -19,8 +19,8 @@
       </div>
       <div class="info-content" >
         <div class="job-info">
-          <div class="job-name cursor-pointer">
-            <span class="mr-3 info-name" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
+          <div class="job-name" :class="{'cursor-pointer': val.job.status === '0'}">
+            <span class="mr-3" :class="{'info-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
             <span v-if="val?.job?.areaName">[{{ val.job.areaName }}]</span>
           </div>
           <div class="job-other">
@@ -84,6 +84,7 @@ const handleCancel = async (item) => {
 
 // 职位详情
 const handleToPositionDetails = (item) => {
+  if (item.job.status === '1') return
   router.push(`/recruit/personal/position/details/${item.job.id}`)
 }
 

+ 3 - 3
src/components/industryTypeCard/index.vue

@@ -58,9 +58,9 @@ const props = defineProps({
   }
 })
 
-let items = ref()
-let idChecked = ref([])
-let currentSelect = ref([])
+const items = ref()
+const idChecked = ref([])
+const currentSelect = ref([])
 // 回显
 if (props.currentData.length) currentSelect.value = props.currentData
 if (props.select.length) idChecked.value = props.select.map(e => e + '') // 数据中的id是字符串

+ 10 - 8
src/config/axios/service.js

@@ -7,7 +7,7 @@ import { useUserStore } from '@/store/user'
 import { getSuffixAfterPrefix, showNextAction } from '@/utils/prefixUrl'
 import { getCurrentLocaleLang } from '@/utils/lang'
 import { enterpriseRefreshToken, userRefreshToken } from '@/api/common'
-import { getToken, getRefreshToken, removeToken, setToken, setRefreshToken, getIsEnterprise } from '@/utils/auth'
+import { getToken, getRefreshToken, setToken, setRefreshToken, getIsEnterprise } from '@/utils/auth'
 import { rewardEventTrackClick } from '@/api/integral'
 import errorCode from './errorCode'
 
@@ -205,11 +205,11 @@ service.interceptors.response.use(
       Snackbar.error(t('sys.api.errMsg901'))
       return Promise.reject(new Error(msg))
     } else if (code !== 200) {
-      if (msg === '无效的刷新令牌') {
-        // hard coding:忽略这个提示,直接登出
-        console.log(msg)
-      }
-      else {
+      if (code === 1100017019 || code === 1100016002 || code === 1100021016) {
+        // 1100017019邮箱未注册、1100016002手机号未注册过、1100021016注册企业申请中
+        // 未注册过的手机号将code码返回
+        return Promise.reject(data)
+      } else {
         Snackbar.error(msg)
       }
       return Promise.reject(msg)
@@ -244,6 +244,7 @@ service.interceptors.response.use(
 
 const handleAuthorized = () => {
   const { t } = useI18n()
+  const user = useUserStore()
   if (!isReLogin.show) {
     // 如果已经到重新登录页面则不进行弹窗提示
     if (window.location.href.includes('login?redirect=')) {
@@ -255,10 +256,11 @@ const handleAuthorized = () => {
     }).then(() => {
       // resetRouter() // 重置静态路由表
       // deleteUserCache() // 删除用户缓存
-      removeToken()
+      user.handleClearStorage()
       isReLogin.show = false
       // 干掉token后再走一次路由让它过router.beforeEach的校验
-      location.reload()
+      // location.reload()
+      window.location.href = '/login'
     }).catch(() => {
       isReLogin.show = false
     })

+ 2 - 8
src/layout/company/navBar.vue

@@ -129,12 +129,6 @@ const handleLogout = async () => {
 const enterpriseList = ref([])
 
 const menuList = ref([
-  // { title: t('enterprise.account.myAccount'), icon: 'mdi-account', change: () => router.push({ path: '/recruit/enterprise/memberCenter/myAccount' }) },
-  // { title: t('vipPackage.purchasePackage'), icon: 'mdi-gift-outline', change: () => window.open('/recruit/enterprise/purchasePackage') },
-  // { title: t('enterprise.personalInformationSettings'), icon: 'mdi-account-cog', change: () => router.push({ path: '/recruit/enterprise/staffInfoSetting' }) },
-  // { title: t('setting.switchToOtherCompany'), icon: 'mdi-home-switch', hidden: enterpriseList.value?.length < 2, change: () => handleSwitchToAnotherEnterprise },
-  // { title: t('enterprise.registeringNewEnterprise'), icon: 'mdi-home-plus-outline', change: () => handleRegisteringNewEnterprise },
-  // { title: t('setting.switchToJobSeeker'), icon: 'mdi-swap-horizontal', change: handleLogout },
   { title: t('setting.logOut'), icon: 'mdi-logout', change: handleLogout }
 ])
 const items = computed(() => {
@@ -146,8 +140,8 @@ let baseInfo = ref(JSON.parse(localStorage.getItem('entBaseInfo')) || {})
 let enterpriseUserAccount = ref(JSON.parse(localStorage.getItem('enterpriseUserAccount')) || {}) // 账户信息
 
 userStore.$subscribe((mutation, state) => {
-  baseInfo.value = state.baseInfo
-  enterpriseUserAccount.value = state.enterpriseUserAccount
+  if (Object.keys(state.baseInfo).length) baseInfo.value = state.entBaseInfo
+  if (Object.keys(state.enterpriseUserAccount).length) enterpriseUserAccount.value = state.enterpriseUserAccount
 })
 
 // 语言切换

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

@@ -107,7 +107,10 @@
       <v-radio-group v-model="radios" :hide-details="true">
         <v-radio v-for="item in enterpriseList" :key="item.enterpriseId" color="primary" :label="item.enterpriseName" :value="item.enterpriseId"></v-radio>
       </v-radio-group>
-      <v-btn :loading="loading1" class="ml-6 mb-3" color="primary" variant="text" @click="newRegistering">{{ btnType ? '注册新企业' : '查看申请进度' }}</v-btn>
+      <!-- <v-btn :loading="loading1" color="primary" variant="text" @click="newRegistering">{{ btnType ? '注册新企业' : '查看申请进度' }}</v-btn> -->
+      <div class="text-end pr-5 pt-5">
+        <span class="color-error cursor-pointer text-decoration-underline" @click="newRegistering">{{ btnType ? '都不是我要的?去注册新企业' : '查看申请进度' }}</span>
+      </div>
     </CtDialog>
   </div>
 </template>
@@ -262,6 +265,7 @@ let userAccount = ref(JSON.parse(localStorage.getItem('userAccount')) || {}) //
 
 userStore.$subscribe((mutation, state) => {
   if (Object.keys(state.baseInfo).length) baseInfo.value = state.baseInfo
+  if (Object.keys(state.userInfo).length) userInfo.value = state.userInfo
   if (Object.keys(state.userAccount).length) userAccount.value = state.userAccount
 })
 

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

@@ -41,7 +41,7 @@ export default {
     activatePosition: '激活职位',
     suspend: '暂停',
     release: '发布',
-    clearFilterCriteria: '清空筛选条件',
+    clearFilterCriteria: '重置筛选条件',
     clearSelectedLocation: '清空已选位置',
     Unrestricted: '不限',
     other: '其他',

+ 23 - 3
src/store/user.js

@@ -10,7 +10,7 @@ import {
   logout 
 } from '@/api/common'
 import { getUserInfo } from '@/api/personal/user'
-import { getEnterpriseUserAccount, getAccountBalance, getUserAccount } from '@/api/common'
+import { getEnterpriseUserAccount, getAccountBalance, getUserAccount, userRegister } from '@/api/common'
 import { getEnterpriseBaseInfo } from '@/api/enterprise'
 import Snackbar from '@/plugins/snackbar'
 import { timesTampChange } from '@/utils/date'
@@ -34,6 +34,21 @@ export const useUserStore = defineStore('user',
       enterpriseUserAccount: {} // 企业账户信息
     }),
     actions: {
+      // 个人用户注册并登录
+      handleUserRegister (data) {
+        return new Promise((resolve, reject) => {
+          userRegister(data).then(async res => {
+            setToken(res.accessToken)
+            setRefreshToken(res.refreshToken)
+            this.accountInfo = res
+            localStorage.setItem('accountInfo', JSON.stringify(res))
+            localStorage.setItem('expiresTime', res.expiresTime) // token过期时间
+            await this.getUserInfos()
+            this.getUserBaseInfos()
+            resolve()
+          }).catch(err => { reject(err) })
+        })
+      },
       // 短信登录
       handleSmsLogin (data) {
         return new Promise((resolve, reject) => {
@@ -49,7 +64,6 @@ export const useUserStore = defineStore('user',
           }).catch(err => { reject(err) })
         })
       },
-
       // 密码登录
       async handlePasswordLogin(data) {
         return new Promise((resolve, reject) => {
@@ -69,7 +83,9 @@ export const useUserStore = defineStore('user',
               this.getUserBaseInfos()
             }
             resolve()
-          }).catch(err => { reject(err) })
+          }).catch(err => {
+            reject(err)
+          })
         })
       },
       // 获取当前登录账户信息
@@ -117,6 +133,10 @@ export const useUserStore = defineStore('user',
         if (type === 1) {
           await logout()
         } else await logoutToken(getToken(1))
+        this.handleClearStorage()
+      },
+      // 清除缓存
+      handleClearStorage () {
         removeToken()
         this.userInfo = {}
         this.baseInfo = {}

+ 1 - 1
src/utils/index.js

@@ -21,7 +21,7 @@ export const checkIsImage = (url) => {
   var link = new URL(url)
   var path = link.pathname
   var extension = path.split('.').pop().toLowerCase()
-  var imageExtensions = ['jpg', 'jpeg', 'gif', 'png']
+  var imageExtensions = ['jpg', 'jpeg', 'gif', 'png', 'jfif']
   var videoExtensions = ['mp4', 'wmv', 'avi', 'mov']
 
   // 图片

+ 1 - 1
src/utils/validate.js

@@ -66,4 +66,4 @@ export const checkEmail = (email) => {
 const USCIReg = /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/;  
 export const checkUSCI = (code) => {  
   return USCIReg.test(code)
-} 
+}

+ 2 - 3
src/views/integral/pointsManagement/components/integralShow.vue

@@ -58,11 +58,10 @@ const list = ref([
 ])
 
 const userStore = useUserStore()
-const key = props.isEnterprise ? 'enterpriseUserAccount' : 'userAccount'
-let accountData = ref(JSON.parse(localStorage.getItem(key)) || {})
+let accountData = ref(JSON.parse(localStorage.getItem('userAccount')) || {})
 
 userStore.$subscribe((mutation, state) => {
-  if (Object.keys(state[key]).length) accountData.value = state[key]
+  if (Object.keys(state.userAccount).length) accountData.value = state.userAccount
 })
 
 // 积分规则

+ 12 - 4
src/views/login/components/editPassword.vue

@@ -23,7 +23,7 @@
         prepend-inner-icon="mdi-lock-outline" 
         :append-inner-icon="show ? 'mdi-eye-outline' : 'mdi-eye-off-outline'"
         :type="show ? 'text' : 'password'"
-        :rules="[v=> !!v || '请再次输入新密码', passwordCheck]"
+        :rules="secondaryConfirmation"
         @click:append-inner="show = !show"
       ></v-text-field>
     </v-form>
@@ -67,14 +67,22 @@ const loading = ref(false)
 const passwordType = ref(false)
 const phoneRef = ref()
 
+const secondaryConfirmation = ref([
+  value => {
+    if (value) return true
+    return '请再次输入密码'
+  },
+  value => {
+    if (value === query.password) return true
+    return '两次输入密码不一致'
+  }
+])
+
 // 密码效验
 const regex = /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,16}$/
 const validPassword = computed(() => {
   return regex.test(query.password) || '请输入8-16位数由数字、大小写字母组成的密码'
 })
-const passwordCheck = computed(() => {
-  return (query.checkPassword === query.password && regex.test(query.checkPassword)) || '两次密码输入不一致'
-})
 
 
 const handleClose = () => {

+ 33 - 14
src/views/login/index.vue

@@ -36,8 +36,8 @@
         </v-btn>
         <div class="login-tips mt-3">
           {{ $t('login.agreeLogin') }}
-          <span class="color" style="cursor: pointer;" @click="handleToUserAgreement"> [{{ $t('login.userAgreement') }}] </span>和
-          <span class="color" style="cursor: pointer;" @click="handlePrivacyPolicy">[{{ $t('login.privacyPolicy') }}]</span>
+          <span class="color" style="cursor: pointer;" @click="router.push('/userAgreement')"> [{{ $t('login.userAgreement') }}] </span>和
+          <span class="color" style="cursor: pointer;" @click="router.push('/privacyPolicy')">[{{ $t('login.privacyPolicy') }}]</span>
         </div>
       </div>
     </div>
@@ -45,14 +45,16 @@
 </template>
 
 <script setup>
+defineOptions({ name: 'login-index' })
 import { ref } from 'vue'
 import passwordFrom from './components/passwordPage.vue'
 import phoneFrom from '@/components/VerificationCode'
 import { useUserStore } from '@/store/user'
 import { useRouter } from 'vue-router'
 import { useI18n } from '@/hooks/web/useI18n'
+import { getEnterpriseRegisterApply } from '@/api/common'
 import Snackbar from '@/plugins/snackbar'
-defineOptions({ name: 'login-index' })
+import Confirm from '@/plugins/confirm'
 
 const { t } = useI18n()
 const router = useRouter()
@@ -64,6 +66,16 @@ const passRef = ref()
 const loginLoading = ref(false)
 const userStore = useUserStore()
 
+const handleCheckEnterprise = async () => {
+  const data = await getEnterpriseRegisterApply(passRef.value.loginData.phone)
+  if (data && Object.keys(data).length) {
+    // 查看申请状态
+    localStorage.setItem('entRegisterData', JSON.stringify(data))
+    localStorage.setItem('loginAccount', data.phone)
+    router.push({ path: '/recruit/entRegister/inReview', query: { type: 'noLoginToRegister', noLogin: true } })
+  }
+}
+
 const handleLogin = async () => {
   const { valid } = tab.value === 1 ? await phoneRef.value.phoneForm.validate() : await passRef.value.passwordForm.validate()
   if (!valid) return
@@ -79,25 +91,32 @@ const handleLogin = async () => {
       const isEnterprise = pattern.test(params.phone)
       params.isEnterprise = isEnterprise
     }
-    // if (params.isEnterprise) router.push({ path: '/enterpriseVerification' }) // 先跳转到会使用企业token的路由
     await userStore[api](params)
     // 跳转
     if (params.isEnterprise) return // 企业邮箱登录
+    else localStorage.setItem('simpleCompleteDialogHaveBeenShow', true) // 个人登录简易基本信息填写弹窗open-status
     Snackbar.success(t('login.loginSuccess'))
     router.push({ path: '/recruitHome' })
-  }
-  finally {
+
+  } catch (err) {
+    if (!err.code) return
+    // 企业注册申请中
+    if (err.code === 1100021016) {
+      handleCheckEnterprise()
+      return
+    }
+    // 登录未注册过的账号跳转注册
+    const text = err.code === 1100016002 ? '您的手机号还未注册过' : '您的邮箱还未注册过'
+    Confirm('系统提示',  `${text},去注册?`, {
+      cancelCallback: true
+    }).then(() => {
+      localStorage.setItem('loginAccount', tab.value === 1 ? phoneRef.value.loginData.phone : passRef.value.loginData.phone)
+      router.push(err.code === 1100016002 ? '/register/person?type=noLoginToRegister' : '/register/company?type=noLoginToRegister')
+    })
+  } finally {
     loginLoading.value = false
   }
 }
-
-// 隐私、用户协议
-const handleToUserAgreement = () => {
-  router.push({ path: '/userAgreement' })
-}
-const handlePrivacyPolicy = () => {
-  router.push({ path: '/privacyPolicy' })
-}
 </script>
 
 <style lang="scss" scoped>

+ 1 - 1
src/views/recruit/components/message/components/chatting.vue

@@ -142,7 +142,7 @@
               </v-chip>
               <v-card v-if="val.payload.content?.type !== 2 || val.from_uid !== IM.uid" width="300" class="pa-3 ma-2" color="teal" variant="tonal" :elevation="3">
                 <v-card-text class="d-flex">
-                  <p v-if="val.payload.content?.type === 1">{{ val.payload.content?.query?.title || t('resume.attachmentResume') }}</p>
+                  <p v-if="val.payload.content?.type === 1" style="width: 100%; text-align: left;">{{ val.payload.content?.query?.title || t('resume.attachmentResume') }}</p>
                   <p v-if="val.payload.content?.type === 2">{{ t('resume.requestResume') }}</p>
                 </v-card-text>
                 <v-card-actions class="justify-center">

+ 13 - 8
src/views/recruit/entRegister/inReview.vue

@@ -2,7 +2,8 @@
 <template>
   <div class="my-5">
     <div :class="isMobile? 'mobileBox' : 'default-width'">
-      <v-btn class="my-2" color="primary" variant="text" size="large" @click="router.push('/recruitHome')">{{ `<< 回到首页` }}</v-btn>
+      <v-btn v-if="query?.noLogin" class="my-2" color="primary" variant="text" size="large" @click="router.push('/login')">{{ `<< 回到登录页` }}</v-btn>
+      <v-btn v-else class="my-2" color="primary" variant="text" size="large" @click="router.push('/recruitHome')">{{ `<< 回到首页` }}</v-btn>
     </div>
     <v-card class="pa-5" :class="isMobile? 'mobileBox' : 'default-width'" :elevation="isMobile? '0' : '3'">
 
@@ -11,7 +12,7 @@
         <!-- 提交企业注册以后跳转显示页面 -->
         <div v-if="!applyInfo || !(Object.keys(applyInfo).length)" class="d-flex flex-column align-center">
           <svg-icon name="submit" size="300"></svg-icon>
-          <div>提交成功,审核时间在1~3个工作日内,申请结果会以短信方式通知到您的手机上,请注意查收</div>
+          <div>提交成功,审核时间在1~3个工作日内,申请结果会以短信方式通知到您的手机上,请注意查收</div>
           <!-- <div>提交成功,审核时间在1~3个工作日内,申请结果会通过邮件的方式通知到您,请注意查看邮箱</div> -->
         </div>
 
@@ -20,7 +21,7 @@
           <div class="d-flex flex-column align-center">
             <svg-icon name="submit" size="300"></svg-icon>
           </div>
-          <div>您的申请正在审核中,审核时间在1~3个工作日内,申请结果会以短信方式通知到您的手机上,请注意查收</div>
+          <div>您的企业账号申请正在审核中,审核时间在1~3个工作日内,申请结果会以短信方式通知到您的手机上,请注意查收</div>
           <!-- <span>您的申请正在审核中,审核时间在1~3个工作日内,申请结果会通过邮件的方式通知到您,请注意查看邮箱</span> -->
           <div class="mt-5">
             <span>提交时间:{{ applyInfo.createTime }}</span>
@@ -29,8 +30,7 @@
 
         <!-- 审核不通过 -->
         <div v-else-if="applyInfo.status === '2'">
-          <div class="mb-3" style="color: red;">审核不通过</div>
-          <div class="mb-3" style="color: red;">原因:{{ applyInfo.reason }}</div>
+          <div class="mb-3" style="color: red;">您的企业账号注册申请审核不通过,具体原因如下:{{ applyInfo.reason }}</div>
           <div v-if="applyInfo.remark">备注:{{ applyInfo.remark }}</div>
           <div class="mt-5">
             <span>审核时间:{{ applyInfo.updateTime }}</span>
@@ -46,7 +46,7 @@
         </div>
         <div class="text-center" v-if="!isMobile">
           <v-btn class="mt-16 buttons" color="primary" to="/recruitHome">{{ $t('common.toHome') }}</v-btn>
-          <v-btn v-if="applyInfo.status === '2'" class="mt-16 ml-12 buttons" color="primary" to="/recruit/entRegister">{{ $t('common.resubmit') }}</v-btn>
+          <v-btn v-if="applyInfo.status === '2'" class="mt-16 ml-12 buttons" color="primary" @click="handleConfirm">{{ $t('common.resubmit') }}</v-btn>
         </div>
       </div>
     </v-card>
@@ -54,13 +54,14 @@
 </template>
 
 <script setup>
+defineOptions({name: 'enterprise-enterpriseRegister-inReview'})
 import { timesTampChange } from '@/utils/date'
 import { getUserRegisterEnterpriseApply } from '@/api/personal/user'
 import { onMounted, ref } from 'vue';
 import { useRouter } from 'vue-router'; const router = useRouter()
-defineOptions({name: 'enterprise-enterpriseRegister-inReview'})
 
 const applyInfo = ref({})
+const query = router.currentRoute.value.query
 
 // 组件挂载后添加事件监听器  
 const isMobile = ref(false)
@@ -71,7 +72,7 @@ onMounted(() => {
 
 // 查看用户是否有在申请中的数据
 const getApplyInfo = async () => {
-  const data = await getUserRegisterEnterpriseApply() // 已经有数据说明已经申请过了
+  const data = query?.noLogin ? JSON.parse(localStorage.getItem('entRegisterData')) : await getUserRegisterEnterpriseApply() // 已经有数据说明已经申请过了
   localStorage.setItem('userApplyInfo', JSON.stringify(data))
   const obj = {
     createTime: timesTampChange(data.createTime), // 创建时间
@@ -84,6 +85,10 @@ const getApplyInfo = async () => {
 }
 getApplyInfo()
 
+const handleConfirm = () => {
+  router.push(query?.noLogin ? '/register/company?type=noLoginToRegister&login=true' : '/recruit/entRegister')
+}
+
 </script>
 <style lang="scss" scoped>
 .mobileBox {

+ 33 - 12
src/views/recruit/entRegister/register.vue

@@ -3,7 +3,7 @@
     <v-card class="pa-5" :class="isMobile? 'mobileBox' : 'default-width'" :elevation="isMobile? '0' : '3'">
       <!-- 标题 -->
       <div class="mt-3">
-        <v-btn v-if="pageType !== 'noLoginToRegister'" color="black" variant="text" @click="router.push('/recruitHome')">{{ `<< 回到首页` }}</v-btn>
+        <v-btn v-if="pageType !== 'noLoginToRegister'" color="primary" variant="text" @click="router.push('/recruitHome')">{{ `<< 回到首页` }}</v-btn>
         <div v-else style="height: 30px;"></div>
       </div>
       <!-- 表单 -->
@@ -72,8 +72,9 @@ const loginLoading = ref(false)
 // 图片预览
 const showPreview = ref(false)
 const current = ref(0)
+const email = localStorage.getItem('loginAccount') || ''
 
-// 组件挂载后添加事件监听器  
+// 组件挂载后添加事件监听器
 const isMobile = ref(false)
 onMounted(() => {
   const userAgent = navigator.userAgent
@@ -94,6 +95,18 @@ const isPrepareChange = () => {
   }
 }
 
+const handleSecondConfirm = () => {
+  const obj = formItems.value.options.find(e => e.key === 'passwordConfirm')
+  obj.type = obj.type === 'password' ? 'text' : 'password'
+  obj.appendInnerIcon = obj.type === 'password' ? 'mdi-eye-off-outline' : 'mdi-eye-outline'
+}
+
+const handlePassword = () => {
+  const obj = formItems.value.options.find(e => e.key === 'password')
+  obj.type = obj.type === 'password' ? 'text' : 'password'
+  obj.appendInnerIcon = obj.type === 'password' ? 'mdi-eye-off-outline' : 'mdi-eye-outline'
+}
+
 const formItems = ref({
   options: [
     {
@@ -132,7 +145,7 @@ const formItems = ref({
     {
       type: 'text',
       key: 'email',
-      value: '',
+      value: email ? email : '',
       label: '联系邮箱(可用于企业招聘登录) *',
       rules: [
         value => {
@@ -146,36 +159,40 @@ const formItems = ref({
       ]
     },
     {
-      type: 'text',
+      type: 'password',
       key: 'password',
       value: '',
+      appendInnerIcon: 'mdi-eye-off-outline',
       label: '邮箱登录密码(用于企业招聘邮箱登录) *',
       placeholder: '请输入邮箱登录密码(用于企业招聘邮箱登录)',
+      appendInnerClick: handlePassword,
       rules: [
         value => {
           if (value) return true
           return '请输入邮箱登录密码(用于企业招聘邮箱登录)'
         },
         value => {
-          if (!(/^[\s]+$/.test(value))) return true
-          return '请输入邮箱登录密码(用于企业招聘邮箱登录)'
+          if (/^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{8,16}$/.test(value)) return true
+          return '请输入8-16位数由数字、大小写字母组成的密码'
         }
       ]
     },
     {
-      type: 'text',
+      type: 'password',
       key: 'passwordConfirm',
       value: '',
+      appendInnerIcon: 'mdi-eye-off-outline',
       label: '请再次输入邮箱登录密码 *',
       placeholder: '请再次输入邮箱登录密码',
+      appendInnerClick: handleSecondConfirm,
       rules: [
         value => {
           if (value) return true
-          return '请再次输入邮箱登录密码'
+          return '请再次输入密码(用于企业招聘邮箱登录)'
         },
         value => {
-          if (!(/^[\s]+$/.test(value))) return true
-          return '请再次输入邮箱登录密码'
+          if (value === formItems.value.options.find(e => e.key === 'password').value) return true
+          return '两次输入密码不一致'
         }
       ]
     },
@@ -208,9 +225,10 @@ const handleCommit = async () => {
   }
   formItems.value.options.forEach(e => { params[e.key] = e.value })
   // 邮箱登录密码校验
-  if (params.password !== params.passwordConfirm) return Snackbar.warning('两次输入的密码不一致,请确认')
+  // if (params.password !== params.passwordConfirm) return Snackbar.warning('两次输入的密码不一致,请确认')
 
   await enterpriseRegisterApply(params)
+  localStorage.removeItem('loginAccount')
   Snackbar.success(t('common.submittedSuccessfully'))
   router.push({ path: '/recruit/entRegister/inReview' })
 }
@@ -224,7 +242,10 @@ if (info && Object.keys(info).length && info.status === '2') {
   licenseUrl.value = info?.businessLicenseUrl
   isPrepare.value = info?.prepare || false
   isPrepareChange()
-  formItems.value.options.forEach(e => { e.value = info[e.key] })
+  formItems.value.options.forEach(e => {
+    if (e.key === 'passwordConfirm') e.value = info.password
+    else e.value = info[e.key]
+  })
 }
 
 </script>

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

@@ -32,6 +32,7 @@
               class="mb-3"
               :is="item.path"
               @complete="complete"
+              @change="val => tab = val"
             />
           </div>
         </template>

+ 2 - 2
src/views/recruit/enterprise/entInfoSetting/informationSettingsComponents/basicInfo.vue

@@ -6,7 +6,7 @@
       <template #name="{ item }">
         <div v-show="!item.show" class="text-right" style="width: 80px; line-height: 40px;">
           <v-icon :color="statusInfo.color" size="20">{{ statusInfo.mdi }}</v-icon>
-          <span :style="{'color': statusInfo.color,'font-size': '14px'}">{{ statusInfo.label }}</span>
+          <span class="cursor-pointer text-decoration-underline" :style="{'color': statusInfo.color,'font-size': '14px'}" @click="emit('change', 6)">{{ statusInfo.label }}</span>
         </div>
       </template>
       <template #industryId="{ item }">
@@ -40,7 +40,7 @@ import { getDict } from '@/hooks/web/useDictionaries'
 import { useI18n } from '@/hooks/web/useI18n'
 import industryTypeCard from '@/components/industryTypeCard'
 import Snackbar from '@/plugins/snackbar'
-const emit = defineEmits(['complete'])
+const emit = defineEmits(['complete', 'change'])
 
 const { t } = useI18n()
 const CtFormRef = ref()

+ 0 - 71
src/views/recruit/enterprise/enterpriseCenter/components/introduction.vue

@@ -1,71 +0,0 @@
-<!-- 公司简介 -->
-<template>
-  <div>
-    <h4 class="mb-1">公司简介</h4>
-    <div v-if="props.info.enterprise?.introduce" class="requirement" v-html="props.info.enterprise?.introduce?.replace(/\n/g, '</br>')"></div>
-    <div v-else>暂无</div>
-    <v-divider class="my-3"></v-divider>
-    <h4>作息时间</h4>
-    <div>
-      <v-icon class="mr-2" size="25" color="primary">mdi-alarm</v-icon>
-      <span class="workAndRest">{{ props.info.enterprise?.time }}</span>
-      <v-icon class="mr-2 ml-4" size="25" color="primary">mdi-calendar-range</v-icon>
-      <span class="workAndRest">{{ props.info.enterprise?.restType }}</span>
-    </div>
-    <v-divider class="my-3"></v-divider>
-    <h4>企业福利</h4>
-    <div class="welfare-tags">
-      <v-chip size="small" label v-for="(k, i) in info.enterprise?.welfareList" :key="i" class="mb-2 welfare-tags-item ellipsis" color="primary">{{ k }}</v-chip>
-    </div>
-    <v-divider class="my-3"></v-divider>
-    <h4 class="mb-1">关于我们</h4>
-    <div v-if="props.info.enterprise?.aboutUs" class="requirement" v-html="props.info.enterprise?.aboutUs?.replace(/\n/g, '</br>')"></div>
-  </div>
-</template>
-
-<script setup>
-defineOptions({name: 'enterprise-enterpriseCenter-introduction'})
-
-const props = defineProps({
-  info: {
-    type: Object,
-    default: () => {}
-  }
-})
-</script>
-
-<style scoped lang="scss">
-h4 { margin-bottom: 8px; }
-.requirement {
-  white-space: pre-wrap;
-  word-break: break-all;
-  line-height: 28px;
-  color: var(--color-333);
-  font-size: 15px;
-  text-align: justify;
-  letter-spacing: 0;
-  // width: 60%;
-}
-.workAndRest {
-  color: var(--color-666);
-  font-size: 15px;
-}
-.welfare-tags {
-  display: flex;
-  // width: 242px;
-  flex-wrap: wrap;
-  // height: 100px;
-  // overflow: hidden;
-  text-align: center;
-}
-.welfare-tags-item {
-  display: block;
-  width: 117px;
-  max-width: 117px;
-  text-align: center;
-  line-height: 26px;
-  margin-right: 8px;
-  // &:nth-child(2n) { margin-right: 0; }
-}
-</style>
-

+ 0 - 273
src/views/recruit/enterprise/enterpriseCenter/components/positions.vue

@@ -1,273 +0,0 @@
-<!-- 在招职位 -->
-<template>
-  <div class="top">
-    <div class="d-flex">
-      <div class="font-weight-bold position-category-left">职位类别:</div>
-      <div class="position-category-right">
-        <span 
-          :class="['category-item', {'default-active': k.active}, {'font-weight-bold': k.active}]" 
-          v-for="k in positionCategory" 
-          :key="k.id"
-          @click="handleClickCategory(k)"
-        >{{ k.id === -1 ? `${k.label}` : `${k.label} (${k.number})` }}</span>
-      </div>
-    </div>
-    <div class="d-flex mt-3">
-      <areaType v-if="areaList.length" :list="areaList" @inputChange="val => handleSearch('areaIds', val)"></areaType>
-      <expType :isSingle="true" @inputChange="val => handleSearch('expType', val)"></expType>
-      <educationType :isSingle="true" @inputChange="val => handleSearch('eduType', val)"></educationType>
-      <payScope @input-change="val => handleSearch('payType', val)"></payScope>
-      <div style="width: 300px;">
-        <v-text-field
-          v-model="query.content"
-          variant="outlined" 
-          label="查找职位关键字"
-          hide-details
-          color="primary"
-          append-inner-icon="mdi-magnify"
-          @click:append-inner="handleSearch('content', { values: query.content })"
-          @keyup.enter="handleSearch('content', { values: query.content })"
-        >
-        </v-text-field>
-      </div>
-    </div>
-  </div>
-  <v-divider class="mt-5"></v-divider>
-  <div class="bottom mt-4">
-    <div v-if="list.length">
-      <div 
-        v-for="(val, i) in list" 
-        :key="i" 
-        :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>
-          <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>
-          </div>
-        </div>
-        <div v-if="!val.active" class="text-right">
-          <p v-if="!val.job.payFrom && !val.job.payTo" class="salary">面议</p>
-          <p v-else class="salary">{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}{{ val.job.payName ? '/' + val.job.payName : '' }}</p>
-          <div class="update-time">{{ timesTampChange(val.job.updateTime) }} 刷新</div>
-        </div>
-        <div v-else class="account-info">
-          <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>
-          </span>
-        </div>
-      </div>
-      <MPagination
-        :total="total"
-        :page="pageInfo.pageNo"
-        :limit="pageInfo.pageSize"
-        @handleChange="handleChangePage"
-      ></MPagination>
-    </div>
-    <Empty v-else :elevation="false"></Empty>
-  </div>
-</template>
-
-<script setup>
-defineOptions({name: 'enterprise-enterpriseCenter-positions'})
-import { reactive, ref, provide } from 'vue'
-import { useRoute, useRouter } from 'vue-router'
-import { timesTampChange } from '@/utils/date'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { dealDictObjData } from '@/utils/position'
-import { getJobAdvertisedPositionCount, getJobAreaByEnterpriseId, getJobAdvertisedSearch } from '@/api/position'
-import MPagination from '@/components/CtPagination'
-import expType from '@/views/recruit/personal/position/components/conditionFilter/expType.vue'
-import educationType from '@/views/recruit/personal/position/components/conditionFilter/educationType.vue'
-import payScope from '@/views/recruit/personal/position/components/conditionFilter/payScope.vue'
-import areaType from '@/views/recruit/personal/position/components/conditionFilter/areaType.vue'
-
-const props = defineProps({
-  info: {
-    type: Object,
-    default: () => {}
-  }
-})
-
-const total = ref(0)
-const pageInfo = ref({
-  pageSize: 10,
-  pageNo: 1
-})
-let query = reactive({})
-const route = useRoute(); const router = useRouter()
-const routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? route.query : null
-if (routeQuery?.content) query.content = routeQuery?.content
-provide('routeQuery', routeQuery)
-if (routeQuery) query = routeQuery
-
-// 职位详情
-const handlePosition = (val) => {
-  window.open(`/recruit/personal/position/details/${val.job.positionId}`)
-}
-
-// 行业列表
-const industryList = ref([])
-const getDictData = async () => {
-  const { data } = await getDict('menduner_industry_type', {}, 'industryList')
-  industryList.value = data
-}
-getDictData()
-
-// 职位类别&工作地点
-const positionCategory = ref([])
-const areaList = ref([])
-const getData = async () => {
-  const data = await getJobAdvertisedPositionCount({ enterpriseId: props.info.enterprise.id })
-  areaList.value = await getJobAreaByEnterpriseId({ enterpriseId: props.info.enterprise.id })
-  const list = data.map(val => {
-    const value = industryList.value.find(e => Number(e.id) === Number(val.key))
-    return { id: value.id, label: value.nameCn, number: val.value, active: false }
-  })
-  positionCategory.value = [{ id: -1, label: '全部', active: true }, ...list]
-}
-const getPoAr = async () => {
-  await getData()
-  // 职位类别回显
-  if (routeQuery?.positionId) {
-    positionCategory.value.map(e => e.active = false)
-    positionCategory.value.find(e => e.id === routeQuery.positionId).active = true
-  }
-}
-getPoAr()
-
-
-
-// 职位类别选中
-const handleClickCategory = (k) => {
-  positionCategory.value.map(e => e.active = false)
-  k.active = !k.active
-  handleSearch('positionId', { values: k.id })
-}
-
-const dealRouteQuery = () => {
-  const arr = Object.keys(query).map(e => {
-    if (Array.isArray(query[e]) && !query[e].length) {
-      delete query[e]
-    }
-    if (!query[e]) delete query[e]
-    if (e !== 'pageSize' && e !== 'pageNo' && e !== 'enterpriseId') return `${e}=${query[e]}`
-  }).filter(Boolean)
-  const str = ['key=recruitmentPositions', ...arr].join('&')
-  if (str) router.replace(`${route.path}?${str}`)
-}
-
-const handleSearch = (key, { values }) => {
-  if (values === -1 || !values || values[0] === -1 || !values.length) delete query[key]
-  else query[key] = values
-  dealRouteQuery()
-  getPositionList(true)
-}
-
-// 职位列表
-const list = ref([])
-// 职位列表
-const getPositionList = async (isSearch) => {
-  query = {
-    ...query,
-    ...pageInfo.value,
-    enterpriseId: props.info.enterprise.id
-  }
-  delete query.key
-  if (isSearch) query.pageNo = 1
-  const { list: arr, total: number } = await getJobAdvertisedSearch(query)
-  total.value = number
-  list.value = arr.map(e => {
-    e.active = false
-    e.job = { ...e.job, ...dealDictObjData({}, e.job) }
-    return e
-  })
-}
-getPositionList()
-
-const handleChangePage = (index) => {
-  pageInfo.value.pageNo = index
-  getPositionList()
-}
-
-// 城市、学历、工作经验
-const desc = [
-  { mdi: 'mdi-map-marker-outline', value: 'areaName' },
-  { mdi: 'mdi-school-outline', value: 'eduName' },
-  { mdi: 'mdi-clock-time-ten-outline', value: 'expName' }
-]
-</script>
-
-<style scoped lang="scss">
-.bottom-item {
-  width: 100%;
-  height: 68px;
-  margin-bottom: 12px;
-}
-.name {
-  position: relative;
-  max-width: 200px;
-  margin-right: 8px;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  font-weight: 600;
-}
-.salary {
-  font-size: 16px;
-  font-weight: 700;
-  color: var(--v-error-base);
-  line-height: 22px;
-  flex: none;
-}
-.tag-text {
-  color: var(--color-222);
-  font-size: 14px;
-}
-.update-time {
-  color: var(--color-666);
-  font-size: 14px;
-  line-height: 40px;
-}
-.account-info {
-  line-height: 52px;
-  .account-label {
-    color: var(--color-666);
-    font-size: 14px;
-    font-weight: 600;
-    margin: 0 10px;
-  }
-}
-.position-category-left {
-  width: 80px;
-}
-.position-category-right {
-  flex: 1;
-}
-.category-item {
-  display: inline-block;
-  margin-right: 20px;
-  font-size: 15px;
-  color: var(--color-666);
-  cursor: pointer;
-  &:hover {
-    color: var(--v-primary-base);
-  }
-}
-:deep(.v-field__input) {
-  height: 28px;
-  padding: 0 0 0 10px;
-  font-size: 12px;
-  min-height: 28px;
-}
-</style>
-

+ 0 - 40
src/views/recruit/enterprise/enterpriseCenter/components/video.vue

@@ -1,40 +0,0 @@
-<!-- 企业视频 -->
-<template>
-  <div class="box">
-    <div class="box-item" v-for="(val, i) in props.info.enterprise?.albumList" :key="val">
-      <v-img v-if="checkIsImage(val)" width="205" height="115" :src="val" cover rounded @click="handleClick(i)"></v-img>
-      <video v-else class="videos-radius" :src="val" controls height="118" width="200" preload="preload" @click="handleClick(i)"></video>
-    </div>
-  </div>
-  <PreviewImg v-if="showPreview" :current="current" :list="props.info.enterprise?.albumList" @close="showPreview = !showPreview"></PreviewImg>
-</template>
-
-<script setup>
-import { checkIsImage } from '@/utils'
-import { ref } from 'vue'
-defineOptions({name: 'enterprise-enterpriseCenter-video'})
-
-const props = defineProps({
-  info: {
-    type: Object,
-    default: () => {}
-  }
-})
-
-// 预览
-const showPreview = ref(false)
-const current = ref(0)
-const handleClick = (index) => {
-  showPreview.value = !showPreview.value
-  current.value = index
-}
-</script>
-<style lang="scss" scoped>
-.box {
-  display: flex;
-  flex-wrap: wrap;
-  .box-item {
-    margin: 0 12px 12px 0;
-  }
-}
-</style>

File diff suppressed because it is too large
+ 0 - 64
src/views/recruit/enterprise/enterpriseCenter/index.vue


+ 8 - 0
src/views/recruit/enterprise/hirePosition/components/jobRequirements.vue

@@ -119,6 +119,10 @@ const items = ref({
         value => {
           if (value >= 1) return true
           return '数额不得小于1'
+        },
+        value => {
+          if (value < items.value.options.find(e => e.key === 'payTo').value) return true
+          return '不得大于最高薪资'
         }
       ]
     },
@@ -138,6 +142,10 @@ const items = ref({
         value => {
           if (value >= 1) return true
           return '数额不得小于1'
+        },
+        value => {
+          if (value > items.value.options.find(e => e.key === 'payFrom').value) return true
+          return '不得小于最高薪资'
         }
       ]
     },

+ 7 - 0
src/views/recruit/enterprise/interviewManagement/components/invite.vue

@@ -6,6 +6,8 @@
         placeholder="面试时间 *"
         class="mb-4"
         model-type="timestamp"
+        :disabled-dates="disabledDates"
+        :day-names="['一', '二', '三', '四', '五', '六', '七']"
         :text-input="{ format: 'MM.dd.yyyy HH:mm' }" />
     </template>
   </CtForm>
@@ -26,6 +28,11 @@ const props = defineProps({
   }
 })
 
+// 过去的日期不可选
+const disabledDates = (date) => {
+  return date.getTime() < new Date().getTime()
+}
+
 const CtFormRef = ref()
 const formItems = ref({
   options: [

+ 7 - 0
src/views/recruit/enterprise/personnelManagement/components/invite.vue

@@ -6,6 +6,8 @@
         placeholder="面试时间 *"
         class="mb-4"
         model-type="timestamp"
+        :disabled-dates="disabledDates"
+        :day-names="['一', '二', '三', '四', '五', '六', '七']"
         :text-input="{ format: 'MM.dd.yyyy HH:mm' }" />
     </template>
   </CtForm>
@@ -22,6 +24,11 @@ const props = defineProps({
   }
 })
 
+// 过去的日期不可选
+const disabledDates = (date) => {
+  return date.getTime() < new Date().getTime()
+}
+
 const CtFormRef = ref()
 const formItems = ref({
   options: [

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

@@ -119,13 +119,17 @@ const items = ref({
         value => {
           if (value >= 1) return true
           return '数额不得小于1'
+        },
+        value => {
+          if (value < items.value.options.find(e => e.key === 'payTo').value) return true
+          return '不得大于最高薪资'
         }
       ]
     },
     {
       type: 'text',
       key: 'payTo',
-      value: '',
+      value: '10',
       col: 4,
       label: '最高薪资 *',
       flexStyle: 'mx-3',
@@ -138,6 +142,10 @@ const items = ref({
         value => {
           if (value >= 1) return true
           return '数额不得小于1'
+        },
+        value => {
+          if (value > items.value.options.find(e => e.key === 'payFrom').value) return true
+          return '不得小于最高薪资'
         }
       ]
     },

+ 7 - 0
src/views/recruit/enterprise/resume/components/invite.vue

@@ -6,6 +6,8 @@
         placeholder="面试时间 *"
         class="mb-4"
         model-type="timestamp"
+        :disabled-dates="disabledDates"
+        :day-names="['一', '二', '三', '四', '五', '六', '七']"
         :text-input="{ format: 'MM.dd.yyyy HH:mm' }" />
     </template>
   </CtForm>
@@ -22,6 +24,11 @@ const props = defineProps({
   }
 })
 
+// 过去的日期不可选
+const disabledDates = (date) => {
+  return date.getTime() < new Date().getTime()
+}
+
 const CtFormRef = ref()
 const formItems = ref({
   options: [

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

@@ -33,7 +33,7 @@
         <v-btn v-if="tab === 0" color="primary" variant="text" @click="handleInterviewInvite(item)">邀请面试</v-btn>
         <v-btn v-if="tab === 0" color="primary" variant="text" @click="handleToCommunicate(item)">立即沟通</v-btn>
         <v-btn v-if="tab === 0 || tab === 1" color="primary" variant="text" @click="handleEliminate(item)">不合适</v-btn>
-        <v-btn v-if="!item.inTalentPool && (tab === 1 || tab === 2 || tab === 3)" color="primary" variant="text" @click="handleJoinToTalentPool(item)">加入人才库</v-btn>
+        <v-btn v-if="!item.inTalentPool && (tab === 1 || tab === 2 || tab === 3)" color="primary" variant="text" @click="handleJoinToTalentPool(item)">加入精英储备</v-btn>
         <v-btn v-if="tab === 1 && (item.status === '3' || item.status === '4')" color="primary" variant="text" @click="handleEnterByEnterprise(item)">入职</v-btn>
         <v-btn v-if="tab === 4" color="primary" variant="text" @click="handleCancelEliminate(item)">取消不合适</v-btn>
         <v-btn v-if="tab === 2 && item?.job?.hire" color="primary" variant="text" @click="handleSettlement(item)">结算</v-btn>

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/companyCollection.vue

@@ -9,7 +9,7 @@
         @handleChange="handleChangePage"
       ></CtPagination>
     </div>
-    <Empty v-else></Empty>
+    <Empty v-else :elevation="false"></Empty>
   </div>
 </template>
 

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/delivery.vue

@@ -9,7 +9,7 @@
         @handleChange="handleChangePage"
       ></CtPagination>
     </div>
-    <Empty v-else></Empty>
+    <Empty v-else :elevation="false"></Empty>
   </div>
 </template>
 

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/index.vue

@@ -14,7 +14,7 @@
           @handleChange="handleChangePage"
         ></CtPagination>
       </div>
-      <Empty v-else class="mt-3"></Empty>
+      <Empty v-else class="mt-3" :elevation="false"></Empty>
   </div>
 </template>
 

+ 7 - 5
src/views/recruit/personal/PersonalCenter/jobFeedback/components/interview/item.vue

@@ -1,7 +1,6 @@
 <template>
   <div class="position-item mb-3 job-closed elevation-2"
     style="position: relative;"
-    :class="{'close-position': val.job.status === '1'}"  
     v-for="(val, i) in props.items" :key="i" @mouseenter="val.active = true" @mouseleave="val.active = false"
   >
     <div class="info-header">
@@ -9,9 +8,10 @@
         <v-btn color="primary" size="small" @click="handleAgree(val)">同意</v-btn>
         <v-btn class="ml-3" color="error" size="small" @click="handleRefuse(val)">拒绝</v-btn>
       </div>
-      <div v-if="tab === '1' || tab === '98'" class="float-right font-size-13" :style="{'padding': '12px 12px 0 0', 'color': tab === '1' ? 'var(--v-primary-base)' : 'var(--v-error-base)'}">
+      <div v-if="val.job.status === '1'" class="font-size-14 header-btn color-error">职位已关闭</div>
+      <!-- <div v-if="tab === '1' || tab === '98'" class="float-right font-size-13" :style="{'padding': '12px 12px 0 0', 'color': tab === '1' ? 'var(--v-primary-base)' : 'var(--v-error-base)'}">
         您已于{{ timesTampChange(val.updateTime, 'Y-M-D h:m') }}{{ tab === '1' ? '接受' : '拒绝'}}了此面试邀请
-      </div>
+      </div> -->
       <div class="img-box">
           <v-avatar :image="getUserAvatar(val.contact.avatar, val.contact.sex)" size="x-small"></v-avatar>
           <span class="name">
@@ -24,12 +24,13 @@
     </div>
     <div class="info-content">
         <div class="font-size-16 color-333 mr-5" style="width: 322px;">
+          <div v-if="tab === '1' || tab === '98'" class="font-size-13 mb-1" :style="{'color': tab === '1' ? 'var(--v-primary-base)' : 'var(--v-error-base)'}">您已于{{ timesTampChange(val.updateTime, 'Y-M-D h:m') }}{{ tab === '1' ? '接受' : '拒绝'}}了此面试邀请</div>
           <div>面试时间:{{ timesTampChange(val.time, 'Y-M-D h:m') }}</div>
           <div class="mt-3 ellipsis" style="max-width: 322px;">面试地点:{{ val.address }}</div>
         </div>
         <div class="job-info color-666">
           <div class="job-name ellipsis" style="max-width: 410px;">
-            <span class="mr-3 cursor-pointer position-name" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
+            <span class="mr-3" :class="{'cursor-pointer': val.job.status === '0', 'position-name': val.job.status === '0'}" @click="handleToPositionDetails(val)">{{ val.job.name }}</span>
             <span v-if="!val.job.payFrom && !val.job.payTo">面议</span>
             <span v-else>{{ val.job.payFrom ? val.job.payFrom + '-' : '' }}{{ val.job.payTo }}{{ val.job.payName ? '/' + val.job.payName : '' }}</span>
           </div>
@@ -85,6 +86,7 @@ const handleToEnterprise = (item) => {
 
 // 职位详情
 const handleToPositionDetails = (item) => {
+  if (item.job.status === '1') return
   router.push(`/recruit/personal/position/details/${item.job.id}`)
 }
 
@@ -120,7 +122,7 @@ const handleRefuse = (val) => {
 
 <style scoped lang="scss">
 .position-item {
-  height: 144px;
+  height: 160px;
   background-color: #fff;
   border-radius: 12px;
   &:hover {

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/positionCollection.vue

@@ -9,7 +9,7 @@
         @handleChange="handleChangePage"
       ></CtPagination>
     </div>
-    <Empty v-else></Empty>
+    <Empty v-else :elevation="false"></Empty>
   </div>
 </template>
 

+ 1 - 1
src/views/recruit/personal/PersonalCenter/jobFeedback/components/seenMe.vue

@@ -33,7 +33,7 @@
         @handleChange="handleChangePage"
       ></CtPagination>
     </div>
-    <Empty v-else></Empty>
+    <Empty v-else :elevation="false"></Empty>
   </div>
 </template>
 

+ 23 - 32
src/views/recruit/personal/PersonalCenter/resume/online/components/basicInfo.vue

@@ -123,6 +123,7 @@ import { uploadFile } from '@/api/common'
 import { getUserAvatar } from '@/utils/avatar'
 import { useI18n } from '@/hooks/web/useI18n'
 import portrait from './portrait.vue'
+import { checkEmail } from '@/utils/validate'
 import { ref } from 'vue';
 defineOptions({name: 'resume-components-basicInfo'})
 const emit = defineEmits(['complete'])
@@ -132,6 +133,7 @@ const userStore = useUserStore()
 const CtFormRef = ref()
 const isEdit = ref(false)
 const showIcon = ref(false)
+let completeStatus = false
 const overlay = ref(false) // 加载中
 let baseInfo = ref({})
 let userInfo = ref({})
@@ -140,6 +142,10 @@ const getBasicInfo = () => { // 获取基础信息
   if (!key || !Object.keys(key).length) return
   baseInfo.value = JSON.parse(key) // 人才信息
   userInfo.value = JSON.parse(localStorage.getItem('userInfo'))
+  if (baseInfo.value && Object.keys(baseInfo.value).length) {
+    completeStatus = true
+    emit('complete', { status: completeStatus, id: 'basicInfo' })
+  }
 }
 getBasicInfo()
 
@@ -215,7 +221,7 @@ const items = ref({
       key: 'sex',
       value: '0', // '1' ? '男' : '女'
       default: 0,
-      label: '性别',
+      label: '性别 *',
       col: 6,
       width: 70,
       dictTypeName: 'menduner_sex',
@@ -224,13 +230,11 @@ const items = ref({
     {
       type: 'datePicker',
       key: 'birthday',
-      // dateType: 'date', // 时间类型 year month date time
       value: null,
       label: '出生日期 *',
       col: 6,
       outlined: true,
       rules: [v => !!v || '请选择出生日期']
-      // options: {},
     },
     {
       type: 'phoneNumber',
@@ -239,20 +243,22 @@ const items = ref({
       default: null,
       label: '电话号码',
       col: 6,
-      outlined: true,
-      rules: [v => !!v || '请填写手机号码']
-      // disabled: true,
-      // slotName: 'phone',
+      outlined: true
     },
     {
       type: 'text',
       key: 'email',
       value: null,
       default: null,
-      label: '常用邮箱 *',
+      label: '常用邮箱',
       col: 6,
       outlined: true,
-      rules: [v => !!v || '请输入常用邮箱']
+      rules: [
+        value => {
+          if (value && !checkEmail(value)) return '请输入正确的电子邮箱'
+          return true
+        }
+      ]
     },
     {
       type: 'autocomplete',
@@ -315,20 +321,19 @@ const items = ref({
       key: 'maritalStatus',
       value: null,
       default: null,
-      label: '婚姻状况 *',
+      label: '婚姻状况',
       col: 6,
       outlined: true,
       itemText: 'label',
       itemValue: 'value',
       dictTypeName: 'menduner_marital_status',
-      rules: [v => !!v || '请选择婚姻状况'],
       items: []
     },
     {
       type: 'autocomplete',
       key: 'workAreaProvinceId',
       value: null,
-      label: '所在城市:省 *',
+      label: '所在城市:省',
       outlined: true,
       itemText: 'name',
       itemValue: 'id',
@@ -336,7 +341,6 @@ const items = ref({
       noParam: true,
       col: 6,
       flexStyle: 'mr-3',
-      rules: [v => !!v || '请选择所在城市:省'],
       items: [],
       change: null
     },
@@ -344,12 +348,11 @@ const items = ref({
       type: 'autocomplete',
       key: 'areaId',
       value: null,
-      label: '所在城市:市 *',
+      label: '所在城市:市',
       outlined: true,
       itemText: 'name',
       itemValue: 'id',
       col: 6,
-      rules: [v => !!v || '请选择所在城市:市'],
       items: [],
       change: null
     },
@@ -387,13 +390,10 @@ const items = ref({
       dateType: 'month',
       key: 'firstWorkTime',
       value: null,
-      label: '首次工作时间 *',
+      label: '首次工作时间',
       col: 6,
-      outlined: true,
-      // clearable: true,
-      rules: [v => !!v || '请选择首次工作时间']
-      // options: {},
-    },
+      outlined: true
+    }
   ]
 })
 
@@ -408,13 +408,13 @@ const handleSave = async () => {
     if (e.type === 'datepicker') obj[e.key] = getTimeStamp(e.value)
     else obj[e.key] = e.value
   })
+  if (!obj.sex) return Snackbar.warning('请先选择您的性别')
   await saveResumeBasicInfo(obj)
   Snackbar.success(t('common.saveMsg'))
   isEdit.value = false
-  // 获取当前登录账户信息
-  // if (baseInfo.value.userId) await userStore.getUserBaseInfos(baseInfo.value.userId)
   await userStore.getUserBaseInfos(baseInfo.value.userId || null)
   getBasicInfo()
+
   // 清除户籍地:省
   if (clearRegProvinceId) items.value.options.forEach(e => { if (e.key === 'regProvinceId') e.value = null })
 }
@@ -448,18 +448,14 @@ const deal = async (id, cityKey, provinceKey) => {
   }
 }
 
-let completeStatus = false
 items.value.options.forEach((e, index) => {
   if ((index + 2) % 2 === 0) e.flexStyle = 'mr-3'
   if (e.dictTypeName) getDictData(e.dictTypeName) // 查字典set options
-  // formItems回显
   const infoExist = baseInfo.value && Object.keys(baseInfo.value).length
-  if (infoExist) completeStatus = true
   if (infoExist && baseInfo.value[e.key]) e.value = baseInfo.value[e.key]
   // 日期相关
   if (e.type === 'datepicker') e.value = timesTampChange(e.value, 'Y-M-D')
   // 所在城市回显
-  // if (infoExist && e.nameKey) e[e.nameKey] = baseInfo.value[e.nameKey]
   if (infoExist && e.key === 'areaId' && baseInfo.value[e.key]) {
     const id = baseInfo.value[e.key]
     deal(id, e.key, 'workAreaProvinceId')
@@ -471,7 +467,6 @@ items.value.options.forEach((e, index) => {
   if (e.value === undefined || e.value === null || e.value === '') completeStatus = false
 })
 // 完成度展示
-emit('complete', { status: completeStatus, id: 'basicInfo' })
   
 const provinceChange = (value, val, obj) => {
   let cityKey
@@ -486,11 +481,7 @@ const provinceChange = (value, val, obj) => {
 getDict('areaTreeData', null, 'areaTreeData').then(({ data }) => {
   data = data?.length && data || []
   if (!data?.length) return console.error('areaTreeData获取失败!')
-  //
-  // const china = data.find(e => e.id === '1')
-  // const chinaTreeData = china?.children?.length ? china.children : []
   const chinaTreeData = data
-  //
   if (!chinaTreeData?.length) return console.error('chinaTreeData获取失败!')
   const workAreaProvince = items.value.options.find(e => e.key === 'workAreaProvinceId')
   const regAreaProvince = items.value.options.find(e => e.key === 'regProvinceId')

+ 0 - 2
src/views/recruit/personal/PersonalCenter/resume/online/components/jobIntention.vue

@@ -278,8 +278,6 @@ const handleArea = (list, arr) => {
   if (!list.length) return setValue('interestedAreaIdList', '')
   query.interestedAreaIdList = list
   areaSelect = arr
-  // const str = arr.map(e => e.name).join('、')
-  // setValue('interestedAreaIdList', str)
 }
 const handleAreaClear = (k) => {
   query.interestedAreaIdList = query.interestedAreaIdList.filter(i => i !== k.id)

+ 7 - 1
src/views/recruit/personal/PersonalCenter/resume/online/components/projectExperience.vue

@@ -2,7 +2,7 @@
   <div class="resume-box">
     <div class="resume-header">
       <div class="resume-title">{{ $t('resume.projectExperience') }}</div>
-      <v-btn variant="text" color="primary" prepend-icon="mdi-plus-box" @click="isEdit = true; type = 'add'">{{ $t('common.add') }}</v-btn>
+      <v-btn variant="text" color="primary" prepend-icon="mdi-plus-box" @click="handleAdd">{{ $t('common.add') }}</v-btn>
     </div>
     <div v-if="isEdit" class="edit">
       <h4 class="label-title my-3 mx-2"> {{ type === 'add' ? $t('common.add') : $t('common.edit') }}{{ $t('resume.projectExperience') }}</h4>
@@ -129,6 +129,12 @@ const getResumeTrainExpData = async () => {
 }
 getResumeTrainExpData()
 
+const handleAdd = () => {
+  items.value.options.forEach(e => e.value = null)
+  type.value = 'add'
+  isEdit.value = true
+}
+
 // 保存项目经历
 const handleSave = async () => {
   const { valid } = await formPageRef.value.formRef.validate()

+ 4 - 2
src/views/recruit/personal/PersonalCenter/resume/online/index.vue

@@ -103,15 +103,17 @@ const complete = (val) => {
   overflow: auto;
 }
 ::-webkit-scrollbar {
-  width: 0;
-  height: 0;
+  width: 8px;
+  height: 10px;
 }
 ::-webkit-scrollbar-thumb, .temporaryAdd ::-webkit-scrollbar-thumb, .details_edit ::-webkit-scrollbar-thumb {
   // 滚动条-颜色
   background: #c3c3c379;
+  border-radius: 10px;
 }
 ::-webkit-scrollbar-track, .temporaryAdd ::-webkit-scrollbar-track, .details_edit ::-webkit-scrollbar-track {
   // 滚动条-底色
   background: #e5e5e58f;
+  border-radius: 10px;
 }
 </style>

+ 6 - 0
src/views/recruit/personal/PersonalCenter/wallet/myBalance/index.vue

@@ -48,11 +48,17 @@ import { ref } from 'vue'
 import { timesTampChange } from '@/utils/date'
 import { FenYuanTransform } from '@/utils/position'
 import { getUserWalletRechargePage } from '@/api/recruit/personal/myWallet.js'
+import { useUserStore } from '@/store/user'
 
 const tab = ref('rechargeDetails')
 
+const userStore = useUserStore()
 const userAccount = ref(JSON.parse(localStorage.getItem('userAccount')) || {}) // 账户信息
 
+userStore.$subscribe((mutation, state) => {
+  if (Object.keys(state.userAccount).length) userAccount.value = state.userAccount
+})
+
 const total = ref(0)
 const query = ref({
   pageNo: 1,

+ 5 - 7
src/views/recruit/personal/home/components/advertisement/index.vue

@@ -25,9 +25,7 @@ const list = [
   { url: 'https://dfws-file.veimg.cn/plutus/img/finish/2021/01/1611813992000.webp' },
   { url: 'https://dfws-file.veimg.cn/plutus/img/finish/2021/01/1611813992000.webp' },
   { url: 'https://admin.61hr.com/admin/uploads/images/ad/202407/e684374c0ff349b4945bc0c7a4a2713f.gif' },
-  { url: 'https://dfws-file.veimg.cn/plutus/img/finish/2024/08/1722492376000.webp' },
-  { url: 'https://dfws-file.veimg.cn/plutus/img/finish/2024/08/1722492376000.webp' },
-  { url: 'https://admin.61hr.com/admin/uploads/images/ad/202407/e684374c0ff349b4945bc0c7a4a2713f.gif' },
+  { url: 'https://dfws-file.veimg.cn/plutus/img/finish/2024/08/1722492376000.webp' }
 ]
 
 const handleOpen = () => {
@@ -62,12 +60,12 @@ const handleOpen = () => {
 }
 .col-item {
   cursor: pointer;
-  width: calc((100% - 36px) / 4);
-  min-width: calc((100% - 36px) / 4);
-  max-width: calc((100% - 36px) / 4);
+  width: calc((100% - 24px) / 3);
+  min-width: calc((100% - 24px) / 3);
+  max-width: calc((100% - 24px) / 3);
   margin: 0 12px 12px 0;
   box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
-  &:nth-child(4n) {
+  &:nth-child(3n) {
     margin-right: 0;
   }
   &:hover {

+ 11 - 10
src/views/recruit/personal/home/index.vue

@@ -6,7 +6,6 @@
     </div>
     <hotJobs></hotJobs>
     <div class="default-width">
-      <!-- <jobTypeCard class="mb-5" page @handleJobClick="handleJobClick" isSingle></jobTypeCard> -->
       <homeJobTypeCard></homeJobTypeCard>
       <advertisementPage class="my-3"></advertisementPage>
       <hotPromotedPositions></hotPromotedPositions>
@@ -14,7 +13,7 @@
     </div>
   </div>
   <!-- 快速填写简易人才信息-弹窗 -->
-  <simplePage v-if="showSimplePage" :closeable="true" closeText="暂时跳过" @simpleInfoReady="handleUpdateInfo"></simplePage>
+  <simplePage v-if="showSimplePage" :closeable="true" closeText="暂时跳过" @close="handleInfoClose" @simpleInfoReady="handleUpdateInfo"></simplePage>
 </template>
 
 <script setup>
@@ -23,7 +22,6 @@ import simplePage from '@/views/recruit/personal/shareJob/sendResume/simple.vue'
 import headCarousel from './components/headCarousel.vue'
 import headSearch from '@/components/headSearch'
 import hotJobs from './components/hotJobs.vue'
-// import jobTypeCard from '@/components/jobTypeCard'
 import homeJobTypeCard from './components/homeJobTypeCard'
 import hotPromotedPositions from './components/hotPromotedPositions.vue'
 import PopularEnterprises from './components/popularEnterprises.vue'
@@ -34,25 +32,28 @@ import { useUserStore } from '@/store/user'
 import { getToken } from '@/utils/auth'
 
 const store = useUserStore()
-// const updateBaseInfo = async () => {
-//   await store.getUserBaseInfos()
-// }
-// updateBaseInfo()
 
 const router = useRouter()
-const simple = localStorage.getItem('simpleCompleteDialogHaveBeenShow')
+const simple = ref(localStorage.getItem('simpleCompleteDialogHaveBeenShow'))
 const showSimplePage = ref(false) // 只提示一次
-if (!getToken() && !simple) showSimplePage.value = true
+if (!getToken()) showSimplePage.value = false
 nextTick(() => {
-  if (getToken()) localStorage.setItem('simpleCompleteDialogHaveBeenShow', true)
+  if (getToken()) {
+    showSimplePage.value = simple.value && JSON.parse(simple.value) ? true : false
+  }
 })
 
 const handleSearch = (val) => {
   if (val) router.push(`/recruit/personal/position?content=${val}`)
 }
 
+const handleInfoClose = () => {
+  localStorage.setItem('simpleCompleteDialogHaveBeenShow', false)
+}
+
 // 更新用户基本信息
 const handleUpdateInfo = async () => {
+  handleInfoClose()
   await store.getUserBaseInfos(null)
 }
 </script>

+ 111 - 37
src/views/recruit/personal/position/components/conditionFilter.vue

@@ -1,48 +1,122 @@
 <template>
-  <div class="d-flex">
-    <companyIndustry positionIndexPage @inputChange="val => inputChange(ids.industryIds, val)"></companyIndustry>
-    <positionType positionIndexPage @inputChange="val => inputChange(ids.positionId, val)"></positionType>
-    <JobType positionIndexPage @inputChange="val => inputChange(ids.jobType, val)"></JobType>
-    <expType positionIndexPage @inputChange="val => inputChange(ids.expType, val)"></expType>
-    <payScope positionIndexPage @inputChange="val => inputChange(ids.payType, val)"></payScope>
-    <educationType positionIndexPage :isSingle="false" @inputChange="val => inputChange(ids.scale, val)"></educationType>
-    <scale positionIndexPage @inputChange="val => inputChange(ids.eduType, val)"></scale>
-    <financingStatus positionIndexPage @inputChange="val => inputChange(ids.financingStatus, val)"></financingStatus>
+  <div>
+    <div class="d-flex">
+      <template v-for="item in list" :key="item.key">
+        <component
+          :is="item.path"
+          :idName="item.key"
+          :title="item.title"
+          :isSingle="item.isSingle"
+          :dictName="item.dictShow"
+          :provideData="item.provideData || []"
+          :info="item"
+          @inputChange="inputChange"
+        ></component>
+      </template>
+    </div>
+    <div v-if="showSelectList?.length">
+      <div style="margin-top: 20px; border-top: 1px solid #eee;">
+        <div v-for="item in showSelectList" :key="item.key" style="margin: 4px 8px 4px 0px;">
+          <template v-if="item.checkedItems?.length">
+            <span style="color: #999;">{{ item.title }}:</span>
+            <v-btn
+              v-for="(val, index) in item.checkedItems" :key="item.key + index"
+              class="mr-3 my-1 py-0 px-2"
+              density="comfortable"
+              color="primary" variant="tonal"
+              v-bind="props"
+            >
+              {{ val.text }}
+              <v-icon class="ml-1" style="margin-top: 1px;" @click="deleteChip(item, val)">mdi-close</v-icon>
+            </v-btn>
+          </template>
+        </div>
+      </div>
+      <div style="text-align: right;">
+        <span class="clearFilterCriteria" @click="emits('reset')">{{ $t('common.clearFilterCriteria') }}</span>
+      </div>
+    </div>
   </div>
 </template>
 <script setup>
-import companyIndustry from './conditionFilter/companyIndustry.vue'
-import positionType from './conditionFilter/positionType.vue'
-import JobType from './conditionFilter/JobType.vue'
-import expType from './conditionFilter/expType.vue'
-import payScope from './conditionFilter/payScope.vue'
-import educationType from './conditionFilter/educationType.vue'
-import scale from './conditionFilter/scale.vue'
-import financingStatus from './conditionFilter/financingStatus.vue'
-import { ref } from 'vue'
+import { useRoute } from 'vue-router'; const route = useRoute()
+import { watch, ref, shallowRef } from 'vue'
+import { filterList, getItemObj } from './dict'
 defineOptions({name: 'retrieval-components-conditionFilter'})
-const emits = defineEmits(['change'])
-const ids = ref({
-  industryIds: 'industryIds',
-  positionId: 'positionId',
-  jobType: 'jobType',
-  expType: 'expType',
-  payType: 'payType',
-  eduType: 'eduType',
-  scale: 'scale',
-  financingStatus: 'financingStatus',
+const emits = defineEmits(['change', 'reset'])
+const props = defineProps({
+  showFilterList: { // 职位检索
+    type: [Array, String],
+    default: ''
+  },
 })
+const list = shallowRef(props.showFilterList === 'all' ? filterList : props.showFilterList?.length? props.showFilterList.map(e => {
+  const item = filterList.find(i => i.key === e.key)
+  return item ? { ...item, ...e } : ''
+}).filter(Boolean) : [])
 
-const inputChange = (key, arr) => {
-  const str = arr.length ? arr.join('_') : ''
+const inputChange = ({ idName: key, values }) => {
+  const str = values.length ? values.join('_') : ''
+  if (!key) return
   emits('change', key, str)
 }
 
-// const clearFun = () => {
-//   Object.keys(ids).forEach(key => emits('change', key, ''))
-// }
+const deleteChip = (item, val) => { // 删除某个标签-更新路由 val结构:{ text:, value: }
+  const ids = item?.checkedItems?.reduce((newArr, e) => {
+    if (e.value !== val.value) newArr.push(e.value)
+    return newArr
+  }, []) || []
+  inputChange({ idName: item.key, values: ids })
+}
 
-defineExpose({
-  ids
-})
-</script>
+const showSelectList = ref([])
+// 添加
+const assembleList = ({ key, idsStr }) => {
+  const ids = idsStr.split('_') || []
+  const obj = getItemObj({ key, ids })
+  if (!obj) return
+  const index = showSelectList.value.findIndex(i => i.key === key)
+  if (index === -1) showSelectList.value.push(obj)
+  else showSelectList.value[index] = obj
+}
+
+watch(
+  () => route.query, 
+  (newVal = {}, oldVal = {}) => {
+    // console.log('oldVal', oldVal); console.log('newVal', newVal)
+    // 回显已选筛选-标签
+    if (!Object.keys(newVal).length) { // 路由没有参数
+      showSelectList.value = []
+    }
+    else if (!Object.keys(oldVal).length && Object.keys(newVal).length) { // 只有新加参数
+      Object.keys(newVal).forEach(key => {
+        assembleList({ key, idsStr: newVal[key] })
+      })
+    }
+    else if (Object.keys(newVal).length && Object.keys(oldVal).length) { //路由参数更新
+      Object.keys(newVal).forEach(key => {
+        if (newVal[key] === oldVal[key]) return
+        assembleList({ key, idsStr: newVal[key] })
+      })
+      // showSelectList去掉newVal里面没有的key
+      showSelectList.value = showSelectList.value.filter(item => Object.keys(newVal).includes(item.key))
+    }
+  },
+  { immediate: true },
+  { deep: true }
+)
+</script>
+
+<style lang="scss" scoped>
+.clearFilterCriteria {
+  cursor: pointer;
+  line-height: 28px;
+  margin-right: 12px;
+  font-size: 14px;
+  margin-top: 4px;
+  color: var(--color-999);
+  &:hover {
+    color: var(--v-primary-base);
+  }
+}
+</style>

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

@@ -1,65 +0,0 @@
-<template>
-  <commonStyle :btnTitle="title" :close-on-content-click="false" v-if="show">
-    <v-list>
-      <v-list-item
-        v-for="item in items" :key="item.id" :value="item.value"
-        :active="selectedItems.includes(item.value)"
-        color="primary"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-
-defineOptions({name: 'conditionFilter-JobType'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('求职类型')
-let show = ref(false)
-let items = ref()
-const selectedItems = ref([])
-
-getDict('menduner_job_type').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  // 刷新回显
-  if (query && query.jobType) {
-    const str = query.jobType.split(',')[0]
-    const arr = str.split('_')
-    if (arr?.length) {
-      selectedItems.value = arr
-      title.value = selectedItems.value.length ? `求职类型(${selectedItems.value.length})` : '求职类型'
-      if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-    }
-  }
-  show.value = true
-})
-const handle = (val) => {
-  if (selectedItems.value.includes(val)) {
-    selectedItems.value = selectedItems.value.filter(i => i !== val)
-  } else {
-    selectedItems.value.push(val)
-  }
-  title.value = selectedItems.value.length ? `求职类型(${selectedItems.value.length})` : '求职类型'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-<style lang="scss" scoped>
-</style>

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

@@ -1,62 +0,0 @@
-<template>
-  <commonStyle :btnTitle="title" v-if="show">
-    <v-list :items="items">
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.id)"
-        v-for="item in items" :key="item.id" :value="item.id"
-        @click="handle(item)"
-      > 
-        <template v-if="selectedItems.includes(item.id)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-
-defineOptions({name: 'conditionFilter-area-type'})
-const emits = defineEmits(['inputChange'])
-const props = defineProps({
-  list: Array
-})
-
-const show = ref(false)
-const query = inject('routeQuery')
-const title = ref('工作地点')
-let items = ref()
-let selectedItems = ref([])
-getDict('menduner_area_type', {}, 'areaList').then(({ data }) => {
-  data = data?.length && data || []
-  const arr = props.list.map(e => {
-    const obj = data.find(k => k.id === e.key)
-    if (!obj) return
-    const { id, parentId, type, name: label } = obj
-    return { id, label, number: e.value, parentId, type }
-  }).filter(Boolean)
-  items.value = [{ id: -1, label: '全部' }, ...arr]
-  show.value = true
-})
-
-if (query && query?.areaIds) {
-    title.value = '工作地点(1)'
-    selectedItems.value = [query.areaIds]
-    emits('inputChange', { values: selectedItems.value })
-  }
-
-const handle = (val) => {
-  const obj = selectedItems.value.includes(val.id)
-  title.value = obj ? '工作地点' : (val.id === -1 ? '工作地点' : '工作地点(1)')
-  selectedItems.value = obj ? [] : [val.id]
-  emits('inputChange', { values: selectedItems.value })
-}
-</script>
-
-<style lang="scss" scoped>
-</style>

+ 118 - 0
src/views/recruit/personal/position/components/conditionFilter/commonPath.vue

@@ -0,0 +1,118 @@
+<template>
+  <commonStyle :btnTitle="btnTitle" :close-on-content-click="props.isSingle" v-if="show">
+    <!-- 行业类型 -->
+    <industryTypeCard v-if="idName === 'industryIds'" :select="selectedItems" @handleClickIndustry="handle"></industryTypeCard>
+    <!-- 职位类型 -->
+    <jobTypeCard v-else-if="idName === 'positionId'" :select="selectedItems" isSingle echo clearable @handleJobClick="handle"></jobTypeCard>
+    <v-list v-else>
+      <v-list-item
+        v-for="item in items" :key="item.id" :value="item.value"
+        :active="selectedItems.includes(item.value)"
+        color="primary"
+        @click="handle(item.value)"
+      >
+        <template v-if="selectedItems.includes(item.value)" v-slot:append>
+          <v-icon icon="mdi-check"></v-icon>
+        </template>
+        <v-list-item-title>{{ item.label }}</v-list-item-title>
+      </v-list-item>
+    </v-list>
+  </commonStyle>
+</template>
+<script setup>
+import commonStyle from './commonStyle.vue'
+import industryTypeCard from '@/components/industryTypeCard'
+import jobTypeCard from '@/components/jobTypeCard'
+import { getDict } from '@/hooks/web/useDictionaries'
+import { ref, computed, watch } from 'vue';
+
+defineOptions({name: 'conditionFilter-JobType'})
+const emits = defineEmits(['inputChange'])
+// const query = inject('routeQuery')
+const props = defineProps({
+  isRefreshEmit: { // 刷新是否触发inputChange
+    type: Boolean,
+    default: false
+  },
+  isSingle: { // 是否单选
+    type: Boolean,
+    default: false
+  },
+  idName: {
+    type: String,
+    default: ''
+  },
+  dictName: {
+    type: [String, Number],
+    default: ''
+  },
+  provideData: {
+    type: Array,
+    default: () => []
+  },
+  title: {
+    type: String,
+    default: '类型名称'
+  },
+})
+
+const btnTitle = computed(() => {
+  return selectedItems.value?.length ? `${props.title}(${selectedItems.value.length})` : props.title
+})
+
+let show = ref(false)
+let items = ref()
+const selectedItems = ref([])
+
+const handle = (value) => {
+  if (props.dictName === 1) { // 插槽使用会返回数组
+    selectedItems.value = value
+  } else {
+    if (selectedItems.value.includes(value)) {
+      selectedItems.value = selectedItems.value.filter(i => i !== value)
+    } else {
+      if (props.idName === 'expType') selectedItems.value = value === '2' ? [value] : (selectedItems.value.push(value) && selectedItems.value.filter(i => i !== '2')) // 选中经验不限时清空其它选中项,选中其他的咬去掉经验不限
+      else if (props.isSingle) selectedItems.value = [value] // 单选
+      else selectedItems.value.push(value)
+    }
+  }
+  emits('inputChange', {
+    idName: props.idName,
+    // title: props.title,
+    values: selectedItems.value,
+    isEmit: props.positionIndexPage
+  })
+}
+
+// 字典
+if (props.dictName === 1) show.value = true // 插槽使用
+else if (props.provideData?.length) { // 自定义下拉数据
+  items.value = props.provideData
+  show.value = true
+}
+else if (props.dictName) {
+  getDict(props.dictName).then(({ data }) => {
+    data = data?.length && data || []
+    items.value = data
+    show.value = true
+  })
+} else console.log('error->字典参数未传递!!')
+
+import { useRoute } from 'vue-router'; const route = useRoute()
+watch(
+  () => route.query, 
+  (newVal, oldVal) => {
+    if (!newVal) selectedItems.value = []
+    const str = newVal[props.idName]?.split(',')[0]
+    const arr = str ? str.split('_') : []
+    selectedItems.value = arr?.length? arr : []
+    if (!oldVal) { // 仅刷新时触发
+      if (props.isRefreshEmit) emits('inputChange', { values: selectedItems.value, isEmit: true })
+    }
+  },
+  { immediate: true },
+  { deep: true }
+)
+</script>
+<style lang="scss" scoped>
+</style>

+ 0 - 42
src/views/recruit/personal/position/components/conditionFilter/companyIndustry.vue

@@ -1,42 +0,0 @@
-<template>
-  <commonStyle :btnTitle="title" :close-on-content-click="false">
-    <industryTypeCard :select="selectedItems" @handleClickIndustry="handle"></industryTypeCard>
-  </commonStyle>
-</template>
-
-<script setup>
-import commonStyle from './commonStyle.vue'
-import industryTypeCard from '@/components/industryTypeCard'
-import { inject, ref } from 'vue'
-defineOptions({name: 'conditionFilter-company-industry'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('行业类型')
-const selectedItems = ref([])
-
-if (query && query.industryIds) {
-  const str = query.industryIds.split(',')[0]
-  const arr = str.split('_')
-  if (arr?.length) {
-    selectedItems.value = arr
-    title.value = selectedItems.value.length ? `行业类型(${selectedItems.value.length})` : '行业类型'
-  }
-}
-
-const handle = (arr) => {
-  selectedItems.value = arr
-  title.value = selectedItems.value.length ? `行业类型(${selectedItems.value.length})` : '行业类型'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-
-<style lang="scss" scoped>
-</style>

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

@@ -1,73 +0,0 @@
-<template>
-  <commonStyle v-if="show" :btnTitle="title" :closeOnContentClick="props.isSingle">
-    <v-list>
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.value)"
-        v-for="item in items" :key="item.id" :value="item.value"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-defineOptions({name: 'conditionFilter-educationType'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-
-const props = defineProps({
-  isSingle: {
-    type: Boolean,
-    default: false
-  },
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('学历要求')
-const show = ref(false)
-let items = ref()
-const selectedItems = ref([])
-
-getDict('menduner_education_type').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  if (query && query.eduType) {
-    const str = query.eduType.split(',')[0]
-    const arr = str.split('_')
-    if (arr?.length) {
-      selectedItems.value = arr
-      title.value = selectedItems.value.length ? `学历要求(${selectedItems.value.length})` : '学历要求'
-      if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-    }
-  }
-  show.value = true
-})
-const handle = (val) => {
-  const obj = selectedItems.value.find(e => e === val)
-  if (props.isSingle) {
-    // 单选
-    selectedItems.value = obj ? [] : [val]
-  } else {
-    // 多选 
-    if (obj) {
-      selectedItems.value = selectedItems.value.filter(i => i !== val)
-    } else selectedItems.value.push(val)
-  }
-  title.value = selectedItems.value.length ? `学历要求(${selectedItems.value.length})` : '学历要求'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-<style lang="scss" scoped>
-</style>

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

@@ -1,80 +0,0 @@
-<template>
-  <commonStyle v-if="show" :btnTitle="title" :closeOnContentClick="props.isSingle">
-    <v-list>
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.value)"
-        v-for="item in items" :key="item.id" :value="item.value"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-
-defineOptions({name: 'conditionFilter-expType'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  isSingle: {
-    type: Boolean,
-    default: false
-  },
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-const title = ref('工作经验')
-const show = ref(false)
-let items = ref()
-const selectedItems = ref([])
-
-getDict('menduner_exp_type').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  if (query && query.expType) {
-    const str = query.expType.split(',')[0]
-    const arr = str.split('_')
-    if (arr?.length) {
-      selectedItems.value = arr
-      title.value = selectedItems.value.length ? `工作经验(${selectedItems.value.length})` : '工作经验'
-      if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-    }
-  }
-  show.value = true
-})
-const handle = (val) => {
-  const obj = selectedItems.value.find(e => e === val)
-  if (props.isSingle) {
-    // 单选
-    selectedItems.value = obj ? [] : [val]
-  } else {
-    // 多选 
-    if (obj) {
-      // 已存在的再次选中就取消掉
-      selectedItems.value = selectedItems.value.filter(i => i !== val)
-    } else {
-      // 不存在
-      if (val === '2') selectedItems.value = [val] // 选中经验不限时清空其它选中项
-      else selectedItems.value.push(val)
-      // 当经验不限已存在时还选中其它项,把经验不限给清掉
-      if (val !== '2' && selectedItems.value.find(k => k === '2')) selectedItems.value = selectedItems.value.filter(i => i !== '2')
-    }
-  }
-  title.value = selectedItems.value.length ? `工作经验(${selectedItems.value.length})` : '工作经验'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-
-<style lang="scss" scoped>
-</style>

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

@@ -1,63 +0,0 @@
-<template>
-  <commonStyle v-if="show" :btnTitle="title" :close-on-content-click="false">
-    <v-list>
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.value)"
-        v-for="item in items" :key="item.id" :value="item.value"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-defineOptions({name: 'conditionFilter-financingStatus'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('融资阶段')
-let show = ref(false)
-let items = ref()
-const selectedItems = ref([])
-
-getDict('menduner_financing_status').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  if (query && query.financingStatus	) {
-    const str = query.financingStatus	.split(',')[0]
-    const arr = str.split('_')
-    if (arr?.length) {
-      selectedItems.value = arr
-      title.value = selectedItems.value.length ? `融资阶段(${selectedItems.value.length})` : '融资阶段'
-      if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-    }
-  }
-  show.value = true
-})
-const handle = (val) => {
-  if (selectedItems.value.includes(val)) {
-    selectedItems.value = selectedItems.value.filter(i => i !== val)
-  } else {
-    selectedItems.value.push(val)
-  }
-  title.value = selectedItems.value.length ? `融资阶段(${selectedItems.value.length})` : '融资阶段'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-<style lang="scss" scoped>
-</style>

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

@@ -1,59 +0,0 @@
-<template>
-  <commonStyle v-if="show" :btnTitle="title" :close-on-content-click="true">
-    <v-list>
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.value)"
-        v-for="item in items" :key="item.id" :value="item.value"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-defineOptions({name: 'conditionFilter-payScope'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('薪资待遇')
-const show = ref(false)
-let items = ref()
-let selectedItems = ref([])
-
-getDict('menduner_pay_scope').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  if (query && query.payType) {
-    title.value = '薪资待遇(1)'
-    selectedItems.value = [query.payType]
-    if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-  }
-  show.value = true
-})
-const handle = (val) => {
-  if (selectedItems.value.includes(val)) {
-    selectedItems.value = selectedItems.value.filter(i => i !== val)
-  } else {
-    selectedItems.value = [val]
-  }
-  title.value = selectedItems.value.length ? `薪资待遇(${selectedItems.value.length})` : '薪资待遇'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-<style lang="scss" scoped>
-</style>

+ 0 - 42
src/views/recruit/personal/position/components/conditionFilter/positionType.vue

@@ -1,42 +0,0 @@
-<template>
-  <commonStyle :btnTitle="title" :close-on-content-click="true">
-    <!-- 后端需要单选 -->
-    <jobTypeCard :select="selectedItems" isSingle echo clearable @handleJobClick="handle"></jobTypeCard>
-  </commonStyle>
-</template>
-
-<script setup>
-import commonStyle from './commonStyle.vue'
-import jobTypeCard from '@/components/jobTypeCard'
-import { inject, ref } from 'vue'
-defineOptions({name: 'conditionFilter-company-industry'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('职位类型')
-const selectedItems = ref([])
-
-if (query && query.positionId) {
-  const str = query.positionId.split(',')[0]
-  const arr = str.split('_')
-  if (arr?.length) {
-    selectedItems.value = arr
-    title.value = selectedItems.value.length ? `职位类型(${selectedItems.value.length})` : '职位类型'
-  }
-}
-const handle = (arr) => {
-  selectedItems.value = arr
-  title.value = selectedItems.value.length ? `职位类型(${selectedItems.value.length})` : '职位类型'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: arr.length ? arr[0] : '', isEmit: true })
-}
-</script>
-
-<style lang="scss" scoped>
-</style>

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

@@ -1,64 +0,0 @@
-<template>
-  <commonStyle v-if="show" :btnTitle="title" :closeOnContentClick="false">
-    <v-list>
-      <v-list-item
-        color="primary"
-        :active="selectedItems.includes(item.value)"
-        v-for="item in items" :key="item.id" :value="item.value"
-        @click="handle(item.value)"
-      >
-        <template v-if="selectedItems.includes(item.value)" v-slot:append>
-          <v-icon icon="mdi-check"></v-icon>
-        </template>
-        <v-list-item-title>{{ item.label }}</v-list-item-title>
-      </v-list-item>
-    </v-list>
-  </commonStyle>
-</template>
-
-<script setup>
-import commonStyle from './commonStyle.vue'
-import { getDict } from '@/hooks/web/useDictionaries'
-import { ref, inject } from 'vue';
-defineOptions({name: 'conditionFilter-scale'})
-const emits = defineEmits(['inputChange'])
-const query = inject('routeQuery')
-const props = defineProps({
-  positionIndexPage: { // 职位检索
-    type: Boolean,
-    default: false
-  }
-})
-
-const title = ref('公司规模')
-let show = ref(false)
-let items = ref()
-const selectedItems = ref([])
-
-getDict('menduner_scale').then(({ data }) => {
-  data = data?.length && data || []
-  items.value = data
-  if (query && query.scale) {
-    const str = query.scale.split(',')[0]
-    const arr = str.split('_')
-    if (arr?.length) {
-      selectedItems.value = arr
-      title.value = selectedItems.value.length ? `公司规模(${selectedItems.value.length})` : '公司规模'
-      if (!props.positionIndexPage) emits('inputChange', { values: selectedItems.value, isEmit: true })
-    }
-  }
-  show.value = true
-})
-const handle = (val) => {
-  if (selectedItems.value.includes(val)) {
-    selectedItems.value = selectedItems.value.filter(i => i !== val)
-  } else {
-    selectedItems.value.push(val)
-  }
-  title.value = selectedItems.value.length ? `公司规模(${selectedItems.value.length})` : '公司规模'
-  if (props.positionIndexPage) emits('inputChange', selectedItems.value)
-  else emits('inputChange', { values: selectedItems.value, isEmit: true })
-}
-</script>
-<style lang="scss" scoped>
-</style>

+ 123 - 0
src/views/recruit/personal/position/components/dict.js

@@ -0,0 +1,123 @@
+import { getDict } from '@/hooks/web/useDictionaries'
+import commonPath from './conditionFilter/commonPath.vue'
+// import areaType from './conditionFilter/areaType.vue'
+
+// dictUse: 查数据回显(一维数组字典),dictShow: 用户操作的字典(用户看到的数据)
+// 当type是tree类型的数据的时候需要提供dictType
+const dictList = [
+  { 
+    dictShow: 'menduner_area_type',
+    apiType: 'areaList',
+    key: 'areaIds',
+    itemKey: 'id',
+    itemText: 'name',
+    title: '工作地点',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictUse: 'menduner_industry_type',
+    apiType: 'industryList',
+    dictShow: 1,
+    key: 'industryIds',
+    itemKey: 'id',
+    itemText: 'nameCn',
+    title: '行业类型',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictUse: 'positionData',
+    apiType: 'positionData',
+    dictShow: 1,
+    key: 'positionId',
+    itemKey: 'id',
+    itemText: 'nameCn',
+    title: '职位类型',
+    isSingle: true,
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_job_type',
+    key: 'jobType',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '求职类型',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_exp_type',
+    key: 'expType',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '工作经验',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_pay_scope',
+    key: 'payScope',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '薪资待遇',
+    isSingle: true,
+    isString: true,
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_education_type',
+    key: 'eduType',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '学历要求',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_scale',
+    key: 'scale',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '公司规模',
+    path: commonPath,
+    data: []
+  },
+  { 
+    dictShow: 'menduner_financing_status',
+    key: 'financingStatus',
+    itemKey: 'value',
+    itemText: 'label',
+    title: '融资阶段',
+    path: commonPath,
+    data: []
+  },
+]
+export const filterList = dictList
+
+// 字典
+const getDictList = async () => {
+  dictList.forEach(async (dictListItem) => {
+    const dictUse = dictListItem.dictUse || dictListItem.dictShow
+    const { data } = await getDict(dictUse, dictListItem.params, dictListItem.apiType)
+    dictListItem.data = data
+  })
+}
+
+const getData = async () => {
+  await getDictList()
+}
+getData()
+
+export const getItemObj = ({ key, ids = [] }) => {
+  const item = dictList.find(dictListItem => dictListItem.key === key)
+  const checkedItems = ids.map(id => {
+    if (!item?.data?.length) return ''
+    const obj = item.data.find(e => e[item.itemKey] === id)
+    return obj ? { text: obj[item.itemText], value: obj[item.itemKey] } : ''
+  }).filter(Boolean)
+
+  return checkedItems?.length ? { key, title: item.title, checkedItems, ref: item.ref } : ''
+}

+ 30 - 37
src/views/recruit/personal/position/index.vue

@@ -2,7 +2,7 @@
 <template>
   <div class="default-width">
     <div class="py-3" style="z-index: 998; background-color: #fff">
-      <div class="stickyBox">
+      <div class="stickyBox mb-5">
         <headSearch
           tipsText="职位/公司关键字搜索"
           v-model="headSearchText"
@@ -10,9 +10,8 @@
         ></headSearch>
       </div>
       <cityFilter class="mx-5 mb-3" ref="cityFilterRef" @change="handleQueryChange"></cityFilter>
-      <div v-if="showConditionFilter" class="d-flex justify-space-between mx-5 mb-3">
-        <conditionFilter ref="conditionFilterRef" @change="handleQueryChange"></conditionFilter>
-        <span class="clearFilterCriteria" @click="handleClearConditionFilter">{{ $t('common.clearFilterCriteria') }}</span>
+      <div class="d-flex justify-space-between mx-5 mb-3">
+        <conditionFilter ref="conditionFilterRef" :showFilterList="showFilterList" @reset="handleReset" @change="handleQueryChange"></conditionFilter>
       </div>
     </div>
     <div class="d-flex mt-3">
@@ -41,23 +40,30 @@ import PositionLongStrip from '@/components/PositionLongStrip/item.vue'
 import Empty from '@/components/Empty'
 import { getJobAdvertisedSearch } from '@/api/position'
 import CtPagination from '@/components/CtPagination'
-import { provide, reactive, ref } from 'vue'
+import { reactive, ref } from 'vue'
 import { dealDictObjData } from '@/utils/position'
 
 import { useRoute, useRouter } from 'vue-router'
 defineOptions({name: 'retrieval-position-page'})
 const route = useRoute(); const router = useRouter()
-const cityFilterRef = ref(); const conditionFilterRef = ref()
+const cityFilterRef = ref()
+const conditionFilterRef = ref()
+const showFilterList = [
+  { key: 'industryIds' },
+  { key: 'positionId', isSingle: true },
+  { key: 'jobType' },
+  { key: 'expType' },
+  { key: 'payScope' },
+  { key: 'eduType' },
+  { key: 'scale' },
+  { key: 'financingStatus' },
+]
 
-const showConditionFilter = ref(true)
 const pageInfo = { pageNo: 1, pageSize: 20}
 const items = ref([])
 const total = ref(0)
 let routeQuery = (route?.query && route.query && Object.keys(route?.query).length) ? reactive(route.query) : reactive({})
-// if (routeQuery && Object.keys(routeQuery).length) {
-//   if ()
-// }
-provide('routeQuery', routeQuery)
+// provide('routeQuery', routeQuery)
 
 const headSearchText = ref(routeQuery?.content || '')
 
@@ -66,7 +72,7 @@ const getData = async () => {
   const pageReqVO = { ...pageInfo }
   // route.query参数
   if (routeQuery && Object.keys(routeQuery).length) {
-    const passingStrings = ['content'] // 传递字符串
+    const passingStrings = ['content', 'payScope'] // 单选且传递字符串
     const passingOneId = ['positionId'] // 单选且传递整型
     Object.keys(routeQuery).forEach(key => {
       if (routeQuery[key] === '') return
@@ -96,17 +102,21 @@ const getData = async () => {
   })
   total.value = number
 }
+getData() // 不使用cityFilter情况下
 
 // 页面刷新
 if (routeQuery && Object.keys(routeQuery).length) getData() 
 
 // 参数改变后刷新路由,触发数据刷新
 const updateRouter = () => {
-  const str = Object.keys(routeQuery).length ? Object.keys(routeQuery).reduce((res, _key) => {
-    if (routeQuery[_key] !== '') res += `${res ? '&' : ''}${_key}=${routeQuery[_key]}`
-    return res
-  }, '') : ''
-  router.push(`${route.path}?${str}`)
+  let query = {}
+  if (Object.keys(routeQuery).length) {
+    query = Object.keys(routeQuery).reduce((obj, key) => {
+      if (routeQuery[key] !== '') obj[key] = routeQuery[key]
+        return obj
+    }, {})
+  }
+  router.push({ path: route.path, query })
   pageInfo.pageNo = 1
   getData()
 }
@@ -118,16 +128,9 @@ const handleQueryChange = (key, val) => { // val为字符串,数组的话用_下
 }
 
 // 清空筛选条件
-const handleClearConditionFilter = async () => {
-  if (conditionFilterRef.value?.ids) {
-    showConditionFilter.value = false
-    const ids = conditionFilterRef.value.ids
-    Object.keys(ids).forEach(key => {
-      if (routeQuery[key]) delete routeQuery[key]
-    })
-    await updateRouter()
-    showConditionFilter.value = true
-  }
+const handleReset = async () => {
+  routeQuery = {}
+  await updateRouter()
 }
 
 // 分页
@@ -138,14 +141,4 @@ const handleChangePage = (index) => {
 </script>
 
 <style lang="scss" scoped>
-.clearFilterCriteria {
-  cursor: pointer;
-  line-height: 28px;
-  margin-right: 12px;
-  font-size: 14px;
-  color: var(--color-999);
-  &:hover {
-    color: var(--v-primary-base);
-  }
-}
 </style>

+ 7 - 3
src/views/recruit/personal/shareJob/sendResume/simple.vue

@@ -7,7 +7,7 @@
     titleClass="text-h6"
     title="补充基本信息"
     :closeable="props.closeable"
-    @close="openDialog = props.closeable ? false : true"
+    @close="handleClose"
     @submit="simpleInfoSubmit"
   >
     <simpleInfoForm ref="formRef"></simpleInfoForm>
@@ -25,7 +25,7 @@ import { useRouter } from 'vue-router'
 import { ref } from 'vue'
 defineOptions({name: 'shareJob-sendResume-simple'})
 
-const emit = defineEmits(['simpleInfoReady'])
+const emit = defineEmits(['simpleInfoReady', 'close'])
 const props = defineProps({
   closeable: {
     type: Boolean,
@@ -42,6 +42,11 @@ const info = ref(null)
 const store = useUserStore()
 const router = useRouter()
 
+const handleClose = () => {
+  emit('close')
+  openDialog.value = props.closeable ? false : true
+}
+
 // 查询用户基本信息
 const timer = ref(null)
 
@@ -60,7 +65,6 @@ const getUserInfoVerify = () => {
     } else {
       openDialog.value = true // 不存在
       Snackbar.warning('请先完善个人基本信息')
-      localStorage.setItem('simpleCompleteDialogHaveBeenShow', true)
     }
   }
   info.value = JSON.parse(localStorage.getItem('baseInfo'))

+ 6 - 1
src/views/register/company.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="box">
-    <PhonePage v-if="!valid" :isCompany="true" @success="handleValidate"></PhonePage>
+    <PhonePage v-if="!valid" :isCompany="true" @success="handleValidate" :isLogin="query.login ? true : false"></PhonePage>
   </div>
 </template>
 
@@ -12,11 +12,16 @@ import PhonePage from './person.vue'
 import { useRouter } from 'vue-router'
 
 const router = useRouter()
+const query = router.currentRoute.value.query
 
 const valid = ref(false)
 const handleValidate = async () => {
   // 已短信登录
   valid.value = true
+  if (query.login) {
+    router.push({ path: '/recruit/entRegister' })
+    return
+  } 
   // 查看用户是否有在申请中的数据
   const data = await getUserRegisterEnterpriseApply()
   const bool = data && Object.keys(data).length // 已经有数据说明已经申请过了

+ 15 - 6
src/views/register/person.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="box">
     <div class="content pa-10">
-      <div class="content-title text-center mt-4">请输入手机号码进行注册认证</div>
-      <phoneFrom class="mt-10" ref="phoneRef" @handleEnter="handleRegister"></phoneFrom>
-      <div v-if="!isCompany" class="font-size-14 tips color-primary cursor-pointer text-end" @click="router.push('/login')">已有账号?去登录</div>
+      <div class="content-title text-center mt-4">{{ isLogin ? '请输入您申请企业账号时填入的手机号进行效验' : '请输入手机号码进行注册认证'}}</div>
+      <phoneFrom class="mt-10" ref="phoneRef" @handleEnter="handleRegister" :phone="phone"></phoneFrom>
+      <div class="font-size-14 tips color-primary cursor-pointer text-end" @click="router.push('/login')">已有账号?去登录</div>
       <v-btn :loading="loading" color="primary" class="white--text mt-5" min-width="370" @click="handleRegister">{{ isCompany ? '下一步' : '注册' }}</v-btn>
       <div class="login-tips mt-3" v-if="!isCompany">
         点击注册即代表您同意
@@ -21,12 +21,17 @@ import { useRouter } from 'vue-router'
 import phoneFrom from '@/components/VerificationCode'
 import { useUserStore } from '@/store/user'
 import Snackbar from '@/plugins/snackbar'
+import { checkEmail } from '@/utils/validate'
 
 const emit = defineEmits(['success'])
 const props = defineProps({
   isCompany: {
     type: Boolean,
     default: false
+  },
+  isLogin: {
+    type: Boolean,
+    default: false
   }
 })
 
@@ -34,6 +39,7 @@ const router = useRouter()
 const phoneRef = ref()
 const loading = ref(false)
 const userStore = useUserStore()
+const phone = localStorage.getItem('loginAccount') && !checkEmail(localStorage.getItem('loginAccount')) ? localStorage.getItem('loginAccount') : ''
 
 // 注册
 const handleRegister = async () => {
@@ -41,10 +47,13 @@ const handleRegister = async () => {
   if (!valid) return
   loading.value = true
   try {
-    await userStore.handleSmsLogin({ ...phoneRef.value.loginData })
+    // isLogin:企业注册申请被驳回后,再次提交时需先登录个人账号
+    props.isLogin ? await userStore.handleSmsLogin({ ...phoneRef.value.loginData }) : await userStore.handleUserRegister({ ...phoneRef.value.loginData })
     Snackbar.success(props.isCompany ? '手机号验证成功' : '注册成功')
-    if (!props.isCompany) router.push({ path: '/recruitHome' })
-    else emit('success')
+    if (!props.isCompany) {
+      router.push({ path: '/recruitHome' })
+      localStorage.removeItem('loginAccount')
+    } else emit('success')
   } finally {
     loading.value = false
   }

Some files were not shown because too many files changed in this diff