Files
competition-website/src/stores/auth.js

157 lines
3.9 KiB
JavaScript
Raw Normal View History

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { useRouter } from 'vue-router'
import * as authApi from '@/api/auth'
// ==================== 认证状态管理 ====================
export const useAuthStore = defineStore('auth', () => {
// ==================== 状态 ====================
// 当前用户信息
const currentUser = ref(
JSON.parse(localStorage.getItem('user') || 'null')
)
// 认证令牌
const token = ref(localStorage.getItem('token') || '')
// ==================== 计算属性(Getters) ====================
// 是否已登录
const isLoggedIn = computed(() => !!token.value)
// 是否为管理员
const isAdmin = computed(() => {
if (!currentUser.value) return false
return (
currentUser.value.role === 'admin' ||
currentUser.value.isAdmin === true
)
})
// 用户名称(优先显示姓名,其次用户名)
const userName = computed(() => {
if (!currentUser.value) return ''
return currentUser.value.name || currentUser.value.username || ''
})
// 用户所属组别
const userGroup = computed(() => {
return currentUser.value?.group || ''
})
// ==================== 私有辅助方法 ====================
/**
* 持久化存储 token 和用户信息到 localStorage
*/
function persistAuth(tokenValue, userData) {
token.value = tokenValue
currentUser.value = userData
localStorage.setItem('token', tokenValue)
localStorage.setItem('user', JSON.stringify(userData))
}
/**
* 清除本地存储的认证信息
*/
function clearAuth() {
token.value = ''
currentUser.value = null
localStorage.removeItem('token')
localStorage.removeItem('user')
}
// ==================== 操作方法(Actions) ====================
/**
* 参赛者登录(身份证号 + 密码)
* @param {string} idNumber - 身份证号
* @param {string} password - 密码
* @returns {Promise<object>} 用户信息
*/
async function login(phone, password) {
const result = await authApi.login(phone, password)
// 后端应返回 { token, user }
persistAuth(result.token, result.user)
return result.user
}
/**
* 管理员登录
* @param {string} username - 管理员用户名
* @param {string} password - 密码
* @returns {Promise<object>} 管理员信息
*/
async function adminLogin(username, password) {
const result = await authApi.adminLogin(username, password)
// 后端应返回 { token, user }
persistAuth(result.token, result.user)
return result.user
}
/**
* 激活账号(设置密码)
* @param {object} data - { phone, password, smsCode }
* @returns {Promise}
*/
async function activate(data) {
const result = await authApi.activate(data)
// 激活成功后自动登录
if (result.token && result.user) {
persistAuth(result.token, result.user)
}
return result
}
/**
* 退出登录
*/
async function logout() {
try {
// 尝试通知后端登出
await authApi.logout()
} catch (e) {
// 即使后端请求失败,也清除本地状态
console.warn('登出请求失败,仍将清除本地状态', e)
}
clearAuth()
// 跳转到登录页
window.location.href = '/login'
}
/**
* 从服务端获取最新用户信息
* @returns {Promise<object>} 用户信息
*/
async function fetchCurrentUser() {
const user = await authApi.getCurrentUser()
currentUser.value = user
localStorage.setItem('user', JSON.stringify(user))
return user
}
// ==================== 导出 ====================
return {
// 状态
currentUser,
token,
// 计算属性
isLoggedIn,
isAdmin,
userName,
userGroup,
// 操作
login,
adminLogin,
activate,
logout,
fetchCurrentUser,
// 工具方法
clearAuth,
persistAuth,
}
})