Source: stores/modules/user.js

/**
 * @file stores/modules/userStore.js
 * @description Pinia Store,用于管理用户认证状态、用户信息和用户偏好设置(如会话免打扰)。
 * 该 Store 的状态支持持久化。
 * @module UserStore
 */

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { toggleMuteConversation } from '../../api/chat' // 导入切换免打扰 API
import { ElMessage } from 'element-plus' // 导入 Element Plus 消息组件

/**
 * @const {object} defaultUserInfo
 * @description 默认的用户信息对象,用于初始化或重置用户状态。
 * @property {string} username - 默认用户名。
 * @property {string} userId - 默认用户ID。
 * @property {string} avatar - 默认用户头像URL。
 */
const defaultUserInfo = {
  username: '用户',
  userId: '',
  avatar: import.meta.env.VITE_DEFAULT_USER_AVATAR
}

/**
 * @function useUserStore
 * @description Pinia Store,用于管理用户的认证状态、个人信息以及聊天免打扰设置。
 * 该 Store 的状态会被持久化到本地存储。
 * @returns {{
 * token: Ref<string>,
 * userInfo: Ref<object>,
 * isLoggedIn: ComputedRef<boolean>,
 * isMuted: ComputedRef<Function>,
 * setToken: Function,
 * setUserInfo: Function,
 * toggleMute: Function,
 * logout: Function
 * }}
 * @property {Ref<string>} token - 用户的认证 token。
 * @property {Ref<object>} userInfo - 用户的详细信息,包括用户名、ID、头像等。
 * @property {ComputedRef<boolean>} isLoggedIn - 计算属性,判断用户是否已登录。
 * @property {ComputedRef<Function>} isMuted - 计算属性,返回一个函数,用于检查指定会话是否处于免打扰状态。
 * @property {Function} setToken - 设置用户的认证 token。
 * @property {Function} setUserInfo - 设置用户的详细信息,并同步免打扰会话列表。
 * @property {Function} toggleMute - 切换指定会话的免打扰状态。
 * @property {Function} logout - 执行用户登出操作,清除所有用户相关状态。
 */
export const useUserStore = defineStore(
  'user',
  () => {
    // --- 状态 (State) ---
    /**
     * @type {Ref<object>}
     * @description 当前登录用户的详细信息。
     */
    const userInfo = ref({ ...defaultUserInfo })
    /**
     * @type {Ref<string>}
     * @description 当前用户的认证 token。
     */
    const token = ref('')
    /**
     * @type {Ref<Set<string>>}
     * @description 存储用户已设置为免打扰的会话ID集合。
     */
    const mutedConversations = ref(new Set())

    // --- 计算属性 (Getters) ---

    /**
     * @type {ComputedRef<boolean>}
     * @description 判断用户是否已登录(通过检查 token 是否存在)。
     */
    const isLoggedIn = computed(() => !!token.value)

    /**
     * @type {ComputedRef<Function>}
     * @description 返回一个函数,该函数接受 `conversationId`,用于检查对应会话是否已设置为免打扰。
     * @returns {function(string): boolean} 检查函数。
     */
    const isMuted = computed(() => {
      return (conversationId) => {
        if (!conversationId) return false
        return mutedConversations.value.has(conversationId)
      }
    })

    // --- 操作 (Actions) ---

    /**
     * @function setToken
     * @description 设置用户的认证 token。
     * @param {string} newToken - 新的认证 token 字符串。
     * @returns {void}
     */
    const setToken = (newToken) => {
      token.value = newToken
    }

    /**
     * @function setUserInfo
     * @description 设置用户的详细信息。
     * 如果新用户信息包含 `mutedConversations` 数组,则同步更新本地的免打扰会话集合。
     * @param {object} newUserInfo - 包含用户详细信息的新对象。
     * @param {string} newUserInfo.username - 用户名。
     * @param {string} newUserInfo.userId - 用户ID。
     * @param {string} newUserInfo.avatar - 用户头像URL。
     * @param {Array<string>} [newUserInfo.mutedConversations] - 用户已设置免打扰的会话ID列表。
     * @returns {void}
     */
    const setUserInfo = (newUserInfo) => {
      Object.assign(userInfo.value, newUserInfo) // 更新用户基本信息
      // 如果新信息包含免打扰列表,则将其转换为 Set 并更新
      if (
        newUserInfo.mutedConversations &&
        Array.isArray(newUserInfo.mutedConversations)
      ) {
        mutedConversations.value = new Set(newUserInfo.mutedConversations)
      }
    }

    /**
     * @function toggleMute
     * @description 切换指定会话的免打扰状态。
     * 会同时更新本地状态和调用后端 API。如果 API 调用失败,会回滚本地状态。
     * @param {string} conversationId - 要切换免打扰状态的会话 ID。
     * @param {boolean} mute - 如果为 `true` 则设为免打扰,如果为 `false` 则取消免打扰。
     * @returns {Promise<void>}
     * @throws {Error} 如果切换免打扰状态的 API 请求失败,会打印错误信息并显示提示。
     */
    const toggleMute = async (conversationId, mute) => {
      // 乐观更新:先更新本地状态,提供即时反馈
      if (mute) {
        mutedConversations.value.add(conversationId)
      } else if (mute === false) {
        mutedConversations.value.delete(conversationId)
      }

      try {
        await toggleMuteConversation({ conversationId, mute }) // 调用 API 更新后端状态
      } catch (error) {
        console.error('切换免打扰状态失败', error)
        // 如果 API 调用失败,回滚本地状态
        if (mute) {
          mutedConversations.value.delete(conversationId)
        } else if (mute === false) {
          mutedConversations.value.add(conversationId)
        }
        ElMessage.error('切换免打扰状态失败,请稍后重试')
      }
    }

    /**
     * @function logout
     * @description 执行用户登出操作。
     * 清除本地 token、用户信息和免打扰会话列表,并移除 localStorage 中的 token。
     * @returns {void}
     */
    const logout = () => {
      token.value = ''
      userInfo.value = { ...defaultUserInfo } // 重置为默认用户信息
      localStorage.removeItem('token') // 清除 localStorage 中的 token
      mutedConversations.value.clear() // 清空免打扰会话列表
    }

    // --- 返回 Store 的状态、计算属性和操作 ---
    return {
      token,
      userInfo,
      isLoggedIn,
      isMuted,
      setToken,
      setUserInfo,
      toggleMute,
      logout
    }
  },
  {
    // 该 Store 的所有状态都会被持久化到本地存储
    persist: true
  }
)