157 lines
3.9 KiB
JavaScript
157 lines
3.9 KiB
JavaScript
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,
|
||
}
|
||
})
|