Просмотр исходного кода

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

Xiao_123 6 месяцев назад
Родитель
Сommit
20728715f5

+ 7 - 7
.env.development

@@ -1,21 +1,21 @@
 NODE_ENV = 'development'
 
-# 版本号 1937
+# 版本号 1032
 VITE_VERSION = 'v24.11.14.1032'
 
 VITE_APP_TITLE = 门墩儿
 
 # 访问路径
-# VITE_ACCESS_BASE_URL = 'http://menduner.citupro.com:7878' # 发布测试环境
-VITE_ACCESS_BASE_URL = 'https://www.menduner.com' # 发布生产环境
+VITE_ACCESS_BASE_URL = 'http://menduner.citupro.com:7878' # 发布测试环境
+# VITE_ACCESS_BASE_URL = 'https://www.menduner.com' # 发布生产环境
 # 
 # 请求路径
-# VITE_BASE_URL = 'http://menduner.citupro.com:7878' # 发布测试环境
-VITE_BASE_URL = 'https://www.menduner.com' # 发布生产环境
+VITE_BASE_URL = 'http://menduner.citupro.com:7878' # 发布测试环境
+# VITE_BASE_URL = 'https://www.menduner.com' # 发布生产环境
 
 # 预览路径
-# VITE_PREVIEW_URL = 'http://192.168.3.91:8012' # 发布测试环境
-VITE_PREVIEW_URL = 'https://kkfileview.menduner.com/' # 发布生产环境
+VITE_PREVIEW_URL = 'http://192.168.3.91:8012' # 发布测试环境
+# VITE_PREVIEW_URL = 'https://kkfileview.menduner.com/' # 发布生产环境
 
 # 租户id
 VITE_TENANTCODE = '155'

+ 16 - 12
src/App.vue

@@ -4,9 +4,8 @@ import { ref, onMounted, onUnmounted, nextTick } from 'vue'
 import Confirm from '@/plugins/confirm'
 import axios from 'axios'
 
-const openCheckVersion = true // 开启检测版本
 const timer = ref(null)
-const setIntervalTime = 3000 // 300000 五分钟
+const setIntervalTime = 3000 // 接口调用间隔时间
 
 function open () {
   if (timer.value) clearInterval(timer.value)
@@ -14,9 +13,9 @@ function open () {
 }
 onMounted(() => {
   nextTick(() => {
-    console.log('baseurl:', import.meta.env?.VITE_BASE_URL, 'version:', import.meta.env?.VITE_VERSION, process?.env?.NODE_ENV) // 打印
+    console.log('baseurl:', import.meta.env?.VITE_BASE_URL, 'version:', import.meta.env?.VITE_VERSION) // 打印
     const process_ENV = process?.env?.NODE_ENV || ''
-    if ((process_ENV === 'production' || process_ENV === 'development') && openCheckVersion) {
+    if (process_ENV === 'production' || process_ENV === 'development') {
       open()
     }
   })
@@ -29,25 +28,30 @@ let ConfirmDone = false
 // 检查版本号
 const checkVersion = () => {
   const baseUrl = import.meta.env.VITE_BASE_URL || ''
-  const version = import.meta.env?.VITE_VERSION || ''
+  const env_v = import.meta.env?.VITE_VERSION || ''
   const tenantId = import.meta.env?.VITE_TENANTCODE || ''
+  const get_v = localStorage.getItem('RES_VERSION') || ''
   // 
-  if (!baseUrl || !version || !tenantId) return
+  if (!baseUrl || !env_v || !tenantId) return
   axios.get(`${baseUrl}/app-api/menduner/system/get/version`, {
     headers: { ['tenant-id']: tenantId },
     cache: 'no-store' // 禁用缓存
   }).then((res) => {
-    // 接口报错和版本一致不弹Confirm
-    if (!res?.data?.data || res.data.data === version) {
+    const res_v = res?.data?.data || ''
+    if (!res_v || res_v === env_v ) { // 接口报错和版本一致不弹Confirm
       return
     }
     if (ConfirmDone) {
       return
     }
-    ConfirmDone = true
-    // Confirm('系统提示', '发现新版本,将立即刷新页面', { hideCancelBtn: true }).then(() => {
-    //   window.location.reload()
-    // })
+    if (res_v === get_v) { // 刷新过的不再刷新,避免刷新不成功但一直刷新
+      return
+    }
+    ConfirmDone = true  // 后续不弹Confirm
+    Confirm('系统提示', '发现新版本,将立即刷新页面', { hideCancelBtn: true }).then(() => {
+      localStorage.setItem('RES_VERSION', res_v)
+      window.location.reload()
+    })
   }).catch(err => {
     console.log('checkVersion-err', err)
   })

+ 8 - 0
src/components/Enterprise/components/positions.vue

@@ -92,6 +92,8 @@ import conditionFilter from '@/views/recruit/personal/position/components/condit
 import loginPage from '@/views/common/loginDialog.vue'
 import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 const props = defineProps({
   info: {
@@ -259,6 +261,12 @@ const toDetails = async (info) => {
     nextFunc.value = toDetails // 登录成功后要执行的操作 (toDetails执行不成功,原因未找到)
     return
   }
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      toDetails(toDetailsInfo)
+    })
+    return
+  }
   const userId = info.contact.userId
   const enterpriseId = info.contact.enterpriseId
   const textObj = {

+ 3 - 0
src/components/Enterprise/details.vue

@@ -68,6 +68,8 @@
 
     <!-- 快速登录 -->
     <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
+    <!-- 完善个人信息 -->
+    <!-- <fillPage v-if="showFill" @success="fillSuccess"></fillPage> -->
   </div>
 </template>
 
@@ -84,6 +86,7 @@ import { useRoute, useRouter } from 'vue-router'
 import { getToken } from '@/utils/auth'
 import Snackbar from '@/plugins/snackbar'
 import loginPage from '@/views/common/loginDialog.vue'
+// import fillPage from '@/views/common/fill/dialog.vue'
 
 const props = defineProps({
   id: {

+ 8 - 0
src/components/Position/longStrip.vue

@@ -63,6 +63,8 @@ import { ref } from 'vue'
 import { prologue, defaultText } from '@/hooks/web/useIM'
 import loginPage from '@/views/common/loginDialog.vue'
 import { getToken } from '@/utils/auth'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 const emits = defineEmits(['refresh'])
 const { t } = useI18n()
@@ -112,6 +114,12 @@ const toDetails = async (info) => {
     nextFunc.value = toDetails // 登录成功后要执行的操作 (toDetails执行不成功,原因未找到)
     return
   }
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      toDetails(toDetailsInfo)
+    })
+    return
+  }
   const userId = info.contact.userId
   const enterpriseId = info.contact.enterpriseId
   const textObj = {

+ 1 - 0
src/config/axios/service.js

@@ -65,6 +65,7 @@ service.interceptors.request.use(
     let isToken = (config.headers || {}).isToken === false
     // token类型
     const tokenIndex = config.tokenIndex ? config.tokenIndex : getIsEnterprise() ? 1 : 2
+    console.log('令牌类型', tokenIndex === 1 ? '企业:' : '个人:', getToken(tokenIndex))
     whiteList.some((v) => {
       if (config.url) {
         config.url.indexOf(v) > -1

+ 6 - 1
src/hooks/web/useDictionaries.js

@@ -13,6 +13,7 @@ import {
 // const DICT_CITY_API = {
 //   menduner_exp_type: getDictData
 // }
+import { getSecondNodes } from '@/utils/dealData'
 
 // const setDict = (type, val, cacheTime = 7200) => {
 const setDict = (type, val) => {
@@ -25,6 +26,9 @@ const setDict = (type, val) => {
       return e
     }) : []
   }
+  if (type === 'positionSecondData') {
+    val = getSecondNodes(val)
+  }
   // 一小时过期
   const currentTime = new Date()
   currentTime.setTime(currentTime.getTime() + 3600 * 1000)
@@ -58,7 +62,8 @@ export const getDict = (type, params, apiType = 'dict') => {
         skillList: getSkillList,
         areaList: getAreaListData,
         areaMap: getAreaMapData,
-        positionData: getPositionData
+        positionData: getPositionData,
+        positionSecondData: getPositionTreeData
       }
       apiFn[apiType](query).then(data => {
         // setDict(type, data, Date.now())

+ 1 - 1
src/permission.js

@@ -27,7 +27,7 @@ router.beforeEach(async (to, from, next) => {
     // 强制修改密码
     if (localStorage.getItem('entUpdatePassword') === 'needChange') fullScreen('entUpdatePassword')
     // 强制填写个人信息
-    else if (localStorage.getItem('necessaryInfoReady') === 'no') necessaryInfo('necessaryInfoDialog')
+    else if (localStorage.getItem('necessaryInfoReady') !== 'ready' && tokenIndex === 2) necessaryInfo('necessaryInfoDialog')
     // 企业信息完成度提示
     else if (localStorage.getItem('checkEnterpriseBaseInfoFalseHref')) {
       const href = localStorage.getItem('checkEnterpriseBaseInfoFalseHref')

+ 77 - 36
src/plugins/necessaryInfo/components/infoForm.vue

@@ -6,32 +6,39 @@
 
 <script setup>
 import { getDict } from '@/hooks/web/useDictionaries'
-defineOptions({name: 'shareJob-form-baseInfo'})
+defineOptions({name: 'necessaryInfo-InfoForm'})
 import { reactive, ref } from 'vue'
 import { checkEmail } from '@/utils/validate'
+import { enterpriseSearchByName } from '@/api/recruit/personal/resume'
 
+const props = defineProps({
+  option: {
+    type: Object,
+    default: () => {}
+  }
+})
+const setInfo = ref(props.option?.setInfo ? props.option.setInfo : {})
+// console.log(1, 'setInfo', setInfo)
 const formPageRef = ref()
 let query = reactive({})
 
 // 企业名称下拉列表
-const enterpriseNameInput = ref('')
+let enterpriseName = ''
+// const enterpriseNameInput = ref('')
 const getEnterpriseData = async (name) => {
-  const item = formItems.value.options.find(e => e.key === 'enterpriseId')
+  const item = items.value.options.find(e => e.key === 'enterpriseId')
   if (!item) return
-  if (item.items?.length && (enterpriseNameInput.value === name)) return // 防抖
-  item[item.itemTextName] = enterpriseNameInput.value = name
+  if (item.items?.length && (enterpriseName === name)) return // 防抖
+  // item[item.itemTextName] = 
+  enterpriseName = name
   if (name === null || name === '') { item.items = [] }
   else {
     const data = await enterpriseSearchByName({ name })
     item.items = data
   }
 }
-const positionSearch = (name) => {
-  const item = formItems.value.options.find(e => e.key === 'positionId')
-  if (!item) return
-  item[item.itemTextName] = name
-}
 
+let positionName = ''
 const items = ref({
   options: [
     {
@@ -70,6 +77,10 @@ const items = ref({
       label: '常用邮箱',
       outlined: true,
       rules: [
+        value => {
+          if (value) return true
+          return '请输入联系邮箱'
+        },
         value => {
           if (value && !checkEmail(value)) return '请输入正确的电子邮箱'
           return true
@@ -79,13 +90,14 @@ const items = ref({
     {
       type: 'datePicker',
       mode: 'date',
-      labelWidth: 110,
+      labelWidth: 80,
       key: 'birthday',
       value: '1990-01-01',
       defaultValue: new Date(1990, 1, 1),
       label: '出生日期 *',
       disabledFutureDates: true,
       format: 'YYYY/MM/DD',
+      flexStyle: 'mb-7',
       outlined: true,
       rules: [v => !!v || '请选择出生日期']
     },
@@ -94,14 +106,14 @@ const items = ref({
       key: 'enterpriseId',
       value: null,
       default: null,
-      label: '任职企业名称(没有可填暂无 *',
+      label: '任职企业名称(可填暂无)',
       outlined: true,
       clearable: true,
       canBeInputted: true, //
       itemTextName: 'enterpriseName',
       itemText: 'value',
       itemValue: 'key',
-      rules: [v => !!v || '任职企业名称(没有可填“暂无”)'],
+      // rules: [v => !!v || '任职企业名称(可填“暂无”)'],
       search: getEnterpriseData,
       items: []
     },
@@ -110,33 +122,32 @@ const items = ref({
       key: 'positionId',
       value: null,
       default: null,
-      label: '任职职位名称(没有可填暂无 *',
+      label: '任职职位名称(可填暂无)',
       outlined: true,
       clearable: true,
       canBeInputted: true, //
       itemTextName: 'positionName',
       itemText: 'nameCn',
       itemValue: 'id',
-      rules: [v => !!v || '任职职位名称(没有可填“暂无”)'],
-      search: val => positionSearch(val),
+      dictTypeName: 'positionSecondData',
+      // rules: [v => !!v || '任职职位名称(没有可填“暂无”)'],
+      search: val => positionName = val,
+      items: []
+    },
+    {
+      type: 'autocomplete',
+      key: 'interestedPositionList',
+      value: null,
+      default: null,
+      label: '意向职位 *',
+      outlined: true,
+      itemText: 'nameCn',
+      itemValue: 'id',
+      multiple: true,
+      dictTypeName: 'positionSecondData',
+      rules: [v => !!v || '请选择意向职位'],
       items: []
     },
-    // {
-    //   type: 'autocomplete',
-    //   key: 'interestedPositionList',
-    //   value: null,
-    //   default: null,
-    //   label: '意向职位 *',
-    //   outlined: true,
-    //   clearable: true,
-    //   multiple: true,
-    //   canBeInputted: true, //
-    //   itemText: 'nameCn',
-    //   itemValue: 'id',
-    //   dictTypeName: 'positionData',
-    //   rules: [v => !!v || '意向职位'],
-    //   items: []
-    // },
     {
       type: 'autocomplete',
       key: 'jobStatus',
@@ -176,14 +187,16 @@ const items = ref({
       rules: [v => !!v || '请选择最高学历'],
       items: []
     },
+    //   label: '学制类型 *', menduner_education_system_type
   ]
 })
 
 // 获取字典内容
-const getDictData = async (dictTypeName) => {
-  const item = items.value.options.find(e => e.dictTypeName === dictTypeName)
+const getDictData = async (dictTypeName, key) => {
+  const item = items.value.options.find(e => e.key === key)
   if (item) {
-    const { data } = await getDict(dictTypeName)
+    const apiFn = dictTypeName === 'positionSecondData' ? 'positionSecondData' : null
+    const { data } = await getDict(dictTypeName, {}, apiFn)
     item.items = data
     // console.log(dictTypeName, '字典内容', data)
   }
@@ -192,12 +205,39 @@ const getDictData = async (dictTypeName) => {
 const userInfo = ref(localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo')) : {})
 const baseInfo = ref(localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')) : {})
 items.value.options.forEach((e) => {
-  if (e.dictTypeName) getDictData(e.dictTypeName) // 查字典set options
+  if (e.dictTypeName) getDictData(e.dictTypeName, e.key) // 查字典set options
   if (baseInfo.value && baseInfo.value[e.key]) e.value = baseInfo.value[e.key] // 人才信息回显
   if (userInfo.value && userInfo.value[e.key]) e.value = userInfo.value[e.key] // 人才信息回显
   if (e.key === 'sex' && e.value === '0') e.value = e.default
+  if (setInfo.value[e.key]) e.value = setInfo.value[e.key]
 })
 
+// const getName = (obj, key) => {
+//   const item = items.value.options.find(e => e.key === key)
+//   if (!item && !item.value) return
+//   const select = item.items.find(e => item.value === e[item.itemValue || 'value'])
+//   if (select) {
+//     obj[item.itemTextName] = select[item.itemText || 'label']
+//   }
+// }
+
+const dealQuery = () => {
+  query.positionName = positionName
+  if (query.positionId === positionName) delete query.positionId  // 有选中id传id和name,否者只传name
+  query.enterpriseName = enterpriseName
+  if (query.enterpriseId === enterpriseName) delete query.enterpriseId  // 有选中id传id和name,否者只传name
+  //
+  if (query.interestedPositionList?.length) {
+    query.interestedList = query.interestedPositionList.map(e => { return {positionId: e} })
+  }
+  query.workExpList = [{
+    enterpriseId: query.enterpriseId,
+    enterpriseName: query.enterpriseName,
+    positionId: query.positionId,
+    positionName: query.positionName,
+  }]
+}
+
 const getQuery = async () => {
   const { valid } = await formPageRef.value.formRef.validate()
   if (!valid) return false
@@ -207,6 +247,7 @@ const getQuery = async () => {
     obj[e.key] = e.value
   })
   query = Object.assign(query, obj)
+  dealQuery()
   return query
 }
 

+ 34 - 10
src/plugins/necessaryInfo/components/necessaryInfoDialog.vue

@@ -11,7 +11,7 @@
       @other="handleLogout"
       @submit="simpleInfoSubmit"
     >
-      <infoForm ref="formRef"></infoForm>
+      <infoForm ref="formRef" :option="option"></infoForm>
     </CtDialog>
   </v-app>
 </template>
@@ -26,27 +26,50 @@ import { useRoute } from 'vue-router'; const route = useRoute()
 import { useRouter } from 'vue-router'; const router = useRouter()
 import Confirm from '@/plugins/confirm'
 import { onMounted, ref } from 'vue'
+import { getToken } from '@/utils/auth'
+import Snackbar from '@/plugins/snackbar'
+
+const props = defineProps({
+  // title: String,
+  // text: String,
+  // cancel: Function,
+  sure: Function,
+  other: Function,
+  option: {
+    type: Object,
+    default: () => {}
+  },
+  setInfo: {
+    type: Object,
+    default: () => {}
+  }
+})
 
 const dialog = ref(false)
+// const isMobile = ref(false)
 onMounted(() => {
   dialog.value = true
 })
 
 const formRef = ref()
 const simpleInfoSubmit = async () => {
+  if (!getToken()) {
+    Confirm('系统提示', '登录失效,请重新登录', { hideCancelBtn: true }).then(() => {
+      window.location.reload()
+    })
+    return
+  }
   try {
     const obj = await formRef.value.getQuery()
     if (!obj) return
     await savePersonSimpleInfo(obj)
-    const info = localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')) : {}
-    localStorage.setItem('baseInfo', JSON.stringify({ ...info, ...obj }))
-    localStorage.setItem('necessaryInfoReady', 'ok')
-    Confirm('系统提示', '提交成功,立即刷新', { hideCancelBtn: true }).then(() => {
-      // window.location.reload()
-      location.reload()
-    })
-    // dialog.value = false
-    // emit('simpleInfoReady')
+    Snackbar.success('保存成功')
+    // const info = localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')) : {}
+    // localStorage.setItem('baseInfo', JSON.stringify({ ...info, ...obj }))
+    // localStorage.setItem('necessaryInfoReady', 'ready') //
+    await useUserStore().getUserBaseInfos() // 更新用户信息
+    dialog.value = false
+    props.sure()
   } catch (error) {
     console.error('error', error)
   }
@@ -56,6 +79,7 @@ const simpleInfoSubmit = async () => {
 const handleLogout = () => {
   Confirm('系统提示', '是否确定退出当前登录账号?').then(async () => {
     await userStore.userLogout(1)
+    props.other()
     if (!route || route.path === '/recruitHome') location.reload()
     else router.push({ path: '/recruitHome' })
   })

+ 30 - 15
src/plugins/necessaryInfo/index.js

@@ -2,21 +2,36 @@ import { createApp } from 'vue'
 import necessaryInfoDialog from './components/necessaryInfoDialog.vue'
 import vuetify from '@/plugins/vuetify'
 
-const toastMessage = (type, options)  => {
-  const componentName = type === 'necessaryInfoDialog' ? necessaryInfoDialog : null
-
-  const rootNode = document.createElement("div")
-  document.querySelector('.v-application').appendChild(rootNode)
-  const app = createApp(componentName, options)
-  app.use(vuetify)
-  app.mount(rootNode)
-  const { timeout } = options || {}
-  if ((timeout - 0)) {
-    setTimeout(() => {
-      app.unmount()
-      rootNode.remove()
-    }, (timeout-0))
-  }
+const toastMessage = (type, option = {})  => {
+  return new Promise((resolve, reject) => {
+    const componentName = type === 'necessaryInfoDialog' ? necessaryInfoDialog : null
+    const rootNode = document.createElement("div")
+      document.querySelector('.v-application').appendChild(rootNode)
+      const app = createApp(componentName, {
+        // title,
+        // text,
+        option,
+        cancel () {
+          app.unmount()
+          rootNode.remove()
+          if (option.cancelCallback) {
+            reject()
+          }
+        },
+        sure () {
+          app.unmount()
+          rootNode.remove()
+          resolve()
+        },
+        other () {
+          app.unmount()
+          rootNode.remove()
+          resolve({ otherClick: true })
+        }
+      })
+      app.use(vuetify)
+      app.mount(rootNode)
+  })
 }
 
 // 注册插件app.use()会自动执行install函数

+ 7 - 15
src/store/user.js

@@ -17,6 +17,7 @@ import Snackbar from '@/plugins/snackbar'
 import { timesTampChange } from '@/utils/date'
 import { updateEventList } from '@/utils/eventList'
 import { getBaseInfoDictOfName } from '@/utils/getText'
+import { checkPersonBaseInfo } from '@/utils/check'
 // import Confirm from '@/plugins/confirm'
 
 // import { useIMStore } from './im'
@@ -47,7 +48,7 @@ export const useUserStore = defineStore('user',
             localStorage.setItem('expiresTime', res.expiresTime) // token过期时间
             updateEventList(true) // 获取规则配置跟踪列表
             await this.getUserInfos()
-            this.getUserBaseInfos()
+            await this.getUserBaseInfos()
             resolve()
           }).catch(err => { reject(err) })
         })
@@ -64,7 +65,7 @@ export const useUserStore = defineStore('user',
             localStorage.setItem('expiresTime', res.expiresTime) // token过期时间
             updateEventList(true) // 获取规则配置跟踪列表
             await this.getUserInfos()
-            this.getUserBaseInfos()
+            await this.getUserBaseInfos()
             resolve(res)
           }).catch(err => { reject(err) })
         })
@@ -73,7 +74,7 @@ export const useUserStore = defineStore('user',
       async handlePasswordLogin(data) {
         return new Promise((resolve, reject) => {
           data.account = data.phone
-          passwordLogin(data).then(res => {
+          passwordLogin(data).then(async res => {
             if (data.isEnterprise) { // 企业邮箱登录
               localStorage.setItem('emailLoginInfo', JSON.stringify(res))
               window.location.href = '/enterpriseVerification'
@@ -85,8 +86,8 @@ export const useUserStore = defineStore('user',
               localStorage.setItem('accountInfo', JSON.stringify(res))
               localStorage.setItem('expiresTime', res.expiresTime) // token过期时间
               updateEventList(true) // 获取规则配置跟踪列表
-              this.getUserInfos()
-              this.getUserBaseInfos()
+              await this.getUserInfos()
+              await this.getUserBaseInfos()
             }
             resolve()
           }).catch(err => {
@@ -113,8 +114,8 @@ export const useUserStore = defineStore('user',
           const data = await getBaseInfo({ userId: userId || this.accountInfo.userId })
           if (!data) return localStorage.setItem('baseInfo', '{}')
           this.baseInfo = await this.getFieldText(data)
-          // this.checkPersonBaseInfo(this.baseInfo)
           localStorage.setItem('baseInfo', JSON.stringify(this.baseInfo))
+          localStorage.setItem('necessaryInfoReady', checkPersonBaseInfo(this.baseInfo) ? 'ready' : 'fddeaddc47868b4d5ca30dcda9f83cac00') // 校验是否完善人才必填信息
         } catch (error) {
           Snackbar.error(error)
         }
@@ -196,15 +197,6 @@ export const useUserStore = defineStore('user',
         return data // 方便直接获取
       },
 
-      // // 校验人才必填信息
-      // checkPersonBaseInfo (bInfo) {
-      //   let necessaryInfoReady = Boolean(bInfo && Object.keys(bInfo).length)
-      //   if (necessaryInfoReady) {
-      //     const keyArr = ['name', 'phone', 'jobStatus', 'expType', 'eduType'] // 必填人才信息
-      //     necessaryInfoReady = keyArr.every(e => bInfo[e] && bInfo[e] !== 0)
-      //   }
-      //   localStorage.setItem('necessaryInfoReady', necessaryInfoReady? 'ok':'no') // true已完成填写,false未完成填写
-      // },
       // 获取《企业基本信息》
       async checkEnterpriseBaseInfo () {
         try {

+ 18 - 0
src/utils/check.js

@@ -0,0 +1,18 @@
+// 校验是否完善人才必填信息
+export const checkPersonBaseInfo = (baseInfo) => {
+  const info = baseInfo ? baseInfo : localStorage.getItem('baseInfo') ? JSON.parse(localStorage.getItem('baseInfo')) : {}
+  if (!info || !Object.keys(info).length) return false
+  const keyArr = [ // 必填项目
+    'name',
+    'sex',
+    'phone',
+    'email',
+    'birthday',
+    'jobStatus',
+    'expType',
+    'eduType'
+  ]
+  const necessaryInfoReady = keyArr.every(e => info[e] && info[e] !== 0)
+  return necessaryInfoReady
+  // return true // return true关闭弹窗
+}

+ 28 - 0
src/utils/dealData.js

@@ -0,0 +1,28 @@
+// 获取所有的叶子节点
+export const  getLeafNodes = (tree) => {
+  const leafNodes = []
+  function traverse(node) {
+    if (!node.children || node.children.length === 0) {
+      leafNodes.push(node)
+    } else {
+      for (let child of node.children) {
+        traverse(child)
+      }
+    }
+  }
+  // 开始遍历
+  if (!tree?.length) return []
+  for (let rootNode of tree) {
+    traverse(rootNode)
+  }
+  return leafNodes
+}
+
+// 获取所有二级节点
+export const  getSecondNodes = (tree) => {
+  let nodes = []
+  for (const rootNode of tree) {
+    if (rootNode.children?.length) nodes = [...nodes, ...rootNode.children]
+  }
+  return nodes
+}

+ 8 - 2
src/views/common/loginDialog.vue

@@ -59,6 +59,8 @@ import { useUserStore } from '@/store/user'; const userStore = useUserStore()
 import { nextTick, ref } from 'vue'
 import Verify from '@/components/Verifition'
 import Snackbar from '@/plugins/snackbar'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 const emit = defineEmits(['loginSuccess', 'close'])
 
@@ -102,8 +104,12 @@ const handleLogin = async () => {
   }
   try {
     await userStore[api](params)
-    emit('loginSuccess')
-    // if (localStorage.getItem('necessaryInfoReady') === 'ok') emit('loginSuccess')
+    if (checkPersonBaseInfo()) emit('loginSuccess')
+    else {
+      necessaryInfo('necessaryInfoDialog').then(() => {  // 强制填写个人信息
+        emit('loginSuccess')
+      })
+    }
   } catch (error) {
     captchaStr.value = '' // 清空人机验证
     phoneRef.value && phoneRef.value.clearCaptcha() // 清空人机验证

+ 8 - 0
src/views/mall/exchange.vue

@@ -36,6 +36,8 @@ import Snackbar from '@/plugins/snackbar'
 import { redeemSubmit } from '@/api/mall'
 import { useUserStore } from '@/store/user'
 import { getDict } from '@/hooks/web/useDictionaries'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 const emit = defineEmits(['login', 'toTaskCenter'])
 defineProps({
@@ -111,6 +113,12 @@ const handleShowDetail = (item) =>{
     emit('login')
     return
   }
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      handleShowDetail()
+    })
+    return
+  }
   detailItem.value = item
   formItems.value.options.forEach(e => {
     if (e.key !== 'contactPhone') e.hide = item.type ? false : true

+ 63 - 45
src/views/recruit/enterprise/systemManagement/groupAccount/inviteConfirm.vue

@@ -34,7 +34,7 @@
     </div>
   </div>
   <!-- 快速填写简易人才信息 -->
-  <CtDialog
+  <!-- <CtDialog
     :visible="showSimpleInput"
     :widthType="2"
     titleClass="text-h6"
@@ -42,22 +42,25 @@
     @close="showSimpleInput = false"
     @submit="simpleInfoSubmit"
   >
-    <simplePageForm ref="formRef"></simplePageForm>
-  </CtDialog>
+    <infoForm ref="formRef"></infoForm>
+  </CtDialog> -->
 </template>
 
 <script setup>
 defineOptions({ name: 'inviteConfirm'})
 import { ref, onMounted } from 'vue'
 import phoneFrom from '@/components/VerificationCode'
-import simplePageForm from './components/simplePageForm.vue'
 import { useRoute } from 'vue-router'; const route = useRoute()
 import { enterpriseInviteRecordConsent, getEnterpriseInfoByCode } from '@/api/recruit/enterprise/enterpriseInvite.js'
 import Snackbar from '@/plugins/snackbar'
 import { getToken } from '@/utils/auth'
-import { getBaseInfo, logout } from '@/api/common'
+import { logout } from '@/api/common'
 import { useUserStore } from '@/store/user'
 import { savePersonSimpleInfo } from '@/api/recruit/personal/shareJob'
+// import infoForm from '@/plugins/necessaryInfo/components/infoForm.vue'
+// import simplePageForm from './components/simplePageForm.vue'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 
 const joinSuccess = ref(false)
@@ -83,10 +86,19 @@ const handleLogin = async () => {
   try {
     const params = { ...phoneRef.value.loginData, autoRegister: true } // 只能验证码登录
     joinPersonEmail = params.email || ''
+    const setInfo = { email: joinPersonEmail, enterpriseId: enterpriseInfo.value.enterpriseName }
     // 如果用户登录后点击关闭填写简易人才信息,再次点击登录仅弹出填写,不再调用登录
     if (copyLoginData === (params.phone + params.code.toString()) && userId) {
-      getUserBaseInfos(userId)
-      return
+      // getUserBaseInfos(userId)
+      // return
+      if (!checkPersonBaseInfo()) { // 强制填写个人信息
+        necessaryInfo('necessaryInfoDialog', { setInfo }).then(() => {
+          join()
+        })
+        return
+      } else {
+        join()
+      }
     }
     if (!params.captchaVerification) {
       phoneRef.value.getCode(true)
@@ -95,7 +107,13 @@ const handleLogin = async () => {
     const data = await useUserStore().handleSmsLogin(params)
     copyLoginData = params.phone + params.code.toString()
     userId = data.userId
-    getUserBaseInfos(data.userId)
+    // getUserBaseInfos(data.userId)
+    if (!checkPersonBaseInfo()) { // 强制填写个人信息
+      necessaryInfo('necessaryInfoDialog', { setInfo }).then(() => {
+        join()
+      })
+      return
+    }
   } catch (error) {
     phoneRef.value && phoneRef.value.clearCaptcha()
     const msg = error?.msg || error
@@ -107,29 +125,29 @@ const handleLogin = async () => {
 }
 
 // 查询人才信息
-const showSimpleInput = ref(false)
-const getUserBaseInfos = async (userId) => {
-  loginLoading.value = true
-  try {
-    const data = await getBaseInfo({ userId })
-    if (!data) {
-      showSimpleInput.value = true; Snackbar.warning('请先完善个人基本信息')
-      return 
-    }
-    const keyArr = ['name', 'phone', 'jobStatus', 'expType', 'eduType'] // 必填人才信息
-    const simpleInfoReady = Object.keys(data).length && keyArr.every(e => data[e] && data[e] !== 0) // 校验必填人才信息
-    if (!simpleInfoReady) {
-      showSimpleInput.value = true; Snackbar.warning('请先完善个人基本信息')
-      return
-    }
-    join()
-  } catch (error) {
-    logoutFun()
-    Snackbar.error('获取用户信息失败! ' + error)
-  } finally {
-    loginLoading.value = false
-  }
-}
+// const showSimpleInput = ref(false)
+// const getUserBaseInfos = async (userId) => {
+//   loginLoading.value = true
+//   try {
+//     const data = await getBaseInfo({ userId })
+//     if (!data) {
+//       showSimpleInput.value = true; Snackbar.warning('请先完善个人基本信息')
+//       return 
+//     }
+//     const keyArr = ['name', 'phone', 'jobStatus', 'expType', 'eduType'] // 必填人才信息
+//     const simpleInfoReady = Object.keys(data).length && keyArr.every(e => data[e] && data[e] !== 0) // 校验必填人才信息
+//     if (!simpleInfoReady) {
+//       showSimpleInput.value = true; Snackbar.warning('请先完善个人基本信息')
+//       return
+//     }
+//     join()
+//   } catch (error) {
+//     logoutFun()
+//     Snackbar.error('获取用户信息失败! ' + error)
+//   } finally {
+//     loginLoading.value = false
+//   }
+// }
 
 // 调用加入接口
 const join = async () => {
@@ -162,22 +180,22 @@ const logoutFun = async () => {
     console.log('登出失败!', error)
   }
 }
-logoutFun() // 清除之前的token
+// logoutFun() // 清除之前的token
 
 // 提交简易人才信息
-const formRef = ref()
-const simpleInfoSubmit = async () => {
-  try {
-    const obj = await formRef.value.getQuery()
-    if (!obj) return
-    await savePersonSimpleInfo(obj)
-    join()
-    if (!isMobile.value) await useUserStore().getUserBaseInfos() // 网页打开需更新用户信息
-    showSimpleInput.value = false
-  } catch (error) {
-    console.error('error', error)
-  }
-}
+// const formRef = ref()
+// const simpleInfoSubmit = async () => {
+//   try {
+//     const obj = await formRef.value.getQuery()
+//     if (!obj) return
+//     await savePersonSimpleInfo(obj)
+//     join()
+//     if (!isMobile.value) await useUserStore().getUserBaseInfos() // 网页打开需更新用户信息
+//     // showSimpleInput.value = false
+//   } catch (error) {
+//     console.error('error', error)
+//   }
+// }
 
 const enterpriseInfo = ref({})
 // 根据邀请码获取企业信息

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

@@ -19,8 +19,8 @@
             <div v-if="!k.payFrom && !k.payTo">面议</div>
             <div v-else>{{k.payFrom ? k.payFrom + '-' : ''}}{{k.payTo}}</div>
             <div class="line">|</div>
-            <div class="grey-text text-box">{{ k.industry && k.industry.length ? k.industry.map(e => e.nameCn).join('、') : '' }}</div>
-            <div class="line" v-if="k.industry.length && k.jobTypeName">|</div>
+            <div class="grey-text text-box">{{ k.industry && k.industry?.length ? k.industry.map(e => e.nameCn).join('、') : '' }}</div>
+            <div class="line" v-if="k.industry?.length && k.jobTypeName">|</div>
             <div class="grey-text">{{ k.jobTypeName }}</div>
             <div class="line" v-if="k.jobTypeName && k.workArea">|</div>
             <div class="grey-text ellipsis" style="max-width: 160px;">

+ 20 - 20
src/views/recruit/personal/home/index.vue

@@ -24,7 +24,7 @@
     </div>
   </div>
   <!-- 快速填写简易人才信息-弹窗 -->
-  <simplePage v-if="showSimplePage" :closeable="true" closeText="暂时跳过" @close="handleInfoClose" @simpleInfoReady="handleUpdateInfo"></simplePage>
+  <!-- <simplePage v-if="showSimplePage" :closeable="true" closeText="暂时跳过" @close="handleInfoClose" @simpleInfoReady="handleUpdateInfo"></simplePage> -->
   <!-- 广告弹窗 -->
   <v-dialog
     v-model="adDialog"
@@ -40,7 +40,7 @@
 
 <script setup>
 defineOptions({ name:'personal-index'})
-import simplePage from './components/simple.vue'
+// import simplePage from './components/simple.vue'
 import headSearch from '@/components/headSearch'
 import hotJobs from './components/hotJobs.vue'
 import homeJobTypeCard from './components/homeJobTypeCard'
@@ -48,8 +48,8 @@ import hotPromotedPositions from './components/hotPromotedPositions.vue'
 import PopularEnterprises from './components/popularEnterprises.vue'
 import advertisementPage from './components/advertisement/index.vue'
 import { useRouter } from 'vue-router'
-import { nextTick, onMounted, ref } from 'vue'
-import { useUserStore } from '@/store/user'
+import { onMounted, ref } from 'vue'
+// import { useUserStore } from '@/store/user'
 import { getToken } from '@/utils/auth'
 import { getRewardEventList } from '@/utils/eventList'
 
@@ -62,23 +62,23 @@ const handleSearch = (val) => {
   if (val) router.push(`/recruit/personal/position?content=${val}`)
 }
 
-const store = useUserStore()
-const simple = ref(localStorage.getItem('simpleCompleteDialogHaveBeenShow'))
-const showSimplePage = ref(false) // 只提示一次
-if (!getToken()) showSimplePage.value = false
-nextTick(() => {
-  if (getToken()) {
-    showSimplePage.value = simple.value && JSON.parse(simple.value) ? true : false
-  }
-})
-const handleInfoClose = () => {
-  localStorage.setItem('simpleCompleteDialogHaveBeenShow', false)
-}
+// const store = useUserStore()
+// const simple = ref(localStorage.getItem('simpleCompleteDialogHaveBeenShow'))
+// const showSimplePage = ref(false) // 只提示一次
+// if (!getToken()) showSimplePage.value = false
+// nextTick(() => {
+//   if (getToken()) {
+//     showSimplePage.value = simple.value && JSON.parse(simple.value) ? true : false
+//   }
+// })
+// const handleInfoClose = () => {
+//   localStorage.setItem('simpleCompleteDialogHaveBeenShow', false)
+// }
 // 更新用户基本信息
-const handleUpdateInfo = async () => {
-  handleInfoClose()
-  await store.getUserBaseInfos(null)
-}
+// const handleUpdateInfo = async () => {
+//   handleInfoClose()
+//   await store.getUserBaseInfos(null)
+// }
 
 // 广告跳转
 const handleOpenAdvertise = () => {

+ 27 - 6
src/views/recruit/personal/position/components/details.vue

@@ -186,6 +186,8 @@ import { timesTampChange } from '@/utils/date'
 import { dealDictObjData, dealDictArrayData, commissionCalculation } from '@/utils/position'
 import { getToken } from '@/utils/auth'
 import { getUserAvatar } from '@/utils/avatar'
+import { checkPersonBaseInfo } from '@/utils/check'
+import necessaryInfo from '@/plugins/necessaryInfo'
 
 const props = defineProps({
   defaultWidth: {
@@ -208,7 +210,8 @@ const props = defineProps({
 
 const { t } = useI18n()
 const router = useRouter()
-const { id } = props.propJobId ? { id: props.propJobId } : router.currentRoute.value.params
+let { id } = props.propJobId ? { id: props.propJobId } : router.currentRoute.value.params
+if (id) id = id.toString()
 const delivery = ref(false) // 是否已投递简历
 const loading = ref(false)
 const showLogin = ref(false)
@@ -240,7 +243,7 @@ const formItems = ref({
   ]
 })
 
-const nextFunc = ref(null)
+const nextFunc = ref(null) // 登录成功或强制填写个人信息成功后回调
 let loginCloseWarningWord = ''
 // 快速登录
 const loginSuccess = () => {
@@ -337,27 +340,39 @@ getCollectionStatus()
 // 分享有礼
 const shareDialog = ref(false)
 const handleShare = async () => {
+  nextFunc.value = handleShare // 登录成功或强制填写个人信息成功后回调
   if (!getToken()) {
     showLogin.value = true // 打开快速登录弹窗
     Snackbar.warning('您还未登录,请先登录后再试')
     //
-    nextFunc.value = handleShare // 登录成功后要执行的操作
     loginCloseWarningWord = '您已取消登录,无法分享职位给好友' // 取消登录提示语
     return
   }
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      if (nextFunc.value) nextFunc.value()
+    })
+    return
+  }
   generateAndDownloadImage() // 生成海报
 }
 
 // 收藏&取消收藏职位
 const handleCollection = async () => {
+  nextFunc.value = handleCollection // 登录成功或强制填写个人信息成功后回调
   if (!getToken()) {
     showLogin.value = true // 打开快速登录弹窗
     Snackbar.warning('您还未登录,请先登录后再试')
     //
-    nextFunc.value = handleCollection // 登录成功后要执行的操作
     loginCloseWarningWord = '您已取消登录,无法收藏职位' // 取消登录提示语
     return
   }
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      if (nextFunc.value) nextFunc.value()
+    })
+    return
+  }
   const api = isCollection.value ? getPersonJobUnfavorite : getPersonJobFavorite
   await api(isCollection.value ? id : { jobId: id })
   await getCollectionStatus()
@@ -402,15 +417,21 @@ const showResume = ref(false)
 const resumeList = ref([])
 const selectResume = ref()
 const handleDelivery = async () => {
+  nextFunc.value = handleDelivery // 登录成功或强制填写个人信息成功后回调
   if (!getToken()) {
     showLogin.value = true // 打开快速登录弹窗
     Snackbar.warning('您还未登录,请先登录后再试')
     //
-    nextFunc.value = handleDelivery // 登录成功后要执行的操作
     loginCloseWarningWord = '您已取消登录,无法投递简历' // 取消登录提示语
     return
   }
   if (delivery.value) return Snackbar.warning(t('resume.alreadyResume'))
+  if (!checkPersonBaseInfo()) { // 强制填写个人信息
+    necessaryInfo('necessaryInfoDialog').then(() => {
+      if (nextFunc.value) nextFunc.value()
+    })
+    return
+  }
   const result = await getPersonResumeCv()
   resumeList.value = result
   // 没有上传过简历的先去上传
@@ -445,6 +466,7 @@ const handleSubmit = async (val) =>{
 let toDetailsInfo = {}
 // 沟通
 const toDetails = async (info) => {
+  nextFunc.value = toDetails // 登录成功或强制填写个人信息成功后回调
   if (info) toDetailsInfo = info // 快速登录弹窗回调使用
   else info = toDetailsInfo
   if (!getToken()) {
@@ -452,7 +474,6 @@ const toDetails = async (info) => {
     Snackbar.warning('您还未登录,请先登录后再试')
     //
     loginCloseWarningWord = '您已取消登录,无法对职位进行沟通' // 取消登录提示语
-    nextFunc.value = toDetails // 登录成功后要执行的操作 (toDetails执行不成功,原因未找到)
     return
   }
   try {