feat: phase 4 - 积分竞猜和游戏黑名单 v0.3.0

竞猜功能:发起竞猜、下注、关闭、开奖、奖池分配
黑名单功能:标记游戏、按原因/严重程度筛选、详情展开
修复:双重结算、TOCTOU竞态、订阅泄漏、选项选择兼容性

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
congsh
2026-04-19 00:21:43 +08:00
parent 2d56df940d
commit 60ad9a04cd
24 changed files with 4047 additions and 14 deletions
+57
View File
@@ -0,0 +1,57 @@
import { pb } from './pocketbase'
import type { BlacklistEntry } from '@/types'
export async function createBlacklistEntry(data: {
group: string
game?: string
gameName: string
reason: string
description: string
severity: string
}): Promise<BlacklistEntry> {
const user = pb.authStore.model
if (!user) throw new Error('未登录')
const payload: Record<string, any> = {
group: data.group,
reporter: user.id,
gameName: data.gameName,
reason: data.reason,
description: data.description,
severity: data.severity,
}
if (data.game) payload.game = data.game
const record = await pb.collection('game_blacklist').create(payload)
return record as unknown as BlacklistEntry
}
export async function listBlacklist(
groupId: string,
options?: { reason?: string; severity?: string }
): Promise<BlacklistEntry[]> {
let filter = `group="${groupId}"`
if (options?.reason) filter += ` && reason="${options.reason}"`
if (options?.severity) filter += ` && severity="${options.severity}"`
const result = await pb.collection('game_blacklist').getFullList({
filter,
sort: '-created',
expand: 'reporter,game',
$autoCancel: false,
})
return result as unknown as BlacklistEntry[]
}
export async function deleteBlacklistEntry(entryId: string): Promise<void> {
await pb.collection('game_blacklist').delete(entryId)
}
export async function subscribeBlacklist(
groupId: string,
callback: (data: any) => void
): Promise<() => void> {
return pb.collection('game_blacklist').subscribe('*', (data) => {
if (data.record?.group === groupId) callback(data)
})
}