Files
gamegroup2/frontend/src/stores/user.ts
T
congsh 6b684f8600 fix: login persistence, username login, realtime refresh, group name uniqueness
- Remove loadFromCookie that overwrites valid localStorage auth data
- Set user status to idle on first login (was empty string)
- Default empty status to idle instead of away

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 09:56:11 +08:00

136 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// src/stores/user.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import type { User, UserStatus, WorkSchedule } from '@/types'
import { pb, getCurrentUser, isAuthenticated, logout as pbLogout } from '@/api/pocketbase'
import { getUser, updateUserStatus, updateWorkSchedule } from '@/api/users'
export const useUserStore = defineStore('user', () => {
// 状态
const user = ref<User | null>(null)
const loading = ref(false)
// 计算属性
const isLoggedIn = computed(() => isAuthenticated() && user.value !== null)
const userStatus = computed(() => user.value?.status || 'idle')
const userId = computed(() => user.value?.id || '')
// 初始化用户信息
async function initUser() {
if (!isAuthenticated()) {
user.value = null
return
}
try {
loading.value = true
const authUser = getCurrentUser() as User
// 获取完整用户信息
user.value = await getUser(authUser.id)
} catch (error) {
console.error('初始化用户信息失败:', error)
user.value = null
} finally {
loading.value = false
}
}
// 登录
async function login(email: string, password: string) {
try {
loading.value = true
await pb.collection('users').authWithPassword(email, password)
await initUser()
// 首次登录设置默认状态为空闲
if (user.value && !user.value.status) {
await setStatus('idle')
}
} catch (error: any) {
throw new Error('邮箱或密码错误')
} finally {
loading.value = false
}
}
// 注册
async function register(data: { email: string; password: string; passwordConfirm: string; username: string }) {
try {
loading.value = true
await pb.collection('users').create(data)
await login(data.email, data.password)
} catch (error: any) {
const validation = error?.data?.data || error?.data
if (validation) {
const messages: string[] = []
if (validation.email) messages.push('邮箱无效或已被使用')
if (validation.username) messages.push('用户名无效或已被使用')
if (validation.password) messages.push('密码不符合要求')
if (messages.length > 0) throw new Error(messages.join(''))
}
throw new Error(error.message || '注册失败')
} finally {
loading.value = false
}
}
// 登出
function logout() {
pbLogout()
user.value = null
}
// 更新状态
async function setStatus(status: UserStatus, note?: string) {
try {
const updated = await updateUserStatus(status, note)
if (user.value) {
user.value.status = status
user.value.statusNote = note
}
return updated
} catch (error: any) {
throw new Error(error.message || '更新状态失败')
}
}
// 更新工作时间
async function setWorkSchedule(schedule: WorkSchedule) {
try {
const updated = await updateWorkSchedule(schedule)
if (user.value) {
user.value.workdays = schedule.workdays
user.value.workStartTime = schedule.workStartTime
user.value.nextWorkTime = updated.nextWorkTime
}
return updated
} catch (error: any) {
throw new Error(error.message || '更新工作时间失败')
}
}
// 检查并自动更新工作时间状态
function checkWorkSchedule() {
if (!user.value || !user.value.nextWorkTime) return
const now = Math.floor(Date.now() / 1000)
if (now >= user.value.nextWorkTime && user.value.status === 'idle') {
setStatus('working')
}
}
return {
user,
loading,
isLoggedIn,
userStatus,
userId,
initUser,
login,
register,
logout,
setStatus,
setWorkSchedule,
checkWorkSchedule
}
})