ソースを参照

埋点概览调整

liuchengsen 3 週間 前
コミット
eb5e3e9b80

+ 8 - 6
backend-java/src/main/java/com/pharmacopoeia/controller/AnalyticsController.java

@@ -66,14 +66,16 @@ public class AnalyticsController {
 
     // ==================== 概览 ====================
 
-    /** 概览数字:total_events / active_users / page_views / searches / ai_qa */
+    /** 概览数字:total_events / active_users / page_views / searches / ai_qa
+     *  range: today | yesterday | week (=近7天) | total (=累计) | custom
+     *  custom 时传 startDate / endDate */
     @GetMapping("/stats/overview")
     public ResponseEntity<ApiResponse<Map<String, Object>>> queryOverview(
-            @RequestParam(required = false) String range) {
-        if (range == null || range.isBlank()) {
-            range = "total";
-        }
-        return ResponseEntity.ok(ApiResponse.success(analyticsService.queryOverview(range)));
+            @RequestParam(required = false) String range,
+            @RequestParam(required = false) String startDate,
+            @RequestParam(required = false) String endDate) {
+        return ResponseEntity.ok(ApiResponse.success(
+                analyticsService.queryOverview(range != null ? range : "total", startDate, endDate)));
     }
 
     // ==================== 维度 ====================

+ 5 - 0
backend-java/src/main/java/com/pharmacopoeia/repository/UserEventRepository.java

@@ -26,6 +26,11 @@ public interface UserEventRepository extends JpaRepository<UserEvent, Long>,
            "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime")
     long countDistinctUsers(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime);
 
+    /** 去重 IP 数 */
+    @Query("SELECT COUNT(DISTINCT e.ip) FROM UserEvent e " +
+           "WHERE e.createdAt >= :startTime AND e.createdAt < :endTime")
+    long countDistinctIps(@Param("startTime") Instant startTime, @Param("endTime") Instant endTime);
+
     /** 按类型 count */
     @Query("SELECT COUNT(e) FROM UserEvent e " +
            "WHERE e.eventType = :eventType " +

+ 42 - 16
backend-java/src/main/java/com/pharmacopoeia/service/AnalyticsService.java

@@ -105,33 +105,59 @@ public class AnalyticsService {
 
     // ==================== 概览数字 ====================
 
-    public Map<String, Object> queryOverview(String range) {
-        String today = LocalDate.now().toString();
-        Instant todayStart = parseDate(today);
-        Instant todayEnd = LocalDate.parse(today).plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant();
+    /**
+     * 统计概览
+     * @param range today | yesterday | week | total | custom
+     * @param startDate custom 的起始日期(yyyy-MM-dd),仅 range=custom 时生效
+     * @param endDate   custom 的结束日期(yyyy-MM-dd),仅 range=custom 时生效
+     */
+    public Map<String, Object> queryOverview(String range, String startDate, String endDate) {
+        if (range == null || range.isBlank()) {
+            range = "total";
+        }
+        Instant todayStart = parseDate(LocalDate.now().toString());
+        Instant todayEnd = LocalDate.now().plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant();
 
         Instant startTime;
         Instant endTime;
         String label;
 
-        if ("today".equals(range)) {
-            startTime = todayStart;
-            endTime = todayEnd;
-            label = "today";
-        } else if ("week".equals(range)) {
-            startTime = todayStart.minus(6, java.time.temporal.ChronoUnit.DAYS);
-            endTime = todayEnd;
-            label = "week";
-        } else {
-            startTime = Instant.EPOCH;
-            endTime = FAR_FUTURE;
-            label = "total";
+        switch (range) {
+            case "today":
+                startTime = todayStart;
+                endTime = todayEnd;
+                label = "today";
+                break;
+            case "yesterday":
+                startTime = todayStart.minus(1, java.time.temporal.ChronoUnit.DAYS);
+                endTime = todayStart;
+                label = "yesterday";
+                break;
+            case "week":
+                startTime = todayStart.minus(6, java.time.temporal.ChronoUnit.DAYS);
+                endTime = todayEnd;
+                label = "week";
+                break;
+            case "custom":
+                Instant customStart = startDate != null ? parseDate(startDate) : Instant.EPOCH;
+                Instant customEnd = endDate != null
+                        ? LocalDate.parse(endDate).plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant()
+                        : FAR_FUTURE;
+                startTime = customStart != null ? customStart : Instant.EPOCH;
+                endTime = customEnd;
+                label = "custom";
+                break;
+            default: // "total"
+                startTime = Instant.EPOCH;
+                endTime = FAR_FUTURE;
+                label = "total";
         }
 
         Map<String, Object> overview = new LinkedHashMap<>();
         overview.put("range", label);
         overview.put("total_events", repo.countTotal(startTime, endTime));
         overview.put("active_users", repo.countDistinctUsers(startTime, endTime));
+        overview.put("unique_ips", repo.countDistinctIps(startTime, endTime));
         overview.put("page_views", repo.countByType("page_view", startTime, endTime));
         overview.put("searches", repo.countByType("search", startTime, endTime));
         overview.put("ai_qa", repo.countByType("chat", startTime, endTime));