2026-04-17 15:45:54 +08:00
|
|
|
|
// 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 || 'away')
|
|
|
|
|
|
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()
|
|
|
|
|
|
} catch (error: any) {
|
2026-04-17 22:35:22 +08:00
|
|
|
|
throw new Error('邮箱或密码错误')
|
2026-04-17 15:45:54 +08:00
|
|
|
|
} 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) {
|
2026-04-17 22:35:22 +08:00
|
|
|
|
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(';'))
|
|
|
|
|
|
}
|
2026-04-17 15:45:54 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|