item_id) { $itemIds[] = $record->item_id; } } if (!empty($itemIds)) { $itemIds = array_unique($itemIds); $items = \App\Module\GameItems\Models\Item::whereIn('id', $itemIds)->get(); foreach ($items as $item) { $this->itemNameCache[$item->id] = $item->name; } // 为未找到的物品设置默认名称 foreach ($itemIds as $itemId) { if (!isset($this->itemNameCache[$itemId])) { $this->itemNameCache[$itemId] = "物品{$itemId}"; } } } } /** * 获取新的记录 * * @param int $lastProcessedId 上次处理的最大ID * @return \Illuminate\Database\Eloquent\Collection */ protected function getNewRecords(int $lastProcessedId) { $records = ItemTransactionLog::where('id', '>', $lastProcessedId) ->orderBy('id') ->limit($this->maxRecords) ->get(); // 预加载物品信息 $this->preloadItems($records); return $records; } /** * 获取源表的最大ID * * 重写父类方法,使用模型查询以获得更好的性能 * * @return int */ public function getSourceTableMaxId(): int { return ItemTransactionLog::max('id') ?: 0; } /** * 转换记录为用户日志数据 * * @param ItemTransactionLog $record 物品交易记录 * @return array|null 用户日志数据,null表示跳过 */ protected function convertToUserLog($record): ?array { try { // 生成用户友好的消息 $message = $this->buildUserFriendlyMessage($record); if (!$message) { return null; // 跳过无法生成消息的记录 } // 根据操作类型选择合适的source_type $sourceType = $this->getSourceTypeByOperation($record->source_type); return $this->createUserLogDataWithSourceType( $record->user_id, $message, $record->id, $record->created_at, $sourceType ); } catch (\Exception $e) { \Illuminate\Support\Facades\Log::error("转换物品日志失败", [ 'record_id' => $record->id, 'error' => $e->getMessage() ]); return null; } } /** * 构建用户友好的消息 * * @param ItemTransactionLog $record * @return string|null */ private function buildUserFriendlyMessage(ItemTransactionLog $record): ?string { $itemName = $this->getItemName($record->item_id); $quantity = abs($record->quantity); $isGain = $record->quantity > 0; // 根据来源类型生成不同的消息格式 switch ($record->source_type) { case 'house_upgrade': return $this->buildHouseUpgradeMessage($record, $itemName, $quantity, $isGain); case 'land_upgrade': return $this->buildLandUpgradeMessage($record, $itemName, $quantity, $isGain); case 'land_sow': return $this->buildLandSowMessage($record, $itemName, $quantity, $isGain); case 'land_remove_crop': return $this->buildLandRemoveCropMessage($record, $itemName, $quantity, $isGain); case 'shop_buy': return $this->buildShopBuyMessage($record, $itemName, $quantity, $isGain); case 'task_reward': return $this->buildTaskRewardMessage($record, $itemName, $quantity, $isGain); case 'admin_add': return $this->buildAdminMessage($record, $itemName, $quantity, $isGain); default: return $this->buildDefaultMessage($record, $itemName, $quantity, $isGain); } } /** * 构建房屋升级消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildHouseUpgradeMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "房屋升级获得{$itemName} {$quantity}"; } else { return "房屋升级消耗{$itemName} {$quantity}"; } } /** * 构建土地升级消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildLandUpgradeMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "土地升级获得{$itemName} {$quantity}"; } else { return "土地升级消耗{$itemName} {$quantity}"; } } /** * 构建播种消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildLandSowMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "播种获得{$itemName} {$quantity}"; } else { return "播种消耗{$itemName} {$quantity}"; } } /** * 构建清除作物消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildLandRemoveCropMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "清除作物获得{$itemName} {$quantity}"; } else { return "清除作物消耗{$itemName} {$quantity}"; } } /** * 构建商店购买消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildShopBuyMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "购买{$itemName} {$quantity}"; } else { return "购买消耗{$itemName} {$quantity}"; } } /** * 构建任务奖励消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildTaskRewardMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "任务奖励{$itemName} {$quantity}"; } else { return "任务消耗{$itemName} {$quantity}"; } } /** * 构建管理员操作消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildAdminMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { if ($isGain) { return "管理员发放{$itemName} {$quantity}"; } else { return "管理员扣除{$itemName} {$quantity}"; } } /** * 构建默认消息 * * @param ItemTransactionLog $record * @param string $itemName * @param int $quantity * @param bool $isGain * @return string */ private function buildDefaultMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string { $action = $isGain ? '获得' : '消耗'; if (!empty($record->source_type)) { $sourceDesc = $this->getSourceTypeDesc($record->source_type); if ($sourceDesc) { return "{$sourceDesc}{$action}{$itemName} {$quantity}"; } } return "{$action}{$itemName} {$quantity}"; } /** * 获取物品名称(带缓存) * * @param int $itemId 物品ID * @return string */ private function getItemName(int $itemId): string { // 检查缓存 if (isset($this->itemNameCache[$itemId])) { return $this->itemNameCache[$itemId]; } try { // 直接查询数据库,避免调用可能有问题的服务 $itemModel = \App\Module\GameItems\Models\Item::find($itemId); if ($itemModel && $itemModel->name) { $this->itemNameCache[$itemId] = $itemModel->name; return $itemModel->name; } $defaultName = "物品{$itemId}"; $this->itemNameCache[$itemId] = $defaultName; return $defaultName; } catch (\Exception $e) { $defaultName = "物品{$itemId}"; $this->itemNameCache[$itemId] = $defaultName; return $defaultName; } } /** * 获取交易类型描述 * * @param int $transactionType 交易类型 * @return string */ private function getTransactionTypeDesc(int $transactionType): string { $typeMap = [ 1 => '获取', 2 => '消耗', 3 => '交易获得', 4 => '交易失去', 5 => '过期失效', ]; return $typeMap[$transactionType] ?? ''; } /** * 获取来源类型描述 * * @param string $sourceType 来源类型 * @return string */ private function getSourceTypeDesc(string $sourceType): string { $sourceMap = [ 'task' => '任务奖励', 'shop' => '商店购买', 'chest' => '宝箱开启', 'craft' => '物品合成', 'farm' => '农场收获', 'pet' => '宠物获得', 'system' => '系统发放', 'admin' => '管理员操作', ]; return $sourceMap[$sourceType] ?? $sourceType; } /** * 是否应该记录此日志 * * @param ItemTransactionLog $record * @return bool */ private function shouldLogRecord(ItemTransactionLog $record): bool { // 跳过数量为0的记录 if ($record->quantity == 0) { return false; } // 可以添加更多过滤条件 // 例如:跳过某些物品类型 // 例如:跳过临时物品 return true; } /** * 获取物品的额外信息 * * @param ItemTransactionLog $record * @return string */ private function getExtraInfo(ItemTransactionLog $record): string { $extraInfo = []; // 如果有实例ID,说明是有特殊属性的物品 if ($record->instance_id) { $extraInfo[] = '特殊属性'; } // 如果有过期时间 if ($record->expire_at) { $expireTime = \Carbon\Carbon::parse($record->expire_at); if ($expireTime->isFuture()) { $extraInfo[] = '有效期至' . $expireTime->format('m-d H:i'); } } return !empty($extraInfo) ? '(' . implode(',', $extraInfo) . ')' : ''; } /** * 根据操作类型获取合适的source_type * * @param string|null $sourceType 原始来源类型 * @return string */ private function getSourceTypeByOperation(?string $sourceType): string { // 如果source_type为null,返回默认的系统类型 if ($sourceType === null) { return REWARD_SOURCE_TYPE::SYSTEM->value; } switch ($sourceType) { case 'house_upgrade': case 'land_upgrade': return REWARD_SOURCE_TYPE::FARM_UPGRADE->value; case 'land_sow': return REWARD_SOURCE_TYPE::FARM_PLANT->value; case 'land_remove_crop': return REWARD_SOURCE_TYPE::LAND_REMOVE_CROP->value; case 'shop_buy': return REWARD_SOURCE_TYPE::SHOP_PURCHASE->value; case 'task_reward': return REWARD_SOURCE_TYPE::TASK->value; case 'admin_add': return REWARD_SOURCE_TYPE::ADMIN_GRANT->value; case 'chest': return REWARD_SOURCE_TYPE::CHEST->value; case 'craft': return REWARD_SOURCE_TYPE::CRAFT->value; case 'farm': return REWARD_SOURCE_TYPE::FARM_HARVEST->value; case 'pet': return REWARD_SOURCE_TYPE::SYSTEM->value; default: return REWARD_SOURCE_TYPE::SYSTEM->value; } } /** * 创建用户日志数据数组(带自定义source_type) * * @param int $userId 用户ID * @param string $message 日志消息 * @param int $sourceId 来源记录ID * @param string|null $originalTime 原始时间(业务发生时间),null则使用当前时间 * @param string $sourceType 来源类型 * @return array */ protected function createUserLogDataWithSourceType( int $userId, string $message, int $sourceId, ?string $originalTime = null, string $sourceType = null ): array { $now = now()->toDateTimeString(); $originalTime = $originalTime ?? $now; $sourceType = $sourceType ?? $this->sourceType; return [ 'user_id' => $userId, 'message' => $message, 'source_type' => $sourceType, 'source_id' => $sourceId, 'source_table' => $this->sourceTable, 'original_time' => $originalTime, // 原始业务时间 'collected_at' => $now, // 收集时间 'created_at' => $now, // 兼容字段 ]; } }