topfans/frontend/store/modules/user.js

243 lines
7.4 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.

import { loginApi, registerApi, getOssPresignedUrlApi } from '@/utils/api'
import { downloadAndCacheAvatar } from '@/utils/avatarCache'
import { resetAllGuides } from '@/utils/guideConfig'
const state = {
token: uni.getStorageSync('access_token') || '',
starId: uni.getStorageSync('star_id') || null,
userInfo: (() => {
const userStr = uni.getStorageSync('user')
if (userStr) {
try {
return JSON.parse(userStr)
} catch (e) {
return null
}
}
return null
})()
}
const getters = {
isLoggedIn: (state) => {
return !!state.token
}
}
const mutations = {
SET_TOKEN(state, token) {
state.token = token
// 缓存到 storage
if (token) {
uni.setStorageSync('access_token', token)
} else {
uni.removeStorageSync('access_token')
}
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo
// 缓存到 storage
if (userInfo) {
uni.setStorageSync('user', JSON.stringify(userInfo))
// 单独缓存 star_id方便其他地方直接读取
const starId = userInfo?.fan_identity?.star_id ?? null
state.starId = starId
if (starId !== null) {
uni.setStorageSync('star_id', starId)
} else {
uni.removeStorageSync('star_id')
}
} else {
uni.removeStorageSync('user')
uni.removeStorageSync('star_id')
state.starId = null
}
},
CLEAR_AUTH(state) {
state.token = ''
state.userInfo = null
state.starId = null
// 获取当前 userId 用于清除引导数据(需要在清除 user 数据之前获取)
const userStr = uni.getStorageSync('user')
let userId = null
if (userStr) {
try {
const user = JSON.parse(userStr)
userId = user?.uid || null
} catch (e) {}
}
// 清除所有引导相关存储(传入 userId 确保正确清除)
resetAllGuides(userId)
// 清除 storage
uni.removeStorageSync('access_token')
uni.removeStorageSync('user')
uni.removeStorageSync('star_id')
// 清除登录手机号
uni.removeStorageSync('login_mobile')
// 清除 gallery_owner_id
uni.removeStorageSync('gallery_owner_id')
// 清除每日登录打卡记录
const today = new Date().toISOString().split('T')[0]
uni.removeStorageSync(`daily_login_completed_${today}`)
}
}
const actions = {
// 登录
async login({ commit }, { mobile, password }) {
try {
const res = await loginApi(mobile, password)
if (res.code === 200 && res.data) {
// 缓存 access_token
const accessToken = res.data.access_token
uni.setStorageSync('access_token', accessToken)
commit('SET_TOKEN', accessToken)
// 缓存用户信息
const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号)
const loginMobile = user.mobile_masked || mobile
uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user))
commit('SET_USER_INFO', user)
// 处理头像缓存
if (user.avatar_url) {
try {
// 获取真实的预签名URL
const urlRes = await getOssPresignedUrlApi(user.avatar_url, 3600, 'avatar')
if (urlRes.code === 200 && urlRes.data && urlRes.data.url) {
// 下载并缓存头像
const localPath = await downloadAndCacheAvatar(user.avatar_url, urlRes.data.url)
// 触发头像更新事件通知Header刷新
setTimeout(() => {
uni.$emit('avatarUpdated', {
uid: user.uid,
avatarUrl: user.avatar_url,
localPath: localPath
})
}, 100)
}
} catch (avatarError) {
console.error('头像缓存失败,但不影响登录:', avatarError)
// 头像缓存失败不影响登录流程
}
}
return Promise.resolve(res)
} else {
// 返回错误信息,包含 message
return Promise.reject(new Error(res.message || '登录失败'))
}
} catch (error) {
// 处理网络错误或HTTP错误
// 如果错误响应包含 message使用它否则使用默认错误信息
if (error.message) {
return Promise.reject(new Error(error.message))
}
return Promise.reject(new Error('登录失败,请检查网络连接'))
}
},
// 注册
async register({ commit }, { mobile, password, star_id, nickname }) {
try {
const res = await registerApi(mobile, password, star_id, nickname)
if (res.code === 200 && res.data) {
// 缓存 access_token
const accessToken = res.data.access_token
uni.setStorageSync('access_token', accessToken)
commit('SET_TOKEN', accessToken)
// 缓存用户信息
const user = res.data.user
// 缓存登录手机号(优先使用后端返回的脱敏手机号)
const loginMobile = user.mobile_masked || mobile
uni.setStorageSync('login_mobile', loginMobile)
uni.setStorageSync('user', JSON.stringify(user))
commit('SET_USER_INFO', user)
// 处理头像缓存
if (user.avatar_url) {
try {
// 获取真实的预签名URL
const urlRes = await getOssPresignedUrlApi(user.avatar_url, 3600, 'avatar')
if (urlRes.code === 200 && urlRes.data && urlRes.data.url) {
// 下载并缓存头像
const localPath = await downloadAndCacheAvatar(user.avatar_url, urlRes.data.url)
// 触发头像更新事件通知Header刷新
setTimeout(() => {
uni.$emit('avatarUpdated', {
uid: user.uid,
avatarUrl: user.avatar_url,
localPath: localPath
})
}, 100)
}
} catch (avatarError) {
console.error('头像缓存失败,但不影响注册:', avatarError)
// 头像缓存失败不影响注册流程
}
}
return Promise.resolve(res)
} else {
// 处理昵称已存在的情况
if (res.code === 409) {
return Promise.reject({ code: 409, message: res.message || '昵称已存在' })
}
return Promise.reject(new Error(res.message || '注册失败'))
}
} catch (error) {
// 处理HTTP 409错误
if (error.statusCode === 409 || error.code === 409) {
return Promise.reject({ code: 409, message: error.message || '昵称已存在' })
}
return Promise.reject(error)
}
},
// 登出
logout({ commit }) {
commit('CLEAR_AUTH')
},
// 检查登录状态(从 storage 恢复)
checkLoginStatus({ commit, state }) {
// 从 storage 恢复 token
const token = uni.getStorageSync('access_token')
if (token && token !== state.token) {
commit('SET_TOKEN', token)
}
// 从 storage 恢复 userInfo
const userStr = uni.getStorageSync('user')
if (userStr) {
try {
const userInfo = JSON.parse(userStr)
if (userInfo && (!state.userInfo || JSON.stringify(userInfo) !== JSON.stringify(state.userInfo))) {
commit('SET_USER_INFO', userInfo)
}
} catch (e) {
console.error('恢复用户信息失败:', e)
}
}
}
}
export default {
namespaced: true,
state,
getters,
mutations,
actions
}