From bdd42bd790a6ab85b814df5d1099c5eb7deee726 Mon Sep 17 00:00:00 2001 From: francis-fh Date: Wed, 3 Jun 2026 17:02:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E5=A4=B1=E8=B4=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/wxAuthLogin/WxAuthLogin.vue | 154 +++++++++++++------------ pages/login/wx-login.vue | 146 ++++++++++++----------- utils/loginHelper.js | 44 ++++++- 3 files changed, 204 insertions(+), 140 deletions(-) diff --git a/components/wxAuthLogin/WxAuthLogin.vue b/components/wxAuthLogin/WxAuthLogin.vue index 283022c..2c03e72 100644 --- a/components/wxAuthLogin/WxAuthLogin.vue +++ b/components/wxAuthLogin/WxAuthLogin.vue @@ -126,6 +126,7 @@ import { ref, inject, onMounted } from 'vue'; import useUserStore from '@/stores/useUserStore'; import useDictStore from '@/stores/useDictStore'; import { tabbarManager } from '@/utils/tabbarManager'; +import { refreshWxLoginCode, takeWxLoginCode } from '@/utils/loginHelper'; const { $api } = inject('globalFunction'); const { loginSetToken } = useUserStore(); @@ -171,6 +172,10 @@ const open = () => { // 检查是否已同意协议 const agreed = uni.getStorageSync('agreedToUserAgreement'); agreedToAgreement.value = !!agreed; + + // #ifdef MP-WEIXIN + refreshWxLoginCode().catch(() => {}); + // #endif }; // 关闭弹窗 @@ -212,84 +217,85 @@ const validateRole = () => { return true; }; -const getPhoneNumber = (e) => { - console.log('获取手机号:', e); - console.log('userType.value', userType.value) - - // 验证角色、机构类型和隐私协议 +const getPhoneNumber = async (e) => { if (!validateRole()) { return; } - + if (e.detail.errMsg === 'getPhoneNumber:ok') { - uni.login({ - provider: 'weixin', - success: (loginRes) => { - console.log('微信登录code获取成功:', loginRes.code); - const { encryptedData, iv } = e.detail; - const code = loginRes.code; // 使用wx.login返回的code - - // 调用后端接口进行登录 - uni.showLoading({ title: '登录中...' }); - - $api.createRequest('/app/appLogin', { - code, - encryptedData, - iv, - userType: userType.value, - orgType: orgType.value - }, 'post').then((resData) => { - uni.hideLoading(); - console.log(resData, 'resume.idCard'); - if (resData.token) { - // 登录成功,存储token - loginSetToken(resData.token).then((resume) => { - // 更新用户类型到缓存 - if (resData.isCompanyUser !== undefined) { - console.log(resData.isCompanyUser, 'resData.isCompanyUser'); - const userInfo = uni.getStorageSync('userInfo') || {}; - userInfo.isCompanyUser = Number(resData.isCompanyUser); // 0-企业用户,1-求职者 - uni.setStorageSync('userInfo', userInfo); - } - - $api.msg('登录成功'); - // 刷新tabbar以显示正确的用户类型 - tabbarManager.refreshTabBar(); - close(); - emit('success'); - - // 根据用户类型跳转到不同的信息补全页面 - if (!resume.jobTitleId) { - console.log(resume, 'resume.idCard'); - if (userType.value === 1 && !resData.idCard) { - // 求职者跳转到个人信息补全页面 - uni.navigateTo({ - url: '/packageA/pages/complete-info/complete-info?step=1' - }); - } else if (userType.value === 0 && !resData.idCard) { - // 招聘者跳转到企业信息补全页面 - uni.navigateTo({ - url: '/packageA/pages/complete-info/company-info' - }); - } - } - }).catch(() => { - $api.msg('获取用户信息失败'); - }); - } else { - // $api.msg('登录失败,请重试'); - $api.msg(resData.msg || '登录失败,请重试'); - } - }).catch((err) => { - uni.hideLoading(); - $api.msg(err.msg || '登录失败,请重试'); - }); - }, - fail: (err) => { - console.error('获取微信登录code失败:', err); - $api.msg('获取登录信息失败,请重试'); - } - }); + const { encryptedData, iv, code: wxPhoneCode } = e.detail; + if (!encryptedData && !wxPhoneCode) { + $api.msg('获取手机号失败'); + return; + } + + let loginCode = takeWxLoginCode(); + if (!loginCode) { + if (encryptedData) { + $api.msg('登录凭证未就绪,请关闭弹窗后重新打开再试'); + refreshWxLoginCode().catch(() => {}); + return; + } + try { + loginCode = await refreshWxLoginCode(); + } catch { + $api.msg('获取登录信息失败,请重试'); + return; + } + } + + const requestParams = { + code: loginCode, + userType: userType.value, + orgType: orgType.value + }; + if (encryptedData && iv) { + requestParams.encryptedData = encryptedData; + requestParams.iv = iv; + } + if (wxPhoneCode) { + requestParams.phoneCode = wxPhoneCode; + } + + uni.showLoading({ title: '登录中...' }); + try { + const resData = await $api.createRequest('/app/appLogin', requestParams, 'post'); + if (resData.token) { + await loginSetToken(resData.token).then((resume) => { + if (resData.isCompanyUser !== undefined) { + const userInfo = uni.getStorageSync('userInfo') || {}; + userInfo.isCompanyUser = Number(resData.isCompanyUser); + uni.setStorageSync('userInfo', userInfo); + } + + $api.msg('登录成功'); + tabbarManager.refreshTabBar(); + close(); + emit('success'); + + if (!resume.jobTitleId) { + if (userType.value === 1 && !resData.idCard) { + uni.navigateTo({ + url: '/packageA/pages/complete-info/complete-info?step=1' + }); + } else if (userType.value === 0 && !resData.idCard) { + uni.navigateTo({ + url: '/packageA/pages/complete-info/company-info' + }); + } + } + }).catch(() => { + $api.msg('获取用户信息失败'); + }); + } else { + $api.msg(resData.msg || '登录失败,请重试'); + } + } catch (err) { + $api.msg(err.msg || '登录失败,请重试'); + } finally { + uni.hideLoading(); + refreshWxLoginCode().catch(() => {}); + } } else if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { $api.msg('您取消了授权'); } else { diff --git a/pages/login/wx-login.vue b/pages/login/wx-login.vue index 6682767..75b2076 100644 --- a/pages/login/wx-login.vue +++ b/pages/login/wx-login.vue @@ -127,6 +127,7 @@ import { ref, inject, onMounted, computed } from 'vue'; import { onLoad } from '@dcloudio/uni-app'; import useUserStore from '@/stores/useUserStore'; import useDictStore from '@/stores/useDictStore'; +import { refreshWxLoginCode, takeWxLoginCode } from '@/utils/loginHelper'; const { $api } = inject('globalFunction'); const userStore = useUserStore(); @@ -243,82 +244,94 @@ const checkBeforeWxAuth = (e) => { } }; -// 微信获取手机号 +// 微信获取手机号(使用授权前预取的 login code,避免授权后再 login 导致 session_key 不匹配) const onWxGetPhoneNumber = async (e) => { - const { encryptedData, iv } = e.detail; - // 使用通用验证函数 if (!validateForm()) { return; } - + if (e.detail.errMsg === 'getPhoneNumber:ok') { - uni.login({ - provider: 'weixin', - success: (loginRes) => { - const code = loginRes.code; - - // 调用接口 /app/appWxphoneSmsCode - uni.showLoading({ title: '获取验证码中...' }); - - // 根据用户类型构建参数 - const requestParams = { - code, - encryptedData, - iv, - userType: userType.value - }; - // 只有单位用户才传递机构类型 - if (userType.value === 0) { - requestParams.orgType = orgType.value; - } - - $api.createRequest('/app/appWxphoneSmsCode', requestParams, 'post').then((resData) => { - uni.hideLoading(); - // 检查可能的手机号字段 - const possiblePhoneFields = ['phone', 'mobile', 'phoneNumber', 'tel', 'mobilePhone']; - let phoneValue = ''; - for (const field of possiblePhoneFields) { - if (resData[field]) { - phoneValue = resData[field]; - console.log(`从接口返回中找到手机号字段 "${field}": ${phoneValue}`); - break; - } - } - - if (resData.code === 200 || resData.success) { - // 跳转到短信验证页面,传递参数 - const params = { - phone: phoneValue || '', // 接口返回的手机号 - openid: resData.openid || '', - unionid: resData.unionid || '', - userType: userType.value - }; - // 只有单位用户才传递机构类型 - if (userType.value === 0) { - params.orgType = orgType.value; - } - - uni.navigateTo({ - url: '/pages/login/sms-verify?' + Object.keys(params) - .map(key => `${key}=${encodeURIComponent(params[key])}`) - .join('&') - }); - } else { - $api.msg(resData.msg || '获取验证码失败'); - } - }).catch((err) => { - uni.hideLoading(); - $api.msg(err.msg || '获取验证码失败,请重试'); + const { encryptedData, iv, code: wxPhoneCode } = e.detail; + if (!encryptedData && !wxPhoneCode) { + uni.showToast({ title: '获取手机号失败', icon: 'none', duration: 2000 }); + return; + } + + let loginCode = takeWxLoginCode(); + if (!loginCode) { + if (encryptedData) { + uni.showToast({ + title: '登录凭证未就绪,请稍后重新点击授权', + icon: 'none', + duration: 2000 }); - }, - fail: (err) => { + refreshWxLoginCode().catch(() => {}); + return; + } + try { + loginCode = await refreshWxLoginCode(); + } catch { uni.showToast({ title: '获取登录信息失败,请重试', icon: 'none', duration: 2000 }); + return; } - }); + } + + uni.showLoading({ title: '获取验证码中...' }); + + const requestParams = { + code: loginCode, + userType: userType.value + }; + if (encryptedData && iv) { + requestParams.encryptedData = encryptedData; + requestParams.iv = iv; + } + if (wxPhoneCode) { + requestParams.phoneCode = wxPhoneCode; + } + if (userType.value === 0) { + requestParams.orgType = orgType.value; + } + + try { + const resData = await $api.createRequest('/app/appWxphoneSmsCode', requestParams, 'post'); + const possiblePhoneFields = ['phone', 'mobile', 'phoneNumber', 'tel', 'mobilePhone']; + let phoneValue = ''; + for (const field of possiblePhoneFields) { + if (resData[field]) { + phoneValue = resData[field]; + break; + } + } + + if (resData.code === 200 || resData.success) { + const params = { + phone: phoneValue || '', + openid: resData.openid || '', + unionid: resData.unionid || '', + userType: userType.value + }; + if (userType.value === 0) { + params.orgType = orgType.value; + } + uni.navigateTo({ + url: '/pages/login/sms-verify?' + Object.keys(params) + .map(key => `${key}=${encodeURIComponent(params[key])}`) + .join('&') + }); + } else { + $api.msg(resData.msg || '获取验证码失败'); + } + } catch (err) { + $api.msg(err.msg || '获取验证码失败,请重试'); + } finally { + uni.hideLoading(); + refreshWxLoginCode().catch(() => {}); + } } else if (e.detail.errMsg === 'getPhoneNumber:fail user deny') { uni.showToast({ title: '您取消了授权', @@ -494,9 +507,12 @@ const testLogin = () => { }); }; -// 页面加载时获取字典数据 +// 页面加载时获取字典数据,并预取 wx.login code onLoad(() => { getOrgTypeDict(); + // #ifdef MP-WEIXIN + refreshWxLoginCode().catch(() => {}); + // #endif }); diff --git a/utils/loginHelper.js b/utils/loginHelper.js index 4f19bb3..9b0de1a 100644 --- a/utils/loginHelper.js +++ b/utils/loginHelper.js @@ -136,6 +136,45 @@ export function parseIdCardLoginParams(url) { * @param {string} base64Str base64编码的字符串 * @returns {string} 解码后的身份证号码 */ +/** 预取的 wx.login code,须在 getPhoneNumber 之前获取,授权后勿再 login */ +let cachedWxLoginCode = ''; + +/** + * 预取 wx.login 的 code(与后续 getPhoneNumber 的 encryptedData 使用同一 session) + */ +export function refreshWxLoginCode() { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: 'weixin', + success: (res) => { + if (res.code) { + cachedWxLoginCode = res.code; + resolve(res.code); + } else { + reject(new Error('未获取到微信登录凭证')); + } + }, + fail: (err) => reject(err), + }); + // #endif + // #ifndef MP-WEIXIN + resolve(''); + // #endif + }); +} + +export function getWxLoginCode() { + return cachedWxLoginCode; +} + +/** 取出并清空缓存(微信 code 仅能使用一次) */ +export function takeWxLoginCode() { + const code = cachedWxLoginCode; + cachedWxLoginCode = ''; + return code; +} + export function decodeIdCardBase64(base64Str) { try { // #ifdef H5 @@ -164,5 +203,8 @@ export default { navigateToLoginPage, checkLoginAndNavigate, parseIdCardLoginParams, - decodeIdCardBase64 + decodeIdCardBase64, + refreshWxLoginCode, + getWxLoginCode, + takeWxLoginCode, };