ItemLogCollector.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <?php
  2. namespace App\Module\Game\Logics\UserLogCollectors;
  3. use App\Module\GameItems\Models\ItemTransactionLog;
  4. use App\Module\GameItems\Services\ItemService;
  5. /**
  6. * 物品日志收集器
  7. *
  8. * 收集item_transaction_logs表的新增记录,转换为用户友好的日志消息
  9. */
  10. class ItemLogCollector extends BaseLogCollector
  11. {
  12. /**
  13. * 源表名
  14. *
  15. * @var string
  16. */
  17. protected string $sourceTable = 'item_transaction_logs';
  18. /**
  19. * 源类型
  20. *
  21. * @var string
  22. */
  23. protected string $sourceType = 'item';
  24. /**
  25. * 获取新的记录
  26. *
  27. * @param int $lastProcessedId 上次处理的最大ID
  28. * @return \Illuminate\Database\Eloquent\Collection
  29. */
  30. protected function getNewRecords(int $lastProcessedId)
  31. {
  32. return ItemTransactionLog::where('id', '>', $lastProcessedId)
  33. ->orderBy('id')
  34. ->limit($this->maxRecords)
  35. ->get();
  36. }
  37. /**
  38. * 按时间获取新的记录
  39. *
  40. * @param int $lastProcessedTimestamp 上次处理的最大时间戳
  41. * @return \Illuminate\Database\Eloquent\Collection
  42. */
  43. protected function getNewRecordsByTime(int $lastProcessedTimestamp)
  44. {
  45. return ItemTransactionLog::where('created_at', '>', date('Y-m-d H:i:s', $lastProcessedTimestamp))
  46. ->orderBy('created_at')
  47. ->orderBy('id') // 相同时间时按ID排序
  48. ->limit($this->maxRecords)
  49. ->get();
  50. }
  51. /**
  52. * 获取记录的时间戳
  53. *
  54. * @param ItemTransactionLog $record 物品交易记录
  55. * @return int 时间戳
  56. */
  57. protected function getRecordTimestamp($record): int
  58. {
  59. return strtotime($record->created_at);
  60. }
  61. /**
  62. * 根据记录ID获取原始记录的时间戳
  63. *
  64. * @param int $recordId 记录ID
  65. * @return int 时间戳
  66. */
  67. protected function getOriginalRecordTimestamp(int $recordId): int
  68. {
  69. try {
  70. $record = ItemTransactionLog::find($recordId);
  71. return $record ? strtotime($record->created_at) : 0;
  72. } catch (\Exception $e) {
  73. \Illuminate\Support\Facades\Log::error("获取物品日志原始时间戳失败", [
  74. 'record_id' => $recordId,
  75. 'error' => $e->getMessage()
  76. ]);
  77. return 0;
  78. }
  79. }
  80. /**
  81. * 转换记录为用户日志数据
  82. *
  83. * @param ItemTransactionLog $record 物品交易记录
  84. * @return array|null 用户日志数据,null表示跳过
  85. */
  86. protected function convertToUserLog($record): ?array
  87. {
  88. try {
  89. // 生成用户友好的消息
  90. $message = $this->buildUserFriendlyMessage($record);
  91. if (!$message) {
  92. return null; // 跳过无法生成消息的记录
  93. }
  94. return $this->createUserLogData(
  95. $record->user_id,
  96. $message,
  97. $record->id,
  98. $record->created_at
  99. );
  100. } catch (\Exception $e) {
  101. \Illuminate\Support\Facades\Log::error("转换物品日志失败", [
  102. 'record_id' => $record->id,
  103. 'error' => $e->getMessage()
  104. ]);
  105. return null;
  106. }
  107. }
  108. /**
  109. * 构建用户友好的消息
  110. *
  111. * @param ItemTransactionLog $record
  112. * @return string|null
  113. */
  114. private function buildUserFriendlyMessage(ItemTransactionLog $record): ?string
  115. {
  116. $itemName = $this->getItemName($record->item_id);
  117. $quantity = abs($record->quantity);
  118. $isGain = $record->quantity > 0;
  119. // 根据来源类型生成不同的消息格式
  120. switch ($record->source_type) {
  121. case 'house_upgrade':
  122. return $this->buildHouseUpgradeMessage($record, $itemName, $quantity, $isGain);
  123. case 'land_upgrade':
  124. return $this->buildLandUpgradeMessage($record, $itemName, $quantity, $isGain);
  125. case 'land_sow':
  126. return $this->buildLandSowMessage($record, $itemName, $quantity, $isGain);
  127. case 'land_remove_crop':
  128. return $this->buildLandRemoveCropMessage($record, $itemName, $quantity, $isGain);
  129. case 'shop_buy':
  130. return $this->buildShopBuyMessage($record, $itemName, $quantity, $isGain);
  131. case 'task_reward':
  132. return $this->buildTaskRewardMessage($record, $itemName, $quantity, $isGain);
  133. case 'admin_add':
  134. return $this->buildAdminMessage($record, $itemName, $quantity, $isGain);
  135. default:
  136. return $this->buildDefaultMessage($record, $itemName, $quantity, $isGain);
  137. }
  138. }
  139. /**
  140. * 构建房屋升级消息
  141. *
  142. * @param ItemTransactionLog $record
  143. * @param string $itemName
  144. * @param int $quantity
  145. * @param bool $isGain
  146. * @return string
  147. */
  148. private function buildHouseUpgradeMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  149. {
  150. if ($isGain) {
  151. return "房屋升级获得{$itemName} {$quantity}";
  152. } else {
  153. return "房屋升级消耗{$itemName} {$quantity}";
  154. }
  155. }
  156. /**
  157. * 构建土地升级消息
  158. *
  159. * @param ItemTransactionLog $record
  160. * @param string $itemName
  161. * @param int $quantity
  162. * @param bool $isGain
  163. * @return string
  164. */
  165. private function buildLandUpgradeMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  166. {
  167. if ($isGain) {
  168. return "土地升级获得{$itemName} {$quantity}";
  169. } else {
  170. return "土地升级消耗{$itemName} {$quantity}";
  171. }
  172. }
  173. /**
  174. * 构建播种消息
  175. *
  176. * @param ItemTransactionLog $record
  177. * @param string $itemName
  178. * @param int $quantity
  179. * @param bool $isGain
  180. * @return string
  181. */
  182. private function buildLandSowMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  183. {
  184. if ($isGain) {
  185. return "播种获得{$itemName} {$quantity}";
  186. } else {
  187. return "播种消耗{$itemName} {$quantity}";
  188. }
  189. }
  190. /**
  191. * 构建清除作物消息
  192. *
  193. * @param ItemTransactionLog $record
  194. * @param string $itemName
  195. * @param int $quantity
  196. * @param bool $isGain
  197. * @return string
  198. */
  199. private function buildLandRemoveCropMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  200. {
  201. if ($isGain) {
  202. return "清除作物获得{$itemName} {$quantity}";
  203. } else {
  204. return "清除作物消耗{$itemName} {$quantity}";
  205. }
  206. }
  207. /**
  208. * 构建商店购买消息
  209. *
  210. * @param ItemTransactionLog $record
  211. * @param string $itemName
  212. * @param int $quantity
  213. * @param bool $isGain
  214. * @return string
  215. */
  216. private function buildShopBuyMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  217. {
  218. if ($isGain) {
  219. return "购买{$itemName} {$quantity}";
  220. } else {
  221. return "购买消耗{$itemName} {$quantity}";
  222. }
  223. }
  224. /**
  225. * 构建任务奖励消息
  226. *
  227. * @param ItemTransactionLog $record
  228. * @param string $itemName
  229. * @param int $quantity
  230. * @param bool $isGain
  231. * @return string
  232. */
  233. private function buildTaskRewardMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  234. {
  235. if ($isGain) {
  236. return "任务奖励{$itemName} {$quantity}";
  237. } else {
  238. return "任务消耗{$itemName} {$quantity}";
  239. }
  240. }
  241. /**
  242. * 构建管理员操作消息
  243. *
  244. * @param ItemTransactionLog $record
  245. * @param string $itemName
  246. * @param int $quantity
  247. * @param bool $isGain
  248. * @return string
  249. */
  250. private function buildAdminMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  251. {
  252. if ($isGain) {
  253. return "管理员发放{$itemName} {$quantity}";
  254. } else {
  255. return "管理员扣除{$itemName} {$quantity}";
  256. }
  257. }
  258. /**
  259. * 构建默认消息
  260. *
  261. * @param ItemTransactionLog $record
  262. * @param string $itemName
  263. * @param int $quantity
  264. * @param bool $isGain
  265. * @return string
  266. */
  267. private function buildDefaultMessage(ItemTransactionLog $record, string $itemName, int $quantity, bool $isGain): string
  268. {
  269. $action = $isGain ? '获得' : '消耗';
  270. if (!empty($record->source_type)) {
  271. $sourceDesc = $this->getSourceTypeDesc($record->source_type);
  272. if ($sourceDesc) {
  273. return "{$sourceDesc}{$action}{$itemName} {$quantity}";
  274. }
  275. }
  276. return "{$action}{$itemName} {$quantity}";
  277. }
  278. /**
  279. * 获取物品名称
  280. *
  281. * @param int $itemId 物品ID
  282. * @return string
  283. */
  284. private function getItemName(int $itemId): string
  285. {
  286. try {
  287. // 尝试从物品服务获取物品信息
  288. $itemDto = ItemService::getItemInfo($itemId);
  289. if ($itemDto && $itemDto->name) {
  290. return $itemDto->name;
  291. }
  292. // 如果服务不可用,尝试直接查询数据库
  293. $itemModel = \App\Module\GameItems\Models\Item::find($itemId);
  294. if ($itemModel) {
  295. return $itemModel->name;
  296. }
  297. return "物品{$itemId}";
  298. } catch (\Exception $e) {
  299. return "物品{$itemId}";
  300. }
  301. }
  302. /**
  303. * 获取交易类型描述
  304. *
  305. * @param int $transactionType 交易类型
  306. * @return string
  307. */
  308. private function getTransactionTypeDesc(int $transactionType): string
  309. {
  310. $typeMap = [
  311. 1 => '获取',
  312. 2 => '消耗',
  313. 3 => '交易获得',
  314. 4 => '交易失去',
  315. 5 => '过期失效',
  316. ];
  317. return $typeMap[$transactionType] ?? '';
  318. }
  319. /**
  320. * 获取来源类型描述
  321. *
  322. * @param string $sourceType 来源类型
  323. * @return string
  324. */
  325. private function getSourceTypeDesc(string $sourceType): string
  326. {
  327. $sourceMap = [
  328. 'task' => '任务奖励',
  329. 'shop' => '商店购买',
  330. 'chest' => '宝箱开启',
  331. 'craft' => '物品合成',
  332. 'farm' => '农场收获',
  333. 'pet' => '宠物获得',
  334. 'system' => '系统发放',
  335. 'admin' => '管理员操作',
  336. ];
  337. return $sourceMap[$sourceType] ?? $sourceType;
  338. }
  339. /**
  340. * 是否应该记录此日志
  341. *
  342. * @param ItemTransactionLog $record
  343. * @return bool
  344. */
  345. private function shouldLogRecord(ItemTransactionLog $record): bool
  346. {
  347. // 跳过数量为0的记录
  348. if ($record->quantity == 0) {
  349. return false;
  350. }
  351. // 可以添加更多过滤条件
  352. // 例如:跳过某些物品类型
  353. // 例如:跳过临时物品
  354. return true;
  355. }
  356. /**
  357. * 获取物品的额外信息
  358. *
  359. * @param ItemTransactionLog $record
  360. * @return string
  361. */
  362. private function getExtraInfo(ItemTransactionLog $record): string
  363. {
  364. $extraInfo = [];
  365. // 如果有实例ID,说明是有特殊属性的物品
  366. if ($record->instance_id) {
  367. $extraInfo[] = '特殊属性';
  368. }
  369. // 如果有过期时间
  370. if ($record->expire_at) {
  371. $expireTime = \Carbon\Carbon::parse($record->expire_at);
  372. if ($expireTime->isFuture()) {
  373. $extraInfo[] = '有效期至' . $expireTime->format('m-d H:i');
  374. }
  375. }
  376. return !empty($extraInfo) ? '(' . implode(',', $extraInfo) . ')' : '';
  377. }
  378. }