// 数据库操作Hooks "use client" import { useState, useEffect, useCallback } from "react" import { db } from "./schema" import { seedDatabase } from "./seed" import type { User, Streamer, Star, Guild, Companion, EsportsVenue, Product, Transaction, Moment, Message, Notification, } from "./schema" // 初始化数据库 export function useInitDatabase() { const [isReady, setIsReady] = useState(false) const [error, setError] = useState(null) useEffect(() => { const init = async () => { try { await db.open() await seedDatabase() setIsReady(true) } catch (err) { console.error("[v0] Database init error:", err) setError(err as Error) } } init() }, []) return { isReady, error } } // 用户相关 export function useCurrentUser() { const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { const loadUser = async () => { try { const currentUser = await db.users.get(1) // 默认用户ID为1 setUser(currentUser || null) } catch (err) { console.error("[v0] Load user error:", err) } finally { setLoading(false) } } loadUser() }, []) const updateUser = useCallback( async (updates: Partial) => { if (!user?.id) return await db.users.update(user.id, { ...updates, updatedAt: new Date().toISOString() }) setUser((prev) => (prev ? { ...prev, ...updates } : null)) }, [user?.id], ) const updateBalance = useCallback( async (amount: number, type: "add" | "subtract") => { if (!user?.id) return false const newBalance = type === "add" ? user.balance + amount : user.balance - amount if (newBalance < 0) return false await db.users.update(user.id, { balance: newBalance, updatedAt: new Date().toISOString() }) setUser((prev) => (prev ? { ...prev, balance: newBalance } : null)) return true }, [user], ) return { user, loading, updateUser, updateBalance } } // 主播列表 export function useStreamers(options?: { game?: string; isLive?: boolean; limit?: number }) { const [streamers, setStreamers] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let query = db.streamers.where("status").equals("approved") if (options?.isLive !== undefined) { query = db.streamers.where("isLive").equals(options.isLive ? 1 : 0) } let results = await query.toArray() if (options?.game) { results = results.filter((s) => s.game === options.game) } if (options?.limit) { results = results.slice(0, options.limit) } setStreamers(results) } catch (err) { console.error("[v0] Load streamers error:", err) } finally { setLoading(false) } } load() }, [options?.game, options?.isLive, options?.limit]) return { streamers, loading } } // 明星列表 export function useStars(options?: { game?: string; limit?: number }) { const [stars, setStars] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.stars.where("status").equals("active").toArray() if (options?.game) { results = results.filter((s) => s.game === options.game) } if (options?.limit) { results = results.slice(0, options.limit) } setStars(results) } catch (err) { console.error("[v0] Load stars error:", err) } finally { setLoading(false) } } load() }, [options?.game, options?.limit]) return { stars, loading } } // 公会列表 export function useGuilds(options?: { limit?: number }) { const [guilds, setGuilds] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.guilds.where("status").equals("active").toArray() if (options?.limit) { results = results.slice(0, options.limit) } setGuilds(results) } catch (err) { console.error("[v0] Load guilds error:", err) } finally { setLoading(false) } } load() }, [options?.limit]) return { guilds, loading } } // CP/陪练列表 export function useCompanions(options?: { category?: "cp" | "coach"; gender?: string; limit?: number }) { const [companions, setCompanions] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.companions.where("status").equals("active").toArray() if (options?.category) { results = results.filter((c) => c.category === options.category) } if (options?.gender) { results = results.filter((c) => c.gender === options.gender) } if (options?.limit) { results = results.slice(0, options.limit) } setCompanions(results) } catch (err) { console.error("[v0] Load companions error:", err) } finally { setLoading(false) } } load() }, [options?.category, options?.gender, options?.limit]) return { companions, loading } } // 电竞酒店/网咖 export function useVenues(options?: { type?: "hotel" | "cafe"; city?: string; limit?: number }) { const [venues, setVenues] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.esportsVenues.where("status").equals("active").toArray() if (options?.type) { results = results.filter((v) => v.type === options.type) } if (options?.city) { results = results.filter((v) => v.city === options.city) } if (options?.limit) { results = results.slice(0, options.limit) } setVenues(results) } catch (err) { console.error("[v0] Load venues error:", err) } finally { setLoading(false) } } load() }, [options?.type, options?.city, options?.limit]) return { venues, loading } } // 商品列表 export function useProducts(options?: { category?: string; game?: string; limit?: number }) { const [products, setProducts] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.products.where("status").equals("active").toArray() if (options?.category) { results = results.filter((p) => p.category === options.category) } if (options?.game) { results = results.filter((p) => p.game === options.game) } if (options?.limit) { results = results.slice(0, options.limit) } setProducts(results) } catch (err) { console.error("[v0] Load products error:", err) } finally { setLoading(false) } } load() }, [options?.category, options?.game, options?.limit]) return { products, loading } } // 交易记录 export function useTransactions(userId: number, options?: { type?: string; limit?: number }) { const [transactions, setTransactions] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { let results = await db.transactions.where("userId").equals(userId).toArray() if (options?.type) { results = results.filter((t) => t.type === options.type) } results = results.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) if (options?.limit) { results = results.slice(0, options.limit) } setTransactions(results) } catch (err) { console.error("[v0] Load transactions error:", err) } finally { setLoading(false) } } load() }, [userId, options?.type, options?.limit]) return { transactions, loading } } // 动态列表 export function useMoments(options?: { userId?: number; limit?: number }) { const [moments, setMoments] = useState([]) const [loading, setLoading] = useState(true) const loadMoments = useCallback(async () => { try { let results = await db.moments.where("status").equals("active").toArray() if (options?.userId) { results = results.filter((m) => m.userId === options.userId) } results = results.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) if (options?.limit) { results = results.slice(0, options.limit) } setMoments(results) } catch (err) { console.error("[v0] Load moments error:", err) } finally { setLoading(false) } }, [options?.userId, options?.limit]) useEffect(() => { loadMoments() }, [loadMoments]) const likeMoment = useCallback( async (momentId: number) => { const moment = await db.moments.get(momentId) if (moment) { await db.moments.update(momentId, { likes: moment.likes + 1, isLiked: true, updatedAt: new Date().toISOString(), }) await loadMoments() } }, [loadMoments], ) return { moments, loading, likeMoment, refresh: loadMoments } } // 消息列表 export function useMessages(conversationId: number) { const [messages, setMessages] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { const results = await db.messages.where("conversationId").equals(conversationId).toArray() setMessages(results.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())) } catch (err) { console.error("[v0] Load messages error:", err) } finally { setLoading(false) } } load() }, [conversationId]) const sendMessage = useCallback( async (content: string, type: "text" | "image" | "voice" = "text") => { const newMessage: Omit = { conversationId, senderId: 1, // 当前用户 receiverId: 0, // 需要从conversation获取 type, content, isRead: false, createdAt: new Date().toISOString(), } const id = await db.messages.add(newMessage as Message) setMessages((prev) => [...prev, { ...newMessage, id } as Message]) }, [conversationId], ) return { messages, loading, sendMessage } } // 通知列表 export function useNotifications(userId: number) { const [notifications, setNotifications] = useState([]) const [unreadCount, setUnreadCount] = useState(0) const [loading, setLoading] = useState(true) useEffect(() => { const load = async () => { try { const results = await db.notifications.where("userId").equals(userId).toArray() const sorted = results.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) setNotifications(sorted) setUnreadCount(sorted.filter((n) => !n.isRead).length) } catch (err) { console.error("[v0] Load notifications error:", err) } finally { setLoading(false) } } load() }, [userId]) const markAsRead = useCallback(async (notificationId: number) => { await db.notifications.update(notificationId, { isRead: true }) setNotifications((prev) => prev.map((n) => (n.id === notificationId ? { ...n, isRead: true } : n))) setUnreadCount((prev) => Math.max(0, prev - 1)) }, []) const markAllAsRead = useCallback(async () => { const unread = notifications.filter((n) => !n.isRead) await Promise.all(unread.map((n) => db.notifications.update(n.id!, { isRead: true }))) setNotifications((prev) => prev.map((n) => ({ ...n, isRead: true }))) setUnreadCount(0) }, [notifications]) return { notifications, unreadCount, loading, markAsRead, markAllAsRead } } // 创建订单 export function useCreateOrder() { const createTransaction = useCallback( async ( userId: number, type: Transaction["type"], category: string, amount: number, description: string, relatedId?: number, relatedType?: string, ) => { const user = await db.users.get(userId) if (!user) throw new Error("User not found") const balanceBefore = user.balance const balanceAfter = type === "recharge" || type === "income" || type === "refund" ? balanceBefore + amount : balanceBefore - amount if (balanceAfter < 0) { throw new Error("Insufficient balance") } const transaction: Omit = { userId, orderNo: `TXN${Date.now()}${Math.random().toString(36).substr(2, 6).toUpperCase()}`, type, category, amount, balanceBefore, balanceAfter, relatedId, relatedType, description, status: "completed", createdAt: new Date().toISOString(), } await db.transactions.add(transaction as Transaction) await db.users.update(userId, { balance: balanceAfter, updatedAt: new Date().toISOString() }) return transaction }, [], ) return { createTransaction } }