From 7dc00f18bf97452caa9055375a3ae43f0149000e Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Tue, 5 May 2026 23:17:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(push):=20=E6=B7=BB=E5=8A=A0=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E4=BE=A7=E6=8E=A8=E9=80=81=E7=AE=A1=E7=90=86=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 PushManagementController,提供 /api/push/admin/** 接口供 租户平台查询用户设备在线状态、设备登录日志及发送测试离线推送。 在 PushDiagnosticsService 增加 searchByUserId 方法。 Co-Authored-By: Claude Sonnet 4.6 --- .../controller/PushManagementController.java | 67 +++++++++++++++++++ .../push/service/PushDiagnosticsService.java | 22 ++++++ 2 files changed, 89 insertions(+) create mode 100644 push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java diff --git a/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java b/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java new file mode 100644 index 0000000..8d01b1c --- /dev/null +++ b/push-service/src/main/java/com/xuqm/push/controller/PushManagementController.java @@ -0,0 +1,67 @@ +package com.xuqm.push.controller; + +import com.xuqm.common.model.ApiResponse; +import com.xuqm.push.entity.DeviceLoginLogEntity; +import com.xuqm.push.service.PushDiagnosticsService; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@RequestMapping("/api/push/admin") +public class PushManagementController { + + private final PushDiagnosticsService diagnosticsService; + + public PushManagementController(PushDiagnosticsService diagnosticsService) { + this.diagnosticsService = diagnosticsService; + } + + @GetMapping("/user-status") + public ResponseEntity> userStatus( + @RequestParam String appId, + @RequestParam String userId) { + return ResponseEntity.ok(ApiResponse.success(diagnosticsService.searchByUserId(appId, userId))); + } + + @GetMapping("/device-logs") + public ResponseEntity>> deviceLogs( + @RequestParam String appId, + @RequestParam String userId, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "20") int size) { + Page result = diagnosticsService.deviceLogs(appId, userId, page, size); + return ResponseEntity.ok(ApiResponse.success(Map.of( + "content", result.getContent(), + "total", result.getTotalElements(), + "totalPages", result.getTotalPages() + ))); + } + + @PostMapping("/test-offline") + public ResponseEntity> testOffline( + @RequestBody TestOfflineRequest request) { + PushDiagnosticsService.TestPushResult result = diagnosticsService.sendTestOfflineMessage( + request.appId(), + request.userId(), + request.title(), + request.body(), + request.payload()); + return ResponseEntity.ok(ApiResponse.success(result)); + } + + public record TestOfflineRequest( + String appId, + String userId, + String title, + String body, + String payload + ) {} +} diff --git a/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java b/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java index 0432196..62d818e 100644 --- a/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java +++ b/push-service/src/main/java/com/xuqm/push/service/PushDiagnosticsService.java @@ -90,6 +90,28 @@ public class PushDiagnosticsService { devices.stream().map(DeviceInfo::from).toList()); } + public PushTokenDiagnostics searchByUserId(String appId, String userId) { + ImPresenceClient.PresenceStatus presence = presenceClient.userStatus(appId, userId) + .orElse(new ImPresenceClient.PresenceStatus(appId, userId, false, 0L)); + List devices = tokenRepository.findByAppIdAndUserIdOrderByLastLoginAtDescUpdatedAtDesc(appId, userId); + List deliverableDevices = pushDispatcher.selectedPushTargets(appId, userId) + .stream() + .map(DeviceInfo::from) + .toList(); + DeviceInfo deliverable = deliverableDevices.isEmpty() ? null : deliverableDevices.get(0); + boolean canSendOffline = !presence.online() && !deliverableDevices.isEmpty(); + return new PushTokenDiagnostics( + "USER", + appId, + userId, + presence.online(), + presence.lastSeenAt(), + canSendOffline, + deliverable, + deliverableDevices, + devices.stream().map(DeviceInfo::from).toList()); + } + public TestPushResult sendTestOfflineMessage(String appId, String userId, String title, String body, String payload) { List targets = pushDispatcher.selectedPushTargets(appId, userId) .stream()