|null $beforeJson * @param array|null $afterJson */ public static function record( string $operatorType, int $operatorId, ?string $moduleCode = null, ?string $actionCode = null, ?string $targetType = null, ?string $targetId = null, ?array $beforeJson = null, ?array $afterJson = null, ?string $ip = null, ?string $userAgent = null, ): AuditLog { return AuditLog::query()->create([ 'operator_type' => $operatorType, 'operator_id' => $operatorId, 'module_code' => $moduleCode, 'action_code' => $actionCode, 'target_type' => $targetType, 'target_id' => $targetId, 'before_json' => $beforeJson, 'after_json' => $afterJson, 'ip' => $ip, 'user_agent' => self::truncateUserAgent($userAgent), ]); } /** * 从当前 HTTP 请求补全 IP、User-Agent(后台 / 玩家 API 调用方便)。 * * @param array|null $beforeJson * @param array|null $afterJson */ public static function recordFromRequest( Request $request, string $operatorType, int $operatorId, ?string $moduleCode = null, ?string $actionCode = null, ?string $targetType = null, ?string $targetId = null, ?array $beforeJson = null, ?array $afterJson = null, ): AuditLog { $row = self::record( $operatorType, $operatorId, $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, $request->ip(), $request->userAgent(), ); self::markAdminApiAuditRecorded($request); return $row; } /** 业务层已写审计时,避免 {@see RecordAdminApiAudit} 重复落库(FormRequest 可能与管道中的 Request 非同一实例)。 */ public static function markAdminApiAuditRecorded(Request $request): void { $request->attributes->set(RecordAdminApiAudit::ATTRIBUTE_AUDIT_RECORDED, true); try { $resolved = request(); if ($resolved !== $request) { $resolved->attributes->set(RecordAdminApiAudit::ATTRIBUTE_AUDIT_RECORDED, true); } } catch (\Throwable) { } } public static function recordForAdmin(AdminUser $admin, ?Request $request = null, ?string $moduleCode = null, ?string $actionCode = null, ?string $targetType = null, ?string $targetId = null, ?array $beforeJson = null, ?array $afterJson = null): AuditLog { if ($request !== null) { return self::recordFromRequest( $request, self::OPERATOR_ADMIN, (int) $admin->getKey(), $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, ); } return self::record( self::OPERATOR_ADMIN, (int) $admin->getKey(), $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, ); } public static function recordForPlayer(Player $player, ?Request $request = null, ?string $moduleCode = null, ?string $actionCode = null, ?string $targetType = null, ?string $targetId = null, ?array $beforeJson = null, ?array $afterJson = null): AuditLog { if ($request !== null) { return self::recordFromRequest( $request, self::OPERATOR_PLAYER, (int) $player->getKey(), $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, ); } return self::record( self::OPERATOR_PLAYER, (int) $player->getKey(), $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, ); } /** 定时任务或队列内无 Request 时使用。 */ public static function recordForSystem(?string $moduleCode = null, ?string $actionCode = null, ?string $targetType = null, ?string $targetId = null, ?array $beforeJson = null, ?array $afterJson = null): AuditLog { return self::record( self::OPERATOR_SYSTEM, 0, $moduleCode, $actionCode, $targetType, $targetId, $beforeJson, $afterJson, ); } private static function truncateUserAgent(?string $userAgent): ?string { if ($userAgent === null || $userAgent === '') { return null; } return mb_substr($userAgent, 0, 255); } }