user.js 4.18 KB
/**
 * 用户状态管理
 *
 * @description 管理用户登录状态、用户信息等
 * @module stores/user
 */

import { defineStore } from 'pinia'
import { ref } from 'vue'
import Taro from '@tarojs/taro'
import { loginStatusAPI, loginAPI, getProfileAPI, logoutAPI } from '@/api/user'
import { ensureOpenidAuthorized } from '@/utils/openid'

export const useUserStore = defineStore('user', () => {
  // ========== 状态 ==========
  /** 用户信息 */
  const userInfo = ref(null)

  /** 是否已授权(openid) */
  const isOpenid = ref(false)

  /** 是否已登录 */
  const isLoggedIn = ref(false)

  /** 加载状态 */
  const loading = ref(false)

  // ========== 方法 ==========

  /**
   * 检查登录状态
   * @description 小程序启动时检查 openid 和登录状态
   * - 只触发微信授权,不跳转登录页
   * - 401 由接口拦截器统一处理
   * @throws {Error} 检查失败时抛出错误
   *
   * @example
   * await userStore.checkLoginStatus()
   */
  async function checkLoginStatus() {
    loading.value = true

    try {
      // 1. 确保 openid 已授权并尝试自动登录
      const user = await ensureOpenidAuthorized()

      if (user) {
        // miniProgramAuthAPI 返回了用户信息,说明已自动登录
        userInfo.value = user
        isOpenid.value = true
        isLoggedIn.value = true
        return
      }

      // 2. 查询登录状态
      const res = await loginStatusAPI()

      if (res.code === 1) {
        isOpenid.value = res.data.is_openid
        isLoggedIn.value = res.data.is_login

        // 3. 如果已登录,获取用户信息
        if (isLoggedIn.value) {
          await fetchUserInfo()
        }
        // 注意:这里不跳转登录页,让用户可以浏览小程序
        // 当用户操作触发接口返回 401 时,会自动跳转登录页
      } else {
        throw new Error(res.msg || '查询登录状态失败')
      }
    } catch (err) {
      console.error('检查登录状态失败:', err)
      throw err
    } finally {
      loading.value = false
    }
  }

  /**
   * 获取用户信息
   * @description 调用 getProfileAPI 获取用户信息
   * @throws {Error} 获取失败时抛出错误
   *
   * @example
   * await userStore.fetchUserInfo()
   */
  async function fetchUserInfo() {
    try {
      const res = await getProfileAPI()

      if (res.code === 1) {
        userInfo.value = res.data.user
      } else {
        throw new Error(res.msg || '获取用户信息失败')
      }
    } catch (err) {
      console.error('获取用户信息失败:', err)
      throw err
    }
  }

  /**
   * 用户登录
   * @description 调用 loginAPI 进行账号密码登录
   * @param {Object} loginData 登录数据
   * @param {string} loginData.uuid 账号
   * @param {string} loginData.password 密码
   * @returns {{success: boolean, message?: string}} 登录结果
   *
   * @example
   * const result = await userStore.login({
   *   uuid: '13800138000',
   *   password: '123456'
   * })
   * if (result.success) {
   *   console.log('登录成功')
   * }
   */
  async function login(loginData) {
    loading.value = true

    try {
      const res = await loginAPI(loginData)

      if (res.code === 1) {
        // 登录成功,获取用户信息
        await fetchUserInfo()

        isLoggedIn.value = true

        return { success: true }
      } else {
        throw new Error(res.msg || '登录失败')
      }
    } catch (err) {
      console.error('登录失败:', err)
      return { success: false, message: err.message }
    } finally {
      loading.value = false
    }
  }

  /**
   * 用户登出
   * @description 调用 logoutAPI 并清除本地状态
   *
   * @example
   * await userStore.logout()
   */
  async function logout() {
    try {
      // 调用登出接口
      await logoutAPI()

      // 清除本地状态
      userInfo.value = null
      isOpenid.value = false
      isLoggedIn.value = false
    } catch (err) {
      console.error('登出失败:', err)
    }
  }

  // ========== 返回 ==========
  return {
    // 状态
    userInfo,
    isOpenid,
    isLoggedIn,
    loading,

    // 方法
    checkLoginStatus,
    fetchUserInfo,
    login,
    logout
  }
})