package com.pharmacopoeia.controller; import com.pharmacopoeia.dto.ApiResponse; import com.pharmacopoeia.service.AnalyticsService; import com.pharmacopoeia.util.IpUtils; import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Map; @RestController @RequestMapping("/api/v1/analytics") public class AnalyticsController { private final AnalyticsService analyticsService; private final HttpServletRequest request; public AnalyticsController(AnalyticsService analyticsService, HttpServletRequest request) { this.analyticsService = analyticsService; this.request = request; } // ==================== 事件 ==================== @GetMapping("/events") public ResponseEntity>> queryEvents( @RequestParam(required = false) String eventType, @RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "20") int pageSize) { return ResponseEntity.ok(ApiResponse.success( analyticsService.queryEvents(eventType, startDate, endDate, page, pageSize))); } @GetMapping("/events/{id}") public ResponseEntity>> getEventDetail(@PathVariable long id) { var detail = analyticsService.getEventDetail(id); if (detail.isEmpty()) { return ResponseEntity.ok(ApiResponse.>builder().code(404).message("事件不存在").build()); } return ResponseEntity.ok(ApiResponse.success(detail)); } @PostMapping("/events") public ResponseEntity>> saveEvent(@RequestBody Map body) { String eventType = (String) body.getOrDefault("event_type", "unknown"); @SuppressWarnings("unchecked") Map eventData = body.get("event_data") instanceof Map ? (Map) body.get("event_data") : Map.of(); String pageUrl = (String) body.getOrDefault("page_url", ""); String referrer = (String) body.getOrDefault("referrer", ""); String userKey = getCurrentUserKey(); String ip = IpUtils.getClientIp(request); String ua = request.getHeader("User-Agent"); analyticsService.saveEvent(userKey, eventType, eventData, pageUrl, referrer, ip, ua != null ? ua : ""); return ResponseEntity.accepted() .body(ApiResponse.>builder().code(202).message("accepted") .data(Map.of("status", "accepted")).build()); } // ==================== 概览 ==================== /** 概览数字:total_events / active_users / page_views / searches / ai_qa */ @GetMapping("/stats/overview") public ResponseEntity>> queryOverview( @RequestParam(required = false) String range) { if (range == null || range.isBlank()) { range = "total"; } return ResponseEntity.ok(ApiResponse.success(analyticsService.queryOverview(range))); } // ==================== 维度 ==================== /** 分页维度统计:dimension=ip/url/type/user/user_ip */ @GetMapping("/stats/dimension") public ResponseEntity>> queryDimension( @RequestParam String dimension, @RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "20") int pageSize) { return ResponseEntity.ok(ApiResponse.success( analyticsService.queryDimension(dimension, startDate, endDate, page, pageSize))); } private String getCurrentUserKey() { var auth = org.springframework.security.core.context.SecurityContextHolder .getContext().getAuthentication(); if (auth != null && auth.isAuthenticated() && !"anonymousUser".equals(auth.getPrincipal())) { return auth.getName(); } return "anonymous"; } }