/** * 积分系统服务 * 管理用户积分账户、交易、奖励等 */ // ==================== 常量配置 ==================== export const CREDIT_CONFIG = { INITIAL_BALANCE: 10000, // 初始积分 MIN_BALANCE: 100, // 最低保留余额(破产保护) MAX_SINGLE_BET: 1000, // 单次下注上限 DAILY_BONUS: 100, // 每日签到奖励 CREATE_TOPIC_COST: 100, // 创建话题费用 }; // 积分账户存储(生产环境应使用数据库) const userAccounts = new Map(); // 交易记录存储 const transactions = []; // ==================== 账户管理 ==================== /** * 获取用户账户 * @param {string} userId - 用户ID * @returns {Object} 用户账户信息 */ export const getUserAccount = (userId) => { if (!userAccounts.has(userId)) { // 首次访问,创建新账户 const newAccount = { user_id: userId, balance: CREDIT_CONFIG.INITIAL_BALANCE, frozen: 0, total: CREDIT_CONFIG.INITIAL_BALANCE, total_earned: CREDIT_CONFIG.INITIAL_BALANCE, total_spent: 0, total_profit: 0, active_positions: [], stats: { total_topics: 0, win_count: 0, loss_count: 0, win_rate: 0, best_profit: 0, }, last_daily_bonus: null, }; userAccounts.set(userId, newAccount); } return userAccounts.get(userId); }; /** * 更新用户账户 * @param {string} userId - 用户ID * @param {Object} updates - 更新内容 */ export const updateUserAccount = (userId, updates) => { const account = getUserAccount(userId); const updated = { ...account, ...updates }; userAccounts.set(userId, updated); return updated; }; /** * 获取用户积分余额 * @param {string} userId - 用户ID * @returns {number} 可用余额 */ export const getBalance = (userId) => { const account = getUserAccount(userId); return account.balance; }; /** * 检查用户是否能支付 * @param {string} userId - 用户ID * @param {number} amount - 金额 * @returns {boolean} 是否能支付 */ export const canAfford = (userId, amount) => { const account = getUserAccount(userId); const afterBalance = account.balance - amount; // 必须保留最低余额 return afterBalance >= CREDIT_CONFIG.MIN_BALANCE; }; // ==================== 积分操作 ==================== /** * 增加积分 * @param {string} userId - 用户ID * @param {number} amount - 金额 * @param {string} reason - 原因 */ export const addCredits = (userId, amount, reason = '系统增加') => { const account = getUserAccount(userId); const updated = { balance: account.balance + amount, total: account.total + amount, total_earned: account.total_earned + amount, }; updateUserAccount(userId, updated); // 记录交易 logTransaction({ user_id: userId, type: 'earn', amount, reason, balance_after: updated.balance, }); return updated; }; /** * 扣除积分 * @param {string} userId - 用户ID * @param {number} amount - 金额 * @param {string} reason - 原因 * @throws {Error} 如果余额不足 */ export const deductCredits = (userId, amount, reason = '系统扣除') => { if (!canAfford(userId, amount)) { throw new Error(`积分不足,需要${amount}积分,但只有${getBalance(userId)}积分`); } const account = getUserAccount(userId); const updated = { balance: account.balance - amount, total_spent: account.total_spent + amount, }; updateUserAccount(userId, updated); // 记录交易 logTransaction({ user_id: userId, type: 'spend', amount: -amount, reason, balance_after: updated.balance, }); return updated; }; /** * 冻结积分(席位占用) * @param {string} userId - 用户ID * @param {number} amount - 金额 */ export const freezeCredits = (userId, amount) => { const account = getUserAccount(userId); if (account.balance < amount) { throw new Error('可用余额不足'); } const updated = { balance: account.balance - amount, frozen: account.frozen + amount, }; updateUserAccount(userId, updated); return updated; }; /** * 解冻积分 * @param {string} userId - 用户ID * @param {number} amount - 金额 */ export const unfreezeCredits = (userId, amount) => { const account = getUserAccount(userId); const updated = { balance: account.balance + amount, frozen: account.frozen - amount, }; updateUserAccount(userId, updated); return updated; }; // ==================== 每日奖励 ==================== /** * 领取每日签到奖励 * @param {string} userId - 用户ID * @returns {Object} 奖励信息 */ export const claimDailyBonus = (userId) => { const account = getUserAccount(userId); const today = new Date().toDateString(); // 检查是否已领取 if (account.last_daily_bonus === today) { return { success: false, message: '今日已领取', }; } // 发放奖励 addCredits(userId, CREDIT_CONFIG.DAILY_BONUS, '每日签到'); // 更新领取时间 updateUserAccount(userId, { last_daily_bonus: today }); return { success: true, amount: CREDIT_CONFIG.DAILY_BONUS, message: `获得${CREDIT_CONFIG.DAILY_BONUS}积分`, }; }; /** * 检查今天是否已签到 * @param {string} userId - 用户ID * @returns {boolean} */ export const hasClaimedToday = (userId) => { const account = getUserAccount(userId); const today = new Date().toDateString(); return account.last_daily_bonus === today; }; // ==================== 持仓管理 ==================== /** * 添加持仓 * @param {string} userId - 用户ID * @param {Object} position - 持仓信息 */ export const addPosition = (userId, position) => { const account = getUserAccount(userId); const updated = { active_positions: [...account.active_positions, position], stats: { ...account.stats, total_topics: account.stats.total_topics + 1, }, }; updateUserAccount(userId, updated); return updated; }; /** * 移除持仓 * @param {string} userId - 用户ID * @param {string} positionId - 持仓ID */ export const removePosition = (userId, positionId) => { const account = getUserAccount(userId); const updated = { active_positions: account.active_positions.filter((p) => p.id !== positionId), }; updateUserAccount(userId, updated); return updated; }; /** * 更新持仓 * @param {string} userId - 用户ID * @param {string} positionId - 持仓ID * @param {Object} updates - 更新内容 */ export const updatePosition = (userId, positionId, updates) => { const account = getUserAccount(userId); const updated = { active_positions: account.active_positions.map((p) => p.id === positionId ? { ...p, ...updates } : p ), }; updateUserAccount(userId, updated); return updated; }; /** * 获取用户持仓 * @param {string} userId - 用户ID * @param {string} topicId - 话题ID(可选) * @returns {Array} 持仓列表 */ export const getUserPositions = (userId, topicId = null) => { const account = getUserAccount(userId); if (topicId) { return account.active_positions.filter((p) => p.topic_id === topicId); } return account.active_positions; }; // ==================== 统计更新 ==================== /** * 记录胜利 * @param {string} userId - 用户ID * @param {number} profit - 盈利金额 */ export const recordWin = (userId, profit) => { const account = getUserAccount(userId); const newWinCount = account.stats.win_count + 1; const totalGames = newWinCount + account.stats.loss_count; const winRate = (newWinCount / totalGames) * 100; const updated = { total_profit: account.total_profit + profit, stats: { ...account.stats, win_count: newWinCount, win_rate: winRate, best_profit: Math.max(account.stats.best_profit, profit), }, }; updateUserAccount(userId, updated); return updated; }; /** * 记录失败 * @param {string} userId - 用户ID * @param {number} loss - 损失金额 */ export const recordLoss = (userId, loss) => { const account = getUserAccount(userId); const newLossCount = account.stats.loss_count + 1; const totalGames = account.stats.win_count + newLossCount; const winRate = (account.stats.win_count / totalGames) * 100; const updated = { total_profit: account.total_profit - loss, stats: { ...account.stats, loss_count: newLossCount, win_rate: winRate, }, }; updateUserAccount(userId, updated); return updated; }; // ==================== 排行榜 ==================== /** * 获取积分排行榜 * @param {number} limit - 返回数量 * @returns {Array} 排行榜数据 */ export const getLeaderboard = (limit = 100) => { const accounts = Array.from(userAccounts.values()); return accounts .sort((a, b) => b.total - a.total) .slice(0, limit) .map((account, index) => ({ rank: index + 1, user_id: account.user_id, total: account.total, total_profit: account.total_profit, win_rate: account.stats.win_rate, })); }; /** * 获取用户排名 * @param {string} userId - 用户ID * @returns {number} 排名 */ export const getUserRank = (userId) => { const leaderboard = getLeaderboard(1000); const index = leaderboard.findIndex((item) => item.user_id === userId); return index >= 0 ? index + 1 : -1; }; // ==================== 交易记录 ==================== /** * 记录交易 * @param {Object} transaction - 交易信息 */ const logTransaction = (transaction) => { const record = { id: `tx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, timestamp: new Date().toISOString(), ...transaction, }; transactions.push(record); return record; }; /** * 获取用户交易记录 * @param {string} userId - 用户ID * @param {number} limit - 返回数量 * @returns {Array} 交易记录 */ export const getUserTransactions = (userId, limit = 50) => { return transactions .filter((tx) => tx.user_id === userId) .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp)) .slice(0, limit); }; // ==================== 批量操作 ==================== /** * 批量发放积分(如活动奖励) * @param {Array} recipients - [{user_id, amount, reason}] */ export const batchAddCredits = (recipients) => { const results = recipients.map(({ user_id, amount, reason }) => { try { return { user_id, success: true, account: addCredits(user_id, amount, reason), }; } catch (error) { return { user_id, success: false, error: error.message, }; } }); return results; }; // ==================== 导出所有功能 ==================== export default { CREDIT_CONFIG, // 账户管理 getUserAccount, updateUserAccount, getBalance, canAfford, // 积分操作 addCredits, deductCredits, freezeCredits, unfreezeCredits, // 每日奖励 claimDailyBonus, hasClaimedToday, // 持仓管理 addPosition, removePosition, updatePosition, getUserPositions, // 统计更新 recordWin, recordLoss, // 排行榜 getLeaderboard, getUserRank, // 交易记录 getUserTransactions, // 批量操作 batchAddCredits, };