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:
@@ -0,0 +1,116 @@
|
||||
// src/api/invitations.ts
|
||||
import pb from './pocketbase'
|
||||
import type { Invitation, InviteStatus } from '@/types'
|
||||
import { joinTeamSession } from './sessions'
|
||||
import { updateUserStatus } from './users'
|
||||
|
||||
// 发送邀请
|
||||
export async function sendInvitation(data: {
|
||||
to: string
|
||||
teamSession: string
|
||||
}) {
|
||||
const user = pb.authStore.model
|
||||
if (!user) throw new Error('未登录')
|
||||
|
||||
// 检查是否已有待处理邀请
|
||||
const existing = await pb.collection('invitations').getList(1, 1, {
|
||||
filter: `from="${user.id}" && to="${data.to}" && teamSession="${data.teamSession}" && status="pending"`
|
||||
})
|
||||
|
||||
if (existing.items.length > 0) {
|
||||
throw new Error('已有待处理的邀请')
|
||||
}
|
||||
|
||||
return pb.collection('invitations').create({
|
||||
...data,
|
||||
from: user.id,
|
||||
status: 'pending'
|
||||
})
|
||||
}
|
||||
|
||||
// 批量发送邀请
|
||||
export async function sendBulkInvitations(recipients: string[], teamSessionId: string) {
|
||||
const promises = recipients.map(to =>
|
||||
sendInvitation({ to, teamSession: teamSessionId })
|
||||
)
|
||||
|
||||
return Promise.allSettled(promises)
|
||||
}
|
||||
|
||||
// 获取用户的待处理邀请
|
||||
export async function getPendingInvitations(): Promise<Invitation[]> {
|
||||
const user = pb.authStore.model
|
||||
if (!user) return []
|
||||
|
||||
const result = await pb.collection('invitations').getList(1, 50, {
|
||||
filter: `to="${user.id}" && status="pending"`,
|
||||
sort: '-created',
|
||||
expand: 'from,teamSession'
|
||||
})
|
||||
|
||||
return result.items as unknown as Invitation[]
|
||||
}
|
||||
|
||||
// 获取我发送的邀请
|
||||
export async function getMySentInvitations(): Promise<Invitation[]> {
|
||||
const user = pb.authStore.model
|
||||
if (!user) return []
|
||||
|
||||
const result = await pb.collection('invitations').getList(1, 50, {
|
||||
filter: `from="${user.id}"`,
|
||||
sort: '-created',
|
||||
expand: 'to,teamSession'
|
||||
})
|
||||
|
||||
return result.items as unknown as Invitation[]
|
||||
}
|
||||
|
||||
// 响应邀请
|
||||
export async function respondInvitation(
|
||||
invitationId: string,
|
||||
response: 'accepted' | 'rejected',
|
||||
rejectReason?: string
|
||||
) {
|
||||
const user = pb.authStore.model
|
||||
if (!user) throw new Error('未登录')
|
||||
|
||||
const invitation = await pb.collection('invitations').getOne(invitationId)
|
||||
|
||||
if (invitation.to !== user.id) {
|
||||
throw new Error('无权操作此邀请')
|
||||
}
|
||||
|
||||
const updateData: Partial<Invitation> = {
|
||||
status: response as InviteStatus,
|
||||
respondedAt: new Date().toISOString()
|
||||
}
|
||||
|
||||
if (response === 'rejected' && rejectReason) {
|
||||
updateData.rejectReason = rejectReason
|
||||
}
|
||||
|
||||
// 更新邀请状态
|
||||
await pb.collection('invitations').update(invitationId, updateData)
|
||||
|
||||
// 如果接受,加入临时小组
|
||||
if (response === 'accepted') {
|
||||
await joinTeamSession(invitation.teamSession)
|
||||
// 更新用户状态
|
||||
await updateUserStatus('in_team')
|
||||
}
|
||||
|
||||
return updateData
|
||||
}
|
||||
|
||||
// 订阅邀请变更
|
||||
export function subscribeInvitations(callback: (invitation: Invitation) => void) {
|
||||
const user = pb.authStore.model
|
||||
if (!user) return () => {}
|
||||
|
||||
return pb.collection('invitations').subscribe('*', (payload) => {
|
||||
const invite = payload.record as unknown as Invitation
|
||||
if (invite.to === user.id || invite.from === user.id) {
|
||||
callback(invite)
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user