| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- import type {
- ILoginForm,
- } from '@/api/login'
- import type { IAuthLoginRes } from '@/api/types/login'
- import { defineStore } from 'pinia'
- import { computed, ref } from 'vue' // 修复:导入 computed
- import {
- login as _login,
- logout as _logout,
- refreshToken as _refreshToken,
- wxLogin as _wxLogin,
- getUserProfile,
- getWxCode,
- } from '@/api/login'
- import { isDoubleTokenRes, isSingleTokenRes } from '@/api/types/login'
- import { isDoubleTokenMode } from '@/utils'
- import { useUserStore } from './user'
- // 初始化状态
- const tokenInfoState = isDoubleTokenMode
- ? {
- accessToken: '',
- accessExpiresIn: 0,
- refreshToken: '',
- refreshExpiresIn: 0,
- }
- : {
- token: '',
- expiresIn: 0,
- }
- export const useTokenStore = defineStore(
- 'token',
- () => {
- // 定义用户信息
- const tokenInfo = ref<IAuthLoginRes>({ ...tokenInfoState })
- // 设置用户信息
- const setTokenInfo = (val: IAuthLoginRes) => {
- tokenInfo.value = val
- // 计算并存储过期时间
- const now = Date.now()
- if (isSingleTokenRes(val)) {
- // 单token模式
- const expireTime = now + val.expiresIn * 1000
- uni.setStorageSync('accessTokenExpireTime', expireTime)
- }
- else if (isDoubleTokenRes(val)) {
- // 双token模式
- const accessExpireTime = now + val.accessExpiresIn * 1000
- const refreshExpireTime = now + val.refreshExpiresIn * 1000
- uni.setStorageSync('accessTokenExpireTime', accessExpireTime)
- uni.setStorageSync('refreshTokenExpireTime', refreshExpireTime)
- }
- }
- /**
- * 判断token是否过期
- */
- const isTokenExpired = computed(() => {
- if (!tokenInfo.value) {
- return true
- }
- const now = Date.now()
- const expireTime = uni.getStorageSync('accessTokenExpireTime')
- if (!expireTime)
- return true
- return now >= expireTime
- })
- /**
- * 判断refreshToken是否过期
- */
- const isRefreshTokenExpired = computed(() => {
- if (!isDoubleTokenMode)
- return true
- const now = Date.now()
- const refreshExpireTime = uni.getStorageSync('refreshTokenExpireTime')
- if (!refreshExpireTime)
- return true
- return now >= refreshExpireTime
- })
- /**
- * 登录成功后处理逻辑
- * @param tokenInfo 登录返回的token信息
- */
- async function _postLogin(tokenInfo: IAuthLoginRes) {
- setTokenInfo(tokenInfo)
- // const userStore = useUserStore()
- // await userStore.fetchUserInfo()
- }
- /**
- * 用户登录
- * 有的时候后端会用一个接口返回token和用户信息,有的时候会分开2个接口,一个获取token,一个获取用户信息
- * (各有利弊,看业务场景和系统复杂度),这里使用2个接口返回的来模拟
- * @param loginForm 登录参数
- * @returns 登录结果
- */
- const login = async (loginForm: ILoginForm) => {
- try {
- const res = await _login(loginForm)
- console.log('普通登录-res: ', res)
- await _postLogin(res)
- uni.showToast({
- title: '登录成功',
- icon: 'success',
- })
- return res
- }
- catch (error) {
- console.error('登录失败:', error)
- uni.showToast({
- title: '登录失败,请重试',
- icon: 'error',
- })
- throw error
- }
- }
- /**
- * 微信登录
- * 有的时候后端会用一个接口返回token和用户信息,有的时候会分开2个接口,一个获取token,一个获取用户信息
- * (各有利弊,看业务场景和系统复杂度),这里使用2个接口返回的来模拟
- * @returns 登录结果
- */
- const wxLogin = async () => {
- try {
- // 获取用户信息
- const profile = await getUserProfile()
- console.log('微信登录-profile: ', profile)
- // 获取微信小程序登录的code
- const code = await getWxCode()
- console.log('微信登录-code: ', code.code)
- const res = await _wxLogin(code.code)
- console.log('微信登录-res: ', res)
- await _postLogin(res)
- uni.showToast({
- title: '登录成功',
- icon: 'success',
- })
- return res
- }
- catch (error) {
- console.error('微信登录失败:', error)
- uni.showToast({
- title: '微信登录失败,请重试',
- icon: 'error',
- })
- throw error
- }
- }
- /**
- * 退出登录 并 删除用户信息
- */
- const logout = async () => {
- try {
- // TODO 实现自己的退出登录逻辑
- await _logout()
- }
- catch (error) {
- console.error('退出登录失败:', error)
- }
- finally {
- // 无论成功失败,都需要清除本地token信息
- // 清除存储的过期时间
- uni.removeStorageSync('accessTokenExpireTime')
- uni.removeStorageSync('refreshTokenExpireTime')
- console.log('退出登录-清除用户信息')
- tokenInfo.value = { ...tokenInfoState }
- uni.removeStorageSync('token')
- const userStore = useUserStore()
- userStore.clearUserInfo()
- }
- }
- /**
- * 刷新token
- * @returns 刷新结果
- */
- const refreshToken = async () => {
- if (!isDoubleTokenMode) {
- console.error('单token模式不支持刷新token')
- throw new Error('单token模式不支持刷新token')
- }
- try {
- // 安全检查,确保refreshToken存在
- if (!isDoubleTokenRes(tokenInfo.value) || !tokenInfo.value.refreshToken) {
- throw new Error('无效的refreshToken')
- }
- const refreshToken = tokenInfo.value.refreshToken
- const res = await _refreshToken(refreshToken)
- console.log('刷新token-res: ', res)
- setTokenInfo(res)
- return res
- }
- catch (error) {
- console.error('刷新token失败:', error)
- throw error
- }
- }
- /**
- * 获取有效的token
- * 注意:在computed中不直接调用异步函数,只做状态判断
- * 实际的刷新操作应由调用方处理
- */
- const getValidToken = computed(() => {
- // token已过期,返回空
- if (isTokenExpired.value) {
- return ''
- }
- console.log('getValidToken', tokenInfo.value)
- if (!isDoubleTokenMode) {
- return isSingleTokenRes(tokenInfo.value) ? tokenInfo.value.token : ''
- }
- else {
- return isDoubleTokenRes(tokenInfo.value) ? tokenInfo.value.accessToken : ''
- }
- })
- /**
- * 检查是否有登录信息(不考虑token是否过期)
- */
- const hasLoginInfo = computed(() => {
- if (!tokenInfo.value) {
- return false
- }
- if (isDoubleTokenMode) {
- return isDoubleTokenRes(tokenInfo.value) && !!tokenInfo.value.accessToken
- }
- else {
- return isSingleTokenRes(tokenInfo.value) && !!tokenInfo.value.token
- }
- })
- /**
- * 检查是否已登录且token有效
- */
- const hasValidLogin = computed(() => {
- console.log('hasValidLogin', hasLoginInfo.value && !isTokenExpired.value, hasLoginInfo.value, !isTokenExpired.value)
- return hasLoginInfo.value && !isTokenExpired.value
- })
- /**
- * 尝试获取有效的token,如果过期且可刷新,则刷新token
- * @returns 有效的token或空字符串
- */
- const tryGetValidToken = async (): Promise<string> => {
- if (!getValidToken.value && isDoubleTokenMode && !isRefreshTokenExpired.value) {
- try {
- await refreshToken()
- return getValidToken.value
- }
- catch (error) {
- console.error('尝试刷新token失败:', error)
- return ''
- }
- }
- return getValidToken.value
- }
- return {
- // 核心API方法
- login,
- wxLogin,
- logout,
- // 认证状态判断(最常用的)
- hasLogin: hasValidLogin,
- // 内部系统使用的方法
- refreshToken,
- tryGetValidToken,
- validToken: getValidToken,
- // 调试或特殊场景可能需要直接访问的信息
- tokenInfo,
- setTokenInfo,
- }
- },
- {
- // 添加持久化配置,确保刷新页面后token信息不丢失
- persist: true,
- },
- )
|