浏览代码

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

Xiao_123 6 月之前
父节点
当前提交
b8ef69bfb7

+ 7 - 7
.env.development

@@ -1,21 +1,21 @@
 NODE_ENV = 'development'
 
 # 版本号 1937
-VITE_VERSION = 'v24.11.11.1843'
+VITE_VERSION = 'v24.11.12.1744'
 
 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'

+ 15 - 15
src/App.vue

@@ -6,15 +6,15 @@ import axios from 'axios'
 
 const openCheckVersion = true // 开启检测版本
 const timer = ref(null)
-const setIntervalTime = 300000 // 300000 五分钟
+const setIntervalTime = 3000 // 300000 五分钟
+
 function open () {
   if (timer.value) clearInterval(timer.value)
   timer.value = setInterval(() => { checkVersion() }, setIntervalTime)
 }
 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, process?.env?.NODE_ENV) // 打印
     const process_ENV = process?.env?.NODE_ENV || ''
     if ((process_ENV === 'production' || process_ENV === 'development') && openCheckVersion) {
       open()
@@ -25,6 +25,7 @@ onUnmounted(() => {
   if (timer.value) clearInterval(timer.value)
 })
 
+let ConfirmDone = false
 // 检查版本号
 const checkVersion = () => {
   const baseUrl = import.meta.env.VITE_BASE_URL || ''
@@ -33,20 +34,19 @@ const checkVersion = () => {
   // 
   if (!baseUrl || !version || !tenantId) return
   axios.get(`${baseUrl}/app-api/menduner/system/get/version`, {
-    headers: { ['tenant-id']: tenantId }
+    headers: { ['tenant-id']: tenantId },
+    cache: 'no-store' // 禁用缓存
   }).then((res) => {
-    if (res?.data?.data !== version) {
-      // const option = {
-      //   autoCloseTime: setIntervalTime > 15000 ? setIntervalTime - 10000 : setIntervalTime >= 5000 ? setIntervalTime - 1000 : setIntervalTime
-      // }
-      clearInterval(timer.value)
-      timer.value = null
-      Confirm('系统提示', '发现新版本,是否立即刷新页面').then(() => {
-        window.location.reload()
-      }).catch(() => {
-        open()
-      })
+    if (res?.data?.data === version) {
+      return
+    }
+    if (ConfirmDone) {
+      return
     }
+    ConfirmDone = true
+    Confirm('系统提示', '发现新版本,将立即刷新页面', { hideCancelBtn: true }).then(() => {
+      window.location.reload()
+    })
   }).catch(err => {
     console.log('checkVersion-err', err)
   })

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

@@ -73,7 +73,7 @@
     <Empty v-else :elevation="false"></Empty>
 
     <!-- 快速登录 -->
-    <login-page v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></login-page>
+    <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
   </div>
 </template>
 

+ 1 - 1
src/components/Position/longStrip.vue

@@ -48,7 +48,7 @@
     </div>
 
     <!-- 快速登录 -->
-    <login-page v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></login-page>
+    <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
   </div>
 </template>
 

+ 13 - 2
src/config/axios/service.js

@@ -76,8 +76,7 @@ service.interceptors.request.use(
       (config).headers.Authorization = 'Bearer ' + getToken(tokenIndex) // 让每个请求携带自定义token
     }
 
-    // 开启参数加密
-    if (config.openEncryption) encryptionFun(config)
+
 
     // 设置租户
     if (tenantEnable && tenantEnable === 'true') {
@@ -101,6 +100,18 @@ service.interceptors.request.use(
         config.url = config.url + '?' + paramsStr
       }
     }
+
+    // 开启参数加密
+    if (config.openEncryption) {
+      // console.log(config)
+      const raw = config.url.split('?')[1]
+      const body = {
+        ...config.data,
+        ...config.params
+      }
+      const header = encryptionFun({raw, body, appId: 'web_client', AppSecret: 'fa0fc0b5098b974b'})
+      Object.assign(config.headers, header)
+    }
     
     if (isToken) {
       // 截取request url

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

@@ -109,7 +109,7 @@ export default {
     userAgreement: '用户协议',
     privacyPolicy: '隐私政策',
     switchToPersonalLogin: '切换到个人登录',
-    agreeLogin: '登录/注册即代表您同意',
+    agreeLogin: '勾选即代表您同意',
     smsOrPassword: '短信、密码登录或注册',
     scanWeChatCode: '微信扫码快速登录',
     loginSuccess: '登录成功',

+ 36 - 32
src/utils/openEncryption.js

@@ -1,38 +1,42 @@
+/**
+ * encryptionFun()
+  示例1 http://xxx.com?id=123
+  encryptionFun('id=123')
+
+  示例2 http://xxx.com   {"id":123}
+  encryptionFun('{"id":123}')
+
+  示例3 http://xxx.com?id=123&name=张三   {"id":123}
+  encryptionFun('id=123&name=张三{"id":123}')
+*/
+
 import { generateUUID } from "@/utils/index" 
 import { sha256 } from 'js-sha256'
-import qs from 'qs'
-
-// 加密方式:请求头加参数: appId + nonce + timestamp + sign
-// (sign为: queryJsonData+paramsToStrSort+appSecret拼接后sha256加密字符串)
 
-// 开启参数加密
-export const encryptionFun = (config) => {
-  // console.log('加密内容用完请注释->config', config)
+/**
+ * 
+ * @param { str } raw 参数用&隔开
+ * @param { Object } body
+ * @returns 
+*/
+export const encryptionFun = ({raw, body, appId, AppSecret}) => {
   const initSign = {
-    appId: 'web_client', // 与后端协商一致使用
-    nonce: generateUUID(), // 前端生成唯一参数
-    timestamp: new Date().getTime() + 3000, // 多加两秒时间
+    appId,
+    nonce: generateUUID(),
+    timestamp: new Date().getTime() + 3000,
+  }
+  const _initSign = Object.keys(initSign).reduce((str, key) => str += `&${key}=${initSign[key]}`, '')
+  const paramsStr = _initSign.slice(1, _initSign.length) + AppSecret
+  let str = ''
+  if (raw) {
+    str += decodeURIComponent(raw)
+  }
+  if (body && Object.keys(body).length) {
+    str += decodeURIComponent(JSON.stringify(body))
+  }
+  // console.log('str:', str, 'paramsStr:', paramsStr)
+  return {
+    ...initSign,
+    sign: sha256(str + paramsStr)
   }
-  // 固定的参数初始化成字符串
-  const paramsToStrSort = ['appId', 'nonce', 'timestamp'] // 顺序不能变
-  let paramsStr = paramsToStrSort.reduce((str, key) => {
-    if (initSign[key]) str = str ? str + `&${key}=${initSign[key]}` : `${key}=${initSign[key]}`
-    return str
-  }, '')
-  const appSecret = 'fa0fc0b5098b974b' // 与后端协商一致使用(拼接在paramsStr后面,且拼接时不加key)
-  paramsStr = paramsStr + appSecret
-  // console.log('加密内容用完请注释->paramsStr', paramsStr)
-
-  // 请求的参数json // 携带的参数json一下,url拼接参数的直接用,没有参数不拼接
-  const queryJsonData = config.data && Object.keys(config.data).length ?
-    decodeURIComponent(JSON.stringify(config.data)) :
-    config.params && Object.keys(config.params).length ?
-    decodeURIComponent(qs.stringify(config.params, { allowDots: true }) ) :
-    config.url.split('?')?.length>1 ?
-    config.url.split('?')[1] : ''
-  // sha256加密字符串
-  if (paramsStr) initSign.sign = sha256(queryJsonData + paramsStr)
-  // console.log('加密内容用完请注释->queryJsonData', queryJsonData)
-  // 请求头加参数initSign,请求头加参数: appId + nonce + timestamp + sign
-  if (initSign &&  Object.keys(initSign).length) Object.keys(initSign).forEach(key => { (config).headers[key] = initSign[key] })
 }

+ 112 - 21
src/views/common/loginDialog.vue

@@ -1,30 +1,66 @@
 <!-- 快速登录/注册 -->
 <template>
-  <CtDialog
-    :visible="openDialog"
-    :widthType="2"
-    :footer="false"
-    titleClass="text-h6"
-    title="快速登录"
-    @close="openDialog = false"
-  >
-    <div class="my-5">
-      <phoneFrom ref="phoneRef" @handleEnter="handleLogin"></phoneFrom>
-      <v-btn :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click="handleLogin">
-        {{ $t('login.loginOrRegister') }}
-      </v-btn>
-      <div class="text-center color-666 font-size-14 mt-3">未注册的手机号,验证后自动注册账号</div>
-    </div>
-  </CtDialog>
+  <div>
+    <CtDialog
+      :visible="openDialog"
+      :widthType="2"
+      :footer="false"
+      titleClass="text-h6"
+      title="快速登录"
+      @close="loginClose"
+    >
+      <div class="mb-5">
+        <!-- <phoneFrom ref="phoneRef" @handleEnter="handleLogin"></phoneFrom> -->
+        <!-- 个人登录 -->
+        <div class="login-tab">
+          <v-tabs v-model="tab" align-tabs="center" color="primary" class="mb-10">
+            <v-tab :value="2">账号</v-tab>
+            <v-tab :value="1">验证码</v-tab>
+          </v-tabs>
+          <v-window v-model="tab">
+              <!-- 验证码登录 -->
+            <v-window-item :value="1">
+              <phoneFrom ref="phoneRef" class="phoneClass" openVerify @handleEnter="handleLogin"></phoneFrom>
+            </v-window-item>
+              <!-- 账号密码登录 -->
+            <v-window-item :value="2">
+              <passwordFrom ref="passRef" @handleEnter="handleLogin"></passwordFrom>
+            </v-window-item>
+          </v-window>
+        </div>
+        <v-btn :loading="loginLoading" color="primary" class="white--text mt-5" min-width="350" @click="handleLogin">
+          {{ $t('login.loginOrRegister') }}
+        </v-btn>
+        <div class="login-tips mt-3 font-size-14">
+            <v-icon v-if="isAgree" size="18" color="primary" class="mr-2" @click="isAgree = !isAgree">mdi-check-circle</v-icon>
+            <v-icon v-else size="18" color="grey" class="mr-2" @click="isAgree = !isAgree">mdi-circle-outline</v-icon>
+            {{ $t('login.agreeLogin') }}
+            <span class="color" style="cursor: pointer;" @click="windowOpen('/userAgreement')"> [{{ $t('login.userAgreement') }}] </span>和
+            <span class="color" style="cursor: pointer;" @click="windowOpen('/privacyPolicy')">[{{ $t('login.privacyPolicy') }}]</span>
+        </div>
+        <div v-if="tab === 1" class="text-center color-666 font-size-12 mt-1">未注册的手机号,验证后自动注册账号</div>
+      </div>
+      <Verify
+        ref="verify"
+        captchaType="blockPuzzle"
+        :imgSize="{ width: '400px', height: '200px' }"
+        mode="pop"
+        @success="verifySuccess"
+      />
+    </CtDialog>
+  </div>
 </template>
 
 <script setup>
 defineOptions({name: 'dialog-login-common-page'})
 import phoneFrom from '@/components/VerificationCode'
+import passwordFrom from '@/views/login/components/passwordPage.vue'
 import { useUserStore } from '@/store/user'; const userStore = useUserStore()
 import { nextTick, ref } from 'vue'
+import Verify from '@/components/Verifition'
+import Snackbar from '@/plugins/snackbar'
 
-const emit = defineEmits(['loginSuccess'])
+const emit = defineEmits(['loginSuccess', 'close'])
 
 const props = defineProps({
   // 是否需要退出后再登录,切换账号时使用
@@ -39,26 +75,81 @@ nextTick(() => {
   openDialog.value = true
 })
 
+const tab = ref(2) // 密码登录
+const isAgree = ref(false)
+const passRef = ref()
 // 验证码登录
 const phoneRef = ref()
 const loginLoading = ref(false)
 
 const handleLogin = async () => {
-  const { valid } = await phoneRef.value.phoneForm.validate()
+  // const { valid } = await phoneRef.value.phoneForm.validate()
+  const { valid } = tab.value === 1 ? await phoneRef.value.phoneForm.validate() : await passRef.value.passwordForm.validate()
   if (!valid) return
+  if (!isAgree.value) return Snackbar.warning('请阅读并勾选底部协议')
+  // 
+  let params, api = ''
+  params = tab.value === 1 ? { ...phoneRef.value.loginData } : { ...passRef.value.loginData }
+  api = tab.value === 1 ? 'handleSmsLogin' : 'handlePasswordLogin'
+  if (!params.captchaVerification && captchaStr.value) params.captchaVerification = captchaStr.value
+  if (!params.captchaVerification) {
+    getCode() // 验证码组件
+    return
+  }
+  loginLoading.value = true
   if (props.hasLogout) {
     await userStore.userLogout(1)
   }
-  loginLoading.value = true
   try {
-    const params = { ...phoneRef.value.loginData, autoRegister: true } // autoRegister: 是否自动注册
-    await userStore.handleSmsLogin(params)
+    // const params = { ...phoneRef.value.loginData, autoRegister: true } // autoRegister: 是否自动注册
+    // await userStore.handleSmsLogin(params)
+    await userStore[api](params)
     emit('loginSuccess')
   } catch (error) {
+    captchaStr.value = '' // 清空人机验证
+    phoneRef.value && phoneRef.value.clearCaptcha() // 清空人机验证
     console.error('error', error)
   }
 }
+
+// 获取验证码
+const verify = ref()
+const getCode = async () => {
+  // 弹出验证码 // 已开启:则展示验证码;只有完成验证码的情况,才进行登录
+  verify.value.show()
+}
+
+const captchaStr = ref('')
+const verifySuccess = (params) => {
+  captchaStr.value = params.captchaVerification
+  handleLogin()
+}
+const loginClose = () => {
+  openDialog.value = false
+  emit('close')
+}
 </script>
 
 <style lang="scss" scoped>
+.login-tips {
+  width: 100%;
+  font-size: 12px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+.tips {
+  span:hover {
+    text-decoration: underline;
+  }
+}
+// :deep(.v-window-item) {}
+:deep(.mask) {
+  width: 100vw;
+  transform: translate(calc(-50% + 200px), calc(-50% + 223px));
+}
+.mask {
+  width: 100vw;
+  transform: translate(calc(-50% + 200px), calc(-50% + 223px));
+}
 </style>

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

@@ -102,7 +102,6 @@ import navBar from '@/layout/personal/navBar.vue'
 import about from '@/views/about/index.vue'
 import { useRoute } from 'vue-router'; const route = useRoute()
 import Verify from '@/components/Verifition'
-console.log(1, '23456', 789)
 
 const isMobile = ref(false)
 onMounted(() => {

+ 2 - 1
src/views/mall/index.vue

@@ -68,7 +68,8 @@ userStore.$subscribe((mutation, state) => {
 
 const showLogin = ref(false)
 const handleLogin = () => {
-  showLogin.value = true
+  showLogin.value = true // 打开快速登录弹窗
+  // Snackbar.warning('您还未登录,请先登录后再试')
 }
 
 // 快速登录

+ 2 - 0
src/views/recruit/enterprise/talentMap/index.vue

@@ -1,4 +1,5 @@
 <template>
+<div>
   <v-card class="card-box pa-5" style="height: 100%;">
     <div class="d-flex flex-column align-center" :class="{'v-center': init}">
       <TextUI
@@ -88,6 +89,7 @@
       <CtForm :items="formItems" style="width: 100%;"></CtForm>
     </div>
   </CtDialog>
+</div>
 </template>
 
 <script setup>

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

@@ -152,7 +152,7 @@
     </div>
 
     <!-- 快速登录 -->
-    <login-page v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></login-page>
+    <loginPage v-if="showLogin" @loginSuccess="loginSuccess" @close="loginClose"></loginPage>
   </div>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
 </template>
 

+ 6 - 6
src/views/recruit/personal/shareJob/index.vue

@@ -72,23 +72,23 @@
     </v-card>
 
     <!-- 快速登录/注册 -->
-    <login-page
+    <loginPage
       v-if="sendResume.showLogin"
       :jobId="jobId"
       :hasLogout="hasLogout"
       @loginSuccess="loginSuccess"
       @close="handleClose('showLogin')"
-    ></login-page>
+    ></loginPage>
 
     <!-- 快速填写简易人才信息 -->
-    <simple-page
+    <simplePage
       v-if="sendResume.showSimpleInfo"
       @simpleInfoReady="simpleInfoReadyFun"
       @close="handleClose('showSimpleInfo')"
-    ></simple-page>
+    ></simplePage>
 
     <!-- 选择简历 -->
-    <select-page
+    <selectPage
       v-if="sendResume.showSelect"
       :hire="info?.hire"
       :jobId="jobId"
@@ -96,7 +96,7 @@
       @refresh="handleCheckJobDelivery"
       @close="handleClose('showSelect')"
       ref="selectRef"
-    ></select-page>
+    ></selectPage>
   </div>
 </template>
 

+ 13 - 27
src/views/recruit/personal/shareJob/sendResume/simple.vue

@@ -20,8 +20,6 @@ import simpleInfoForm from '../form/simpleInfo.vue'
 import { savePersonSimpleInfo } from '@/api/recruit/personal/shareJob'
 import { useI18n } from '@/hooks/web/useI18n'; const { t } = useI18n()
 import Snackbar from '@/plugins/snackbar'
-import { useUserStore } from '@/store/user'
-import { useRouter } from 'vue-router'
 import { ref } from 'vue'
 defineOptions({name: 'shareJob-sendResume-simple'})
 
@@ -38,47 +36,35 @@ const props = defineProps({
 })
 
 const openDialog = ref(false) // 默认不打开弹窗,先检验simpleInfoReady
-const info = ref(null)
-const store = useUserStore()
-const router = useRouter()
 
 const handleClose = () => {
   emit('close')
   openDialog.value = props.closeable ? false : true
 }
 
-// 查询用户基本信息
-const timer = ref(null)
-
-// 登录情况下校验必填人才信息
-if (getToken()) timer.value = setInterval(() => { getUserInfoVerify() }, 100)
-
-// 查询用户基本信息
+let verifyCount = 0
 const getUserInfoVerify = () => {
-  setTimeout(() => { if (!info.value) getUserInfoFail() }, 10000); // 十秒后停止获取清除timer
-  if (info.value) {
-    if (timer.value) clearInterval(timer.value); timer.value = null
+  // console.log('获取人才信息->')
+  const bInfo = JSON.parse(localStorage.getItem('baseInfo'))
+  if (bInfo && Object.keys(bInfo).length) { // 校验必填人才信息
+    // console.log('获取人才信息成功->')
     const keyArr = ['name', 'phone', 'jobStatus', 'expType', 'eduType'] // 必填人才信息
-    const simpleInfoReady = Object.keys(info.value).length && keyArr.every(e => info.value[e] && info.value[e] !== 0) // 校验必填人才信息
+    const simpleInfoReady = keyArr.every(e => bInfo[e] && bInfo[e] !== 0) // 校验必填人才信息
     if (simpleInfoReady) {
       emit('simpleInfoReady') // 存在
     } else {
       openDialog.value = true // 不存在
       Snackbar.warning('请先完善个人基本信息')
     }
+  } else {
+    if (verifyCount > 2) Snackbar.error(t('login.getUserInfoFailed')+','+t('login.loginAgain'))  // 获取人才信息失败 
+    else {
+      verifyCount++
+      setTimeout(() => { getUserInfoVerify() }, 4000) // 获取人才信息
+    }
   }
-  info.value = JSON.parse(localStorage.getItem('baseInfo'))
-}
-
-// 查询用户基本信息-失败 
-const getUserInfoFail = () => {
-  if (timer.value) clearInterval(timer.value); timer.value = null
-  Snackbar.error(t('login.getUserInfoFailed')+','+t('login.loginAgain'))
-  setTimeout(() => {
-    store.userLogout(1)
-    router.push('/login')
-  }, 3000)
 }
+if (getToken()) setTimeout(() => { getUserInfoVerify() }, 2000) // 获取人才信息
 
 const formRef = ref()
 const simpleInfoSubmit = async () => {