PointLogCollector.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. <?php
  2. namespace App\Module\Game\Logics\UserLogCollectors;
  3. use App\Module\Point\Models\PointLogModel;
  4. use App\Module\Point\Enums\LOG_TYPE;
  5. /**
  6. * 积分日志收集器
  7. *
  8. * 收集point_logs表的新增记录,转换为用户友好的日志消息
  9. */
  10. class PointLogCollector extends BaseLogCollector
  11. {
  12. /**
  13. * 源表名
  14. *
  15. * @var string
  16. */
  17. protected string $sourceTable = 'point_logs';
  18. /**
  19. * 源类型
  20. *
  21. * @var string
  22. */
  23. protected string $sourceType = 'point';
  24. /**
  25. * 获取新的记录
  26. *
  27. * @param int $lastProcessedId 上次处理的最大ID
  28. * @return \Illuminate\Database\Eloquent\Collection
  29. */
  30. protected function getNewRecords(int $lastProcessedId)
  31. {
  32. return PointLogModel::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 PointLogModel::where('create_time', '>', $lastProcessedTimestamp)
  46. ->orderBy('create_time')
  47. ->orderBy('id')
  48. ->limit($this->maxRecords)
  49. ->get();
  50. }
  51. /**
  52. * 获取记录的时间戳
  53. *
  54. * @param PointLogModel $record 积分日志记录
  55. * @return int 时间戳
  56. */
  57. protected function getRecordTimestamp($record): int
  58. {
  59. return $record->create_time;
  60. }
  61. /**
  62. * 获取记录的ID
  63. *
  64. * @param PointLogModel $record 积分日志记录
  65. * @return int 记录ID
  66. */
  67. protected function getRecordId($record): int
  68. {
  69. return $record->id;
  70. }
  71. /**
  72. * 转换记录为用户日志数据
  73. *
  74. * @param PointLogModel $record 积分日志记录
  75. * @return array|null 用户日志数据,null表示跳过
  76. */
  77. protected function convertToUserLog($record): ?array
  78. {
  79. try {
  80. // 检查是否应该记录此日志
  81. if (!$this->shouldLogRecord($record)) {
  82. return null;
  83. }
  84. // 获取积分类型名称
  85. $pointTypeName = $record->getPointTypeName();
  86. // 判断是获得还是消耗
  87. $amount = abs($record->amount);
  88. $action = $record->amount > 0 ? '获得' : '消耗';
  89. // 解析备注信息,生成用户友好的消息
  90. $message = $this->buildUserFriendlyMessage($record, $pointTypeName, $action, $amount);
  91. // 使用原始记录的时间
  92. $createdAt = date('Y-m-d H:i:s', $record->create_time);
  93. return $this->createUserLogData(
  94. $record->user_id,
  95. $message,
  96. $record->id,
  97. $createdAt
  98. );
  99. } catch (\Exception $e) {
  100. \Illuminate\Support\Facades\Log::error("转换积分日志失败", [
  101. 'record_id' => $record->id,
  102. 'error' => $e->getMessage()
  103. ]);
  104. return null;
  105. }
  106. }
  107. /**
  108. * 构建用户友好的消息
  109. *
  110. * @param PointLogModel $record 积分日志记录
  111. * @param string $pointTypeName 积分类型名称
  112. * @param string $action 操作类型(获得/消耗)
  113. * @param int $amount 积分数量
  114. * @return string 用户友好的消息
  115. */
  116. private function buildUserFriendlyMessage(PointLogModel $record, string $pointTypeName, string $action, int $amount): string
  117. {
  118. // 获取操作类型名称
  119. $operateTypeName = $this->getOperateTypeName($record->operate_type);
  120. // 根据操作类型生成不同的消息格式
  121. $message = match($record->operate_type) {
  122. LOG_TYPE::TASK_COMPLETE => "完成任务{$action} {$amount} {$pointTypeName}",
  123. LOG_TYPE::CHECKIN_REWARD => "签到{$action} {$amount} {$pointTypeName}",
  124. LOG_TYPE::ACTIVITY_REWARD => "活动奖励{$action} {$amount} {$pointTypeName}",
  125. LOG_TYPE::ACHIEVEMENT_REWARD => "成就奖励{$action} {$amount} {$pointTypeName}",
  126. LOG_TYPE::REFERRAL_REWARD => "推荐奖励{$action} {$amount} {$pointTypeName}",
  127. LOG_TYPE::PLANTING_REWARD => "种植作物{$action} {$amount} {$pointTypeName}",
  128. LOG_TYPE::POINT_CONSUME => "消费{$action} {$amount} {$pointTypeName}",
  129. LOG_TYPE::POINT_EXCHANGE => "兑换{$action} {$amount} {$pointTypeName}",
  130. LOG_TYPE::TRANSFER => $this->buildTransferMessage($record, $pointTypeName, $action, $amount),
  131. LOG_TYPE::CIRCULATION => "积分流转{$action} {$amount} {$pointTypeName}",
  132. LOG_TYPE::ADMIN_OPERATE => "管理员操作{$action} {$amount} {$pointTypeName}",
  133. LOG_TYPE::FREEZE => "冻结 {$amount} {$pointTypeName}",
  134. LOG_TYPE::UNFREEZE => "解冻 {$amount} {$pointTypeName}",
  135. LOG_TYPE::REFUND => "退还 {$amount} {$pointTypeName}",
  136. LOG_TYPE::DEDUCT => "扣除 {$amount} {$pointTypeName}",
  137. LOG_TYPE::SYSTEM_REWARD => "系统奖励{$action} {$amount} {$pointTypeName}",
  138. default => "{$operateTypeName}{$action} {$amount} {$pointTypeName}",
  139. };
  140. // 如果有备注且不是默认备注,添加到消息中
  141. if (!empty($record->remark) && !$this->isDefaultRemark($record->remark)) {
  142. $message .= "({$record->remark})";
  143. }
  144. return $message;
  145. }
  146. /**
  147. * 构建转账消息
  148. *
  149. * @param PointLogModel $record 积分日志记录
  150. * @param string $pointTypeName 积分类型名称
  151. * @param string $action 操作类型(未使用,保持接口一致性)
  152. * @param int $amount 积分数量
  153. * @return string 转账消息
  154. */
  155. private function buildTransferMessage(PointLogModel $record, string $pointTypeName, string $action, int $amount): string
  156. {
  157. // 根据金额正负判断是转入还是转出
  158. if ($record->amount > 0) {
  159. return "收到转账 {$amount} {$pointTypeName}";
  160. } else {
  161. return "转账给他人 {$amount} {$pointTypeName}";
  162. }
  163. }
  164. /**
  165. * 获取操作类型名称
  166. *
  167. * @param LOG_TYPE $operateType 操作类型
  168. * @return string 操作类型名称
  169. */
  170. private function getOperateTypeName(LOG_TYPE $operateType): string
  171. {
  172. try {
  173. return $operateType->getTypeName();
  174. } catch (\Exception $e) {
  175. return "未知操作";
  176. }
  177. }
  178. /**
  179. * 判断是否为默认备注
  180. *
  181. * @param string $remark 备注内容
  182. * @return bool 是否为默认备注
  183. */
  184. private function isDefaultRemark(string $remark): bool
  185. {
  186. $defaultRemarks = [
  187. '系统操作',
  188. '自动操作',
  189. '默认备注',
  190. '',
  191. ];
  192. return in_array(trim($remark), $defaultRemarks);
  193. }
  194. /**
  195. * 检查是否应该记录此日志
  196. *
  197. * @param PointLogModel $record 积分日志记录
  198. * @return bool 是否应该记录
  199. */
  200. private function shouldLogRecord(PointLogModel $record): bool
  201. {
  202. // 过滤掉测试操作
  203. if ($record->operate_type === LOG_TYPE::TEST) {
  204. return false;
  205. }
  206. // 过滤掉金额为0的记录
  207. if ($record->amount == 0) {
  208. return false;
  209. }
  210. // 过滤掉系统内部操作(可根据需要调整)
  211. $internalOperations = [
  212. // 可以在这里添加需要过滤的内部操作类型
  213. ];
  214. if (in_array($record->operate_type, $internalOperations)) {
  215. return false;
  216. }
  217. return true;
  218. }
  219. /**
  220. * 根据记录ID获取原始记录的时间戳
  221. *
  222. * @param int $recordId 记录ID
  223. * @return int 时间戳
  224. */
  225. protected function getOriginalRecordTimestamp(int $recordId): int
  226. {
  227. try {
  228. $record = PointLogModel::find($recordId);
  229. return $record ? $record->create_time : 0;
  230. } catch (\Exception $e) {
  231. \Illuminate\Support\Facades\Log::error("获取积分日志时间戳失败", [
  232. 'record_id' => $recordId,
  233. 'error' => $e->getMessage()
  234. ]);
  235. return 0;
  236. }
  237. }
  238. }