pet/utils/loginState.js

383 lines
10 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 登录状态管理工具
* 用于管理用户登录流程中的状态和数据传递
*/
// 登录步骤常量
export const LOGIN_STEPS = {
NOT_LOGGED: 'not_logged', // 未登录
WX_LOGGED: 'wx_logged', // 微信登录完成
PHONE_AUTHED: 'phone_authed', // 手机号授权完成
PHONE_SKIPPED: 'phone_skipped', // 跳过手机号授权
PROFILE_COMPLETED: 'profile_completed' // 个人信息完善完成
}
// 存储键名常量
export const STORAGE_KEYS = {
LOGIN_STEP: 'loginStep',
WX_LOGIN_CODE: 'wxLoginCode',
TOKEN: 'token',
REFRESH_TOKEN: 'refreshToken',
PHONE_NUMBER: 'phoneNumber',
WX_USER_INFO: 'wxUserInfo',
USER_INFO: 'userInfo',
LOGIN_DATE: 'loginDate'
}
/**
* 获取当前登录步骤
* @returns {string} 当前登录步骤
*/
export const getCurrentLoginStep = () => {
return uni.getStorageSync(STORAGE_KEYS.LOGIN_STEP) || LOGIN_STEPS.NOT_LOGGED
}
/**
* 设置登录步骤
* @param {string} step 登录步骤
*/
export const setLoginStep = (step) => {
console.log('设置登录步骤:', step)
uni.setStorageSync(STORAGE_KEYS.LOGIN_STEP, step)
}
/**
* 检查用户是否已完成登录流程
* @returns {boolean} 是否已完成登录
*/
export const isLoginCompleted = () => {
const step = getCurrentLoginStep()
return step === LOGIN_STEPS.PROFILE_COMPLETED
}
/**
* 检查用户是否需要继续登录流程
* @returns {boolean} 是否需要继续登录
*/
export const needsContinueLogin = () => {
const step = getCurrentLoginStep()
return step !== LOGIN_STEPS.NOT_LOGGED && step !== LOGIN_STEPS.PROFILE_COMPLETED
}
/**
* 获取下一个应该跳转的页面
* @returns {string|null} 页面路径如果不需要跳转则返回null
*/
export const getNextPage = () => {
const step = getCurrentLoginStep()
switch (step) {
case LOGIN_STEPS.WX_LOGGED:
return '/pages/auth/phone-auth'
case LOGIN_STEPS.PHONE_AUTHED:
case LOGIN_STEPS.PHONE_SKIPPED:
return '/pages/profile/user-info?mode=setup'
case LOGIN_STEPS.PROFILE_COMPLETED:
return '/pages/profile/profile'
default:
return null
}
}
/**
* 保存微信登录信息
* @param {Object} loginData 登录数据
*/
export const saveWxLoginData = (loginData) => {
const { code } = loginData
uni.setStorageSync(STORAGE_KEYS.WX_LOGIN_CODE, code)
uni.setStorageSync(STORAGE_KEYS.LOGIN_DATE, new Date().toISOString())
setLoginStep(LOGIN_STEPS.WX_LOGGED)
console.log('保存微信登录数据:', { code, step: LOGIN_STEPS.WX_LOGGED })
}
/**
* 保存手机号授权信息
* @param {Object} phoneData 手机号数据
*/
export const savePhoneAuthData = (phoneData) => {
const { token, refreshToken, userInfo } = phoneData
if (token) {
uni.setStorageSync(STORAGE_KEYS.TOKEN, token)
}
if (refreshToken) {
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, refreshToken)
}
if (userInfo) {
if (userInfo.phoneNumber) {
uni.setStorageSync(STORAGE_KEYS.PHONE_NUMBER, userInfo.phoneNumber)
}
// 保存微信用户信息供后续使用
const wxUserInfo = {
phoneNumber: userInfo.phoneNumber || '',
openid: userInfo.openid || '',
nickName: userInfo.nickName || '',
avatarUrl: userInfo.avatarUrl || ''
}
uni.setStorageSync(STORAGE_KEYS.WX_USER_INFO, wxUserInfo)
uni.setStorageSync(STORAGE_KEYS.USER_INFO, userInfo)
}
// 根据用户信息完善状态设置登录步骤
if (userInfo && userInfo.profileCompleted) {
setLoginStep(LOGIN_STEPS.PROFILE_COMPLETED)
} else {
setLoginStep(LOGIN_STEPS.PHONE_AUTHED)
}
console.log('保存手机号授权数据:', { token: !!token, refreshToken: !!refreshToken, userInfo: !!userInfo })
}
/**
* 标记手机号授权被跳过
*/
export const markPhoneSkipped = () => {
setLoginStep(LOGIN_STEPS.PHONE_SKIPPED)
console.log('标记手机号授权被跳过')
}
/**
* 保存用户信息完善数据
* @param {Object} profileData 用户信息数据
*/
export const saveProfileData = (profileData) => {
uni.setStorageSync(STORAGE_KEYS.USER_INFO, profileData)
setLoginStep(LOGIN_STEPS.PROFILE_COMPLETED)
console.log('保存用户信息完善数据:', profileData)
}
/**
* 清理登录流程中的临时数据
*/
export const clearTempLoginData = () => {
// 清理临时数据,保留重要的用户信息
uni.removeStorageSync(STORAGE_KEYS.WX_LOGIN_CODE)
console.log('清理临时登录数据')
}
/**
* 检查并验证token有效性
* @returns {Promise<boolean>} token是否有效
*/
export const validateToken = async () => {
const token = uni.getStorageSync(STORAGE_KEYS.TOKEN)
if (!token) {
return false
}
try {
// 调用一个简单的API来验证token
const { getUserInfo } = await import('@/http/api/profile.js')
await getUserInfo({
custom: {
loading: false,
toast: false
}
})
return true
} catch (error) {
console.log('Token验证失败:', error)
return false
}
}
/**
* 尝试刷新token
* @returns {Promise<boolean>} 是否刷新成功
*/
export const tryRefreshToken = async () => {
const refreshToken = uni.getStorageSync(STORAGE_KEYS.REFRESH_TOKEN)
if (!refreshToken) {
return false
}
try {
const { refreshToken: refreshTokenApi } = await import('@/http/api/auth.js')
const result = await refreshTokenApi({
custom: {
loading: false,
toast: false
}
})
if (result && result.token) {
uni.setStorageSync(STORAGE_KEYS.TOKEN, result.token)
if (result.refreshToken) {
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, result.refreshToken)
}
console.log('Token刷新成功')
return true
}
return false
} catch (error) {
console.log('Token刷新失败:', error)
return false
}
}
/**
* 自动登录(用于用户再次进入小程序)
* @returns {Promise<boolean>} 是否登录成功
*/
export const autoLogin = async () => {
console.log('开始自动登录检查')
// 1. 检查token有效性
if (await validateToken()) {
console.log('Token有效自动登录成功')
return true
}
// 2. 尝试刷新token
if (await tryRefreshToken()) {
console.log('Token刷新成功自动登录成功')
return true
}
// 3. 尝试使用微信code重新登录不需要手机号授权
try {
const loginRes = await new Promise((resolve, reject) => {
uni.login({
success: resolve,
fail: reject
})
})
if (loginRes.code) {
const { wxLogin } = await import('@/http/api/auth.js')
const result = await wxLogin({
code: loginRes.code
}, {
custom: {
loading: false,
toast: false
}
})
if (result && result.token) {
// 保存新的登录信息
uni.setStorageSync(STORAGE_KEYS.TOKEN, result.token)
if (result.refreshToken) {
uni.setStorageSync(STORAGE_KEYS.REFRESH_TOKEN, result.refreshToken)
}
if (result.userInfo) {
uni.setStorageSync(STORAGE_KEYS.WX_USER_INFO, result.userInfo)
uni.setStorageSync(STORAGE_KEYS.USER_INFO, result.userInfo)
// 如果用户已完善过信息,设置为已完成状态
if (result.userInfo.profileCompleted) {
setLoginStep(LOGIN_STEPS.PROFILE_COMPLETED)
} else {
setLoginStep(LOGIN_STEPS.PHONE_AUTHED)
}
}
console.log('微信code登录成功自动登录成功')
return true
}
}
} catch (error) {
console.log('微信code登录失败:', error)
}
console.log('自动登录失败,需要用户手动登录')
return false
}
/**
* 完全重置登录状态(用于登出)
*/
export const resetLoginState = () => {
uni.removeStorageSync(STORAGE_KEYS.LOGIN_STEP)
uni.removeStorageSync(STORAGE_KEYS.WX_LOGIN_CODE)
uni.removeStorageSync(STORAGE_KEYS.TOKEN)
uni.removeStorageSync(STORAGE_KEYS.REFRESH_TOKEN)
uni.removeStorageSync(STORAGE_KEYS.PHONE_NUMBER)
uni.removeStorageSync(STORAGE_KEYS.WX_USER_INFO)
uni.removeStorageSync(STORAGE_KEYS.USER_INFO)
uni.removeStorageSync(STORAGE_KEYS.LOGIN_DATE)
console.log('重置登录状态')
}
/**
* 获取登录流程的状态信息(用于内部检查)
* @returns {Object} 状态信息
*/
const getLoginStateInfo = () => {
return {
currentStep: getCurrentLoginStep(),
wxLoginCode: uni.getStorageSync(STORAGE_KEYS.WX_LOGIN_CODE),
hasToken: !!uni.getStorageSync(STORAGE_KEYS.TOKEN),
hasPhoneNumber: !!uni.getStorageSync(STORAGE_KEYS.PHONE_NUMBER),
hasWxUserInfo: !!uni.getStorageSync(STORAGE_KEYS.WX_USER_INFO),
hasUserInfo: !!uni.getStorageSync(STORAGE_KEYS.USER_INFO),
loginDate: uni.getStorageSync(STORAGE_KEYS.LOGIN_DATE)
}
}
/**
* 检查并处理登录流程的断点续传
* @returns {string|null} 需要跳转的页面路径如果不需要跳转则返回null
*/
export const checkAndResumeLogin = () => {
const currentStep = getCurrentLoginStep()
// 如果已完成登录或未开始登录,不需要续传
if (currentStep === LOGIN_STEPS.PROFILE_COMPLETED || currentStep === LOGIN_STEPS.NOT_LOGGED) {
return null
}
// 检查数据完整性
const stateInfo = getLoginStateInfo()
console.log('检查登录断点续传:', stateInfo)
// 根据当前步骤和数据完整性决定下一步
switch (currentStep) {
case LOGIN_STEPS.WX_LOGGED:
// 检查是否有微信登录凭证
if (!stateInfo.wxLoginCode) {
console.warn('微信登录凭证丢失,重置登录状态')
setLoginStep(LOGIN_STEPS.NOT_LOGGED)
return null
}
// 检查登录凭证是否过期超过30分钟
const loginDate = uni.getStorageSync(STORAGE_KEYS.LOGIN_DATE)
if (loginDate) {
const loginTime = new Date(loginDate).getTime()
const now = new Date().getTime()
const timeDiff = now - loginTime
// 如果超过30分钟认为登录凭证过期
if (timeDiff > 30 * 60 * 1000) {
console.warn('微信登录凭证已过期,重置登录状态')
setLoginStep(LOGIN_STEPS.NOT_LOGGED)
return null
}
}
return '/pages/auth/phone-auth'
case LOGIN_STEPS.PHONE_AUTHED:
// 检查是否有token
if (!stateInfo.hasToken) {
console.warn('Token丢失回退到手机号授权')
setLoginStep(LOGIN_STEPS.WX_LOGGED)
return '/pages/auth/phone-auth'
}
return '/pages/profile/user-info?mode=setup'
case LOGIN_STEPS.PHONE_SKIPPED:
return '/pages/profile/user-info?mode=setup&phoneSkipped=true'
default:
console.warn('未知的登录步骤:', currentStep)
setLoginStep(LOGIN_STEPS.NOT_LOGGED)
return null
}
}