feat: add game library CRUD/import/export/favorites/comments, fix team creation
- Game library: add/delete games per group, JSON/CSV import/export, favorites, star ratings & comments - Fix team session creation: add creator to members array, handle null currentGroup - Fix image loading: rename SVG files from .png to .svg extensions - Add PocketBase migrations for game_comments and game_favorites collections - Remove seed data script Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+122
-65
@@ -1,88 +1,127 @@
|
||||
// src/api/games.ts
|
||||
import pb from './pocketbase'
|
||||
import type { Game, GamePlatform } from '@/types'
|
||||
import type { Game, GamePlatform, GameComment } from '@/types'
|
||||
|
||||
// 获取游戏列表
|
||||
export async function getGames(options?: {
|
||||
// 获取群组的游戏列表
|
||||
export async function getGroupGames(groupId: string, options?: {
|
||||
page?: number
|
||||
limit?: number
|
||||
platform?: GamePlatform
|
||||
search?: string
|
||||
}): Promise<{ items: Game[], total: number }> {
|
||||
const { page = 1, limit = 20, platform, search } = options || {}
|
||||
|
||||
let filter = ''
|
||||
if (platform) {
|
||||
filter = `platform="${platform}"`
|
||||
}
|
||||
if (search) {
|
||||
const searchFilter = `name ~ "${search}"`
|
||||
filter = filter ? `${filter} && ${searchFilter}` : searchFilter
|
||||
}
|
||||
const { page = 1, limit = 50, platform, search } = options || {}
|
||||
let filter = `group="${groupId}"`
|
||||
if (platform) filter += ` && platform="${platform}"`
|
||||
if (search) filter += ` && name ~ "${search}"`
|
||||
|
||||
const result = await pb.collection('games').getList(page, limit, {
|
||||
filter,
|
||||
sort: '-popularCount'
|
||||
sort: '-created'
|
||||
})
|
||||
|
||||
return {
|
||||
items: result.items as unknown as Game[],
|
||||
total: result.totalItems
|
||||
}
|
||||
return { items: result.items as unknown as Game[], total: result.totalItems }
|
||||
}
|
||||
|
||||
// 获取热门游戏
|
||||
export async function getPopularGames(limit = 10): Promise<Game[]> {
|
||||
const result = await pb.collection('games').getList(1, limit, {
|
||||
sort: '-popularCount'
|
||||
})
|
||||
|
||||
return result.items as unknown as Game[]
|
||||
}
|
||||
|
||||
// 搜索游戏
|
||||
export async function searchGames(query: string, limit = 20): Promise<Game[]> {
|
||||
if (!query.trim()) return []
|
||||
|
||||
const result = await pb.collection('games').getList(1, limit, {
|
||||
filter: `name ~ "${query}"`,
|
||||
sort: '-popularCount'
|
||||
})
|
||||
|
||||
return result.items as unknown as Game[]
|
||||
}
|
||||
|
||||
// 添加游戏(需要管理员权限)
|
||||
export async function addGame(data: {
|
||||
// 添加游戏到群组
|
||||
export async function addGame(groupId: string, data: {
|
||||
name: string
|
||||
platform: GamePlatform
|
||||
platform?: GamePlatform
|
||||
tags?: string[]
|
||||
cover?: string
|
||||
}) {
|
||||
return pb.collection('games').create(data)
|
||||
}
|
||||
|
||||
// 更新游戏热度
|
||||
export async function incrementGamePopularity(gameId: string) {
|
||||
const game = await pb.collection('games').getOne(gameId)
|
||||
return pb.collection('games').update(gameId, {
|
||||
popularCount: (game.popularCount || 0) + 1
|
||||
const user = pb.authStore.model
|
||||
return pb.collection('games').create({
|
||||
...data,
|
||||
group: groupId,
|
||||
addedBy: user?.id,
|
||||
popularCount: 0
|
||||
})
|
||||
}
|
||||
|
||||
// 获取游戏详情
|
||||
export async function getGame(gameId: string): Promise<Game> {
|
||||
return pb.collection('games').getOne(gameId) as unknown as Game
|
||||
// 删除游戏
|
||||
export async function deleteGame(gameId: string) {
|
||||
return pb.collection('games').delete(gameId)
|
||||
}
|
||||
|
||||
// 按平台获取游戏
|
||||
export async function getGamesByPlatform(platform: GamePlatform): Promise<Game[]> {
|
||||
const result = await pb.collection('games').getList(1, 50, {
|
||||
filter: `platform="${platform}"`,
|
||||
sort: '-popularCount'
|
||||
// 导入游戏(批量添加)
|
||||
export async function importGames(groupId: string, games: Array<{
|
||||
name: string
|
||||
platform?: GamePlatform
|
||||
tags?: string[]
|
||||
cover?: string
|
||||
}>) {
|
||||
const results = []
|
||||
for (const game of games) {
|
||||
try {
|
||||
const result = await addGame(groupId, game)
|
||||
results.push({ success: true, data: result })
|
||||
} catch (error: any) {
|
||||
results.push({ success: false, error: error.message, data: game })
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// 导出游戏(获取全部数据)
|
||||
export async function exportGames(groupId: string): Promise<Game[]> {
|
||||
const result = await pb.collection('games').getFullList({
|
||||
filter: `group="${groupId}"`,
|
||||
sort: '-created'
|
||||
})
|
||||
return result as unknown as Game[]
|
||||
}
|
||||
|
||||
// 收藏/取消收藏
|
||||
export async function toggleFavorite(gameId: string): Promise<boolean> {
|
||||
const user = pb.authStore.model
|
||||
if (!user) throw new Error('未登录')
|
||||
|
||||
const existing = await pb.collection('game_favorites').getList(1, 1, {
|
||||
filter: `game="${gameId}" && user="${user.id}"`
|
||||
})
|
||||
|
||||
return result.items as unknown as Game[]
|
||||
if (existing.items.length > 0) {
|
||||
await pb.collection('game_favorites').delete(existing.items[0].id)
|
||||
return false
|
||||
} else {
|
||||
await pb.collection('game_favorites').create({
|
||||
game: gameId,
|
||||
user: user.id
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已收藏
|
||||
export async function isFavorite(gameId: string): Promise<boolean> {
|
||||
const user = pb.authStore.model
|
||||
if (!user) return false
|
||||
|
||||
const result = await pb.collection('game_favorites').getList(1, 1, {
|
||||
filter: `game="${gameId}" && user="${user.id}"`
|
||||
})
|
||||
return result.items.length > 0
|
||||
}
|
||||
|
||||
// 添加评论
|
||||
export async function addComment(gameId: string, content: string, rating?: number) {
|
||||
const user = pb.authStore.model
|
||||
if (!user) throw new Error('未登录')
|
||||
|
||||
return pb.collection('game_comments').create({
|
||||
game: gameId,
|
||||
author: user.id,
|
||||
content,
|
||||
rating
|
||||
})
|
||||
}
|
||||
|
||||
// 获取游戏评论
|
||||
export async function getGameComments(gameId: string): Promise<GameComment[]> {
|
||||
const result = await pb.collection('game_comments').getList(1, 50, {
|
||||
filter: `game="${gameId}"`,
|
||||
sort: '-created',
|
||||
expand: 'author'
|
||||
})
|
||||
return result.items as unknown as GameComment[]
|
||||
}
|
||||
|
||||
// 获取所有平台
|
||||
@@ -90,9 +129,27 @@ export function getAllPlatforms(): GamePlatform[] {
|
||||
return ['PC', 'PS5', 'Xbox', 'Switch', 'Mobile']
|
||||
}
|
||||
|
||||
// 订阅游戏变更
|
||||
export function subscribeGames(callback: (game: Game) => void) {
|
||||
return pb.collection('games').subscribe('*', (payload) => {
|
||||
callback(payload.record as unknown as Game)
|
||||
// 搜索游戏(用于 GameSelectDialog,全局搜索或群组内搜索)
|
||||
export async function searchGames(query: string, groupId?: string, limit = 20): Promise<Game[]> {
|
||||
if (!query.trim()) return []
|
||||
let filter = `name ~ "${query}"`
|
||||
if (groupId) filter += ` && group="${groupId}"`
|
||||
|
||||
const result = await pb.collection('games').getList(1, limit, {
|
||||
filter,
|
||||
sort: '-popularCount'
|
||||
})
|
||||
return result.items as unknown as Game[]
|
||||
}
|
||||
|
||||
// 获取热门游戏(全局,按 popularCount 排序)
|
||||
export async function getPopularGames(limit = 10): Promise<Game[]> {
|
||||
const user = pb.authStore.model
|
||||
if (!user) return []
|
||||
|
||||
// 获取用户所在群组的游戏
|
||||
const result = await pb.collection('games').getList(1, limit, {
|
||||
sort: '-popularCount'
|
||||
})
|
||||
return result.items as unknown as Game[]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user