feat: add GameGroup2 project with frontend and backend

- Add .gitignore for Node.js and PocketBase projects
- Add frontend (Vue 3 + Vite + TypeScript)
- Add backend (PocketBase)
- Add deployment scripts and Docker compose configs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
congsh
2026-04-17 15:45:54 +08:00
parent 2db391901c
commit 2ce8985747
56 changed files with 3981 additions and 783 deletions
+123
View File
@@ -0,0 +1,123 @@
// 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) {
throw new Error(error.message || '登录失败')
} 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) {
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
}
})