366 lines
9.9 KiB
JavaScript
366 lines
9.9 KiB
JavaScript
/**
|
||
* 登录状态管理工具
|
||
* 用于管理用户登录流程中的状态和数据传递
|
||
*/
|
||
|
||
// 登录步骤常量
|
||
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)
|
||
}
|
||
|
||
/**
|
||
* 清理登录流程中的临时数据
|
||
* @deprecated 使用 http/utils/auth-helper.js 中的 clearTempLoginData 替代
|
||
*/
|
||
export const clearTempLoginData = () => {
|
||
const { clearTempLoginData } = require('../http/utils/auth-helper.js')
|
||
clearTempLoginData()
|
||
}
|
||
|
||
/**
|
||
* 检查并验证token有效性
|
||
* @returns {Promise<boolean>} token是否有效
|
||
* @deprecated 使用 http/utils/auth-helper.js 中的 validateToken 替代
|
||
*/
|
||
export const validateToken = async () => {
|
||
const { validateToken } = await import('../http/utils/auth-helper.js')
|
||
return await validateToken()
|
||
}
|
||
|
||
/**
|
||
* 尝试刷新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
|
||
}
|
||
}
|