FundLogCollector.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <?php
  2. namespace App\Module\Game\Logics\UserLogCollectors;
  3. use App\Module\Fund\Models\FundLogModel;
  4. use App\Module\Fund\Services\AccountService;
  5. /**
  6. * 资金日志收集器
  7. *
  8. * 收集fund_logs表的新增记录,转换为用户友好的日志消息
  9. */
  10. class FundLogCollector extends BaseLogCollector
  11. {
  12. /**
  13. * 源表名
  14. *
  15. * @var string
  16. */
  17. protected string $sourceTable = 'fund_logs';
  18. /**
  19. * 源类型
  20. *
  21. * @var string
  22. */
  23. protected string $sourceType = 'fund';
  24. /**
  25. * 获取新的记录
  26. *
  27. * @param int $lastProcessedId 上次处理的最大ID
  28. * @return \Illuminate\Database\Eloquent\Collection
  29. */
  30. protected function getNewRecords(int $lastProcessedId)
  31. {
  32. return FundLogModel::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 FundLogModel::where('create_time', '>', $lastProcessedTimestamp)
  46. ->orderBy('create_time')
  47. ->orderBy('id') // 相同时间戳时按ID排序
  48. ->limit($this->maxRecords)
  49. ->get();
  50. }
  51. /**
  52. * 获取记录的时间戳
  53. *
  54. * @param FundLogModel $record 资金日志记录
  55. * @return int 时间戳
  56. */
  57. protected function getRecordTimestamp($record): int
  58. {
  59. return $record->create_time;
  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 = FundLogModel::find($recordId);
  71. return $record ? $record->create_time : 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 FundLogModel $record 资金日志记录
  84. * @return array|null 用户日志数据,null表示跳过
  85. */
  86. protected function convertToUserLog($record): ?array
  87. {
  88. try {
  89. // 获取资金名称
  90. $fundName = $this->getFundName($record->fund_id);
  91. // 判断是获得还是消耗
  92. $amount = abs($record->amount);
  93. $action = $record->amount > 0 ? '获得' : '消耗';
  94. // 解析备注信息,生成用户友好的消息
  95. $message = $this->buildUserFriendlyMessage($record, $fundName, $action, $amount);
  96. // 使用原始记录的时间
  97. $createdAt = date('Y-m-d H:i:s', $record->create_time);
  98. return $this->createUserLogData(
  99. $record->user_id,
  100. $message,
  101. $record->id,
  102. $createdAt
  103. );
  104. } catch (\Exception $e) {
  105. \Illuminate\Support\Facades\Log::error("转换资金日志失败", [
  106. 'record_id' => $record->id,
  107. 'error' => $e->getMessage()
  108. ]);
  109. return null;
  110. }
  111. }
  112. /**
  113. * 构建用户友好的消息
  114. *
  115. * @param FundLogModel $record 资金日志记录
  116. * @param string $fundName 资金名称
  117. * @param string $action 操作类型(获得/消耗)
  118. * @param int $amount 金额
  119. * @return string
  120. */
  121. private function buildUserFriendlyMessage(FundLogModel $record, string $fundName, string $action, int $amount): string
  122. {
  123. // 解析备注信息
  124. $remarkInfo = $this->parseRemark($record->remark);
  125. // 根据来源类型生成不同的消息格式
  126. if (isset($remarkInfo['source']) && isset($remarkInfo['id'])) {
  127. $sourceMessage = $this->getSourceMessage($remarkInfo['source'], $remarkInfo['id'], $action);
  128. if ($sourceMessage) {
  129. return "{$sourceMessage}{$action}{$fundName} {$amount}";
  130. }
  131. }
  132. // 如果无法解析来源信息,使用默认格式
  133. return "{$action}{$fundName} {$amount}";
  134. }
  135. /**
  136. * 获取资金名称
  137. *
  138. * @param mixed $fundId 资金ID
  139. * @return string
  140. */
  141. private function getFundName($fundId): string
  142. {
  143. try {
  144. // 获取资金类型描述
  145. $fundNames = AccountService::getFundsDesc();
  146. // 如果是枚举对象,获取其值
  147. $fundKey = is_object($fundId) ? $fundId->value : $fundId;
  148. return $fundNames[$fundKey] ?? "资金{$fundKey}";
  149. } catch (\Exception $e) {
  150. return "未知资金";
  151. }
  152. }
  153. /**
  154. * 解析备注信息
  155. *
  156. * @param string $remark 备注内容
  157. * @return array 解析后的信息数组
  158. */
  159. private function parseRemark(string $remark): array
  160. {
  161. $info = [];
  162. // 解析格式:币种消耗:2,消耗组:16,来源:shop_buy,ID:7
  163. // 使用更宽松的正则表达式来匹配中文和英文字符
  164. if (preg_match_all('/([^:,]+):([^,]+)/', $remark, $matches)) {
  165. for ($i = 0; $i < count($matches[1]); $i++) {
  166. $key = trim($matches[1][$i]);
  167. $value = trim($matches[2][$i]);
  168. // 转换中文键名为英文
  169. switch ($key) {
  170. case '来源':
  171. $info['source'] = $value;
  172. break;
  173. case 'ID':
  174. $info['id'] = (int)$value;
  175. break;
  176. case '消耗组':
  177. $info['consume_group'] = (int)$value;
  178. break;
  179. case '币种消耗':
  180. $info['fund_type'] = (int)$value;
  181. break;
  182. default:
  183. $info[$key] = $value;
  184. }
  185. }
  186. }
  187. return $info;
  188. }
  189. /**
  190. * 根据来源信息获取操作描述
  191. *
  192. * @param string $source 来源类型
  193. * @param int $id 来源ID
  194. * @param string $action 操作类型
  195. * @return string|null 操作描述,null表示使用默认格式
  196. */
  197. private function getSourceMessage(string $source, int $id, string $action): ?string
  198. {
  199. switch ($source) {
  200. case 'shop_buy':
  201. $itemName = $this->getShopItemName($id);
  202. return "购买{$itemName}";
  203. case '开启宝箱':
  204. case 'chest_open':
  205. return "开启宝箱";
  206. case 'house_upgrade':
  207. return "房屋升级";
  208. case 'land_upgrade':
  209. return "土地升级";
  210. case 'task_reward':
  211. return "任务奖励";
  212. case 'system_gift':
  213. return "系统赠送";
  214. case 'admin_operation':
  215. return "管理员操作";
  216. case 'test_command':
  217. return "测试操作";
  218. default:
  219. return null;
  220. }
  221. }
  222. /**
  223. * 获取商店商品名称
  224. *
  225. * @param int $itemId 商品ID
  226. * @return string
  227. */
  228. private function getShopItemName(int $itemId): string
  229. {
  230. try {
  231. $shopItem = \App\Module\Shop\Models\ShopItem::find($itemId);
  232. if ($shopItem && $shopItem->name) {
  233. return $shopItem->name;
  234. }
  235. return "商品{$itemId}";
  236. } catch (\Exception $e) {
  237. return "商品{$itemId}";
  238. }
  239. }
  240. /**
  241. * 是否应该记录此日志
  242. *
  243. * @param FundLogModel $record
  244. * @return bool
  245. */
  246. private function shouldLogRecord(FundLogModel $record): bool
  247. {
  248. // 可以在这里添加过滤规则
  249. // 例如:只记录金额大于某个值的变更
  250. // 跳过金额为0的记录
  251. if ($record->amount == 0) {
  252. return false;
  253. }
  254. // 可以添加更多过滤条件
  255. // 例如:跳过某些操作类型
  256. // if (in_array($record->operate_type, [...])) {
  257. // return false;
  258. // }
  259. return true;
  260. }
  261. /**
  262. * 重写转换方法,添加过滤逻辑
  263. *
  264. * @param FundLogModel $record 资金日志记录
  265. * @return array|null 用户日志数据,null表示跳过
  266. */
  267. protected function convertToUserLogWithFilter($record): ?array
  268. {
  269. // 检查是否应该记录此日志
  270. if (!$this->shouldLogRecord($record)) {
  271. return null;
  272. }
  273. return $this->convertToUserLog($record);
  274. }
  275. }