*/ private const BANK_MILESTONES = [ 10000000, 30000000, ]; /** * 注入聊天室状态服务,用于里程碑公告广播。 */ public function __construct( private readonly ChatStateService $chatState, ) {} /** * 计算 AI 当前手上可直接使用的金币。 */ public function getSpendableGold(User $user): int { return (int) ($user->jjb ?? 0); } /** * 计算 AI 当前持有的金币总资产(手上 + 银行)。 */ public function getTotalGoldAssets(User $user): int { return (int) ($user->jjb ?? 0) + (int) ($user->bank_jjb ?? 0); } /** * 判断 AI 当前手上金币是否足够支付本次支出。 */ public function prepareSpend(User $user, int $spendAmount): bool { if ($spendAmount <= 0) { return true; } $user->refresh(); return (int) ($user->jjb ?? 0) >= $spendAmount; } /** * 为大额支出准备手头金币。 * * 该模式不会保留手上余额阈值,适用于买单活动等需要临时调拨银行金币的场景。 */ public function prepareAllInSpend(User $user, int $spendAmount): bool { if ($spendAmount <= 0) { return true; } return $this->raiseWalletTo($user, $spendAmount); } /** * 将 100 万以上的富余金币自动转存到银行。 */ public function bankExcessGold(User $user): void { $milestones = DB::transaction(function () use ($user): array { $lockedUser = User::query()->lockForUpdate()->find($user->id); if (! $lockedUser) { return []; } $walletGold = (int) ($lockedUser->jjb ?? 0); if ($walletGold <= self::AVAILABLE_GOLD_RESERVE) { return []; } $bankBefore = (int) ($lockedUser->bank_jjb ?? 0); $depositAmount = $walletGold - self::AVAILABLE_GOLD_RESERVE; // 只把超过 100 万的部分转入银行,手上保留不高于 100 万的常规活动资金。 $lockedUser->jjb = self::AVAILABLE_GOLD_RESERVE; $lockedUser->bank_jjb = $bankBefore + $depositAmount; $lockedUser->save(); BankLog::create([ 'user_id' => $lockedUser->id, 'type' => 'deposit', 'amount' => $depositAmount, 'balance_after' => (int) $lockedUser->bank_jjb, ]); return array_values(array_filter( self::BANK_MILESTONES, fn (int $milestone): bool => $bankBefore < $milestone && (int) $lockedUser->bank_jjb >= $milestone, )); }); $user->refresh(); foreach ($milestones as $milestone) { $this->broadcastMilestoneAnnouncement($milestone); } } /** * 一次性完成 AI 常规理财:仅把超过 100 万的部分转入银行。 */ public function rebalanceHoldings(User $user): void { $this->bankExcessGold($user); } /** * 将手上金币抬升到目标值,必要时从银行自动取款。 */ private function raiseWalletTo(User $user, int $targetWalletGold): bool { $reachedTarget = DB::transaction(function () use ($user, $targetWalletGold): bool { $lockedUser = User::query()->lockForUpdate()->find($user->id); if (! $lockedUser) { return false; } $walletGold = (int) ($lockedUser->jjb ?? 0); if ($walletGold >= $targetWalletGold) { return true; } $bankGold = (int) ($lockedUser->bank_jjb ?? 0); $withdrawAmount = min($targetWalletGold - $walletGold, $bankGold); if ($withdrawAmount <= 0) { return false; } // 优先把银行金币提回手上,保证 AI 的即时可用余额尽量回到目标线。 $lockedUser->jjb = $walletGold + $withdrawAmount; $lockedUser->bank_jjb = $bankGold - $withdrawAmount; $lockedUser->save(); BankLog::create([ 'user_id' => $lockedUser->id, 'type' => 'withdraw', 'amount' => $withdrawAmount, 'balance_after' => (int) $lockedUser->bank_jjb, ]); return (int) $lockedUser->jjb >= $targetWalletGold; }); $user->refresh(); return $reachedTarget; } /** * 广播 AI小班长达成银行存款目标的全站公告。 */ private function broadcastMilestoneAnnouncement(int $milestone): void { $roomIds = $this->chatState->getAllActiveRoomIds(); if (empty($roomIds)) { $roomIds = [1]; } $milestoneInWan = (int) ($milestone / 10000); $content = "🏆 🎉 【全站公告】 恭喜 AI小班长 达成理财新高度!
他在银行的存款已成功突破 {$milestoneInWan}万 金币!💰✨"; foreach ($roomIds as $roomId) { $message = [ 'id' => $this->chatState->nextMessageId($roomId), 'room_id' => $roomId, 'from_user' => '系统传音', 'to_user' => '大家', 'content' => $content, 'is_secret' => false, 'font_color' => '#f59e0b', 'action' => '大声宣告', 'sent_at' => now()->toDateTimeString(), ]; $this->chatState->pushMessage($roomId, $message); broadcast(new MessageSent($roomId, $message)); SaveMessageJob::dispatch($message); } } }