瀏覽代碼

更新推荐位管理和埋点信息查询

liuchengsen 3 周之前
父節點
當前提交
590147b762

+ 51 - 0
backend-java/docs/CHANGELOG.md

@@ -0,0 +1,51 @@
+# 更改文档 — 2026-07-30
+
+> **日期**: 2026-07-30  
+> **编译**: ✓ BUILD SUCCESS (JDK 21)  
+> **范围**: 7 文件修改
+
+---
+
+## 一、分析模块 — 事件类型切换
+
+### 新增 GET /api/v1/analytics/event-types
+- **AnalyticsController.java** — 新增端点、添加 java.util.List import
+- **AnalyticsService.java** — getEventTypes() 方法,返回所有 distinct 事件类型
+- **UserEventRepository.java** — indDistinctEventTypes() JPQL 查询
+
+已有 GET /events?eventType=xxx 过滤保持不变。前端调用 /event-types 获取选项列表渲染切换控件。
+
+---
+
+## 二、JWT 鉴权解析(不强鉴权)
+
+### JwtAuthFilter.java — doFilterInternal
+- 从 Authorization: Bearer header 提取 JWT,jwtUtil.getSubject() 解析
+- 校验通过 → SecurityContextHolder.getContext().setAuthentication()
+- 无 token 或解析失败 → 直接放行
+- inally 中 SecurityContextHolder.clearContext() 防泄漏
+- AnalyticsController.getCurrentUserKey() 无需改动,现在能正确获取 token 对应用户
+
+---
+
+## 三、快捷提问 — SQL 层 LIMIT + 管理端分页
+
+### QuickAskRepository.java
+- indByIsActiveTrueOrderBySortOrderAscIdAsc() 改为 @Query + Pageable,SQL 层加 LIMIT
+- 添加 Page import
+- indAllByOrderBySortOrderAscIdAsc() 同样改为 Pageable 分页版本
+
+### AdminKnowledgeService.java
+- listQuickAsks() — 去掉 subList 截断,传 PageRequest.of(0,6) 在 SQL 层限制
+- listAllQuickAsks() — 改为 listAllQuickAsks(page, pageSize),返回 Map (items/total/page/page_size/total_pages)
+- 
eorderQuickAsks() — sort_order → sortOrder(camelCase)
+- 添加 PageRequest import
+
+### AdminKnowledgeController.java
+- GET /quick-asks 添加 page (默认1) 和 pageSize (默认20) 参数
+
+---
+
+## 四、编码规范
+
+全文件 **UTF-8 without BOM**,换行 **LF**。后续编辑遵循此约定。

+ 4 - 3
backend-java/src/main/java/com/pharmacopoeia/controller/AdminKnowledgeController.java

@@ -3,7 +3,6 @@ package com.pharmacopoeia.controller;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.pharmacopoeia.config.UnifiedResponse;
 import com.pharmacopoeia.dto.*;
-import com.pharmacopoeia.entity.QuickAsk;
 import com.pharmacopoeia.service.AdminKnowledgeService;
 import com.pharmacopoeia.service.BrandRecommendService;
 import jakarta.validation.Valid;
@@ -244,8 +243,10 @@ public class AdminKnowledgeController {
     public ResponseEntity<Map<String, Object>> listQuickAskAuditLog(
             @RequestParam(defaultValue = "1") int page,
             @RequestParam(defaultValue = "20") int pageSize,
-            @RequestParam(required = false) String action) {
-        return ResponseEntity.ok(service.listQuickAskAuditLog(page, pageSize, action));
+            @RequestParam(required = false) String action,
+            @RequestParam(required = false) String startDate,
+            @RequestParam(required = false) String endDate) {
+        return ResponseEntity.ok(service.listQuickAskAuditLog(page, pageSize, action, startDate, endDate));
     }
 
    // ==================== 品牌管理 ====================

+ 15 - 0
backend-java/src/main/java/com/pharmacopoeia/repository/QuickAskAuditLogRepository.java

@@ -4,8 +4,12 @@ import com.pharmacopoeia.entity.QuickAskAuditLog;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
+import java.time.Instant;
+
 @Repository
 public interface QuickAskAuditLogRepository extends JpaRepository<QuickAskAuditLog, Long> {
 
@@ -16,4 +20,15 @@ public interface QuickAskAuditLogRepository extends JpaRepository<QuickAskAuditL
      * 前端 auditLog 接口可传 action 参数,后端自动使用此方法查询
      */
     Page<QuickAskAuditLog> findByActionOrderByCreatedAtDesc(String action, Pageable pageable);
+
+    @Query("SELECT a FROM QuickAskAuditLog a WHERE "
+         + "(:action IS NULL OR a.action = :action) AND "
+         + "(:startTime IS NULL OR a.createdAt >= :startTime) AND "
+         + "(:endTime IS NULL OR a.createdAt < :endTime) "
+         + "ORDER BY a.createdAt DESC")
+    Page<QuickAskAuditLog> findByFilters(
+            @Param("action") String action,
+            @Param("startTime") Instant startTime,
+            @Param("endTime") Instant endTime,
+            Pageable pageable);
 }

+ 19 - 10
backend-java/src/main/java/com/pharmacopoeia/service/AdminKnowledgeService.java

@@ -13,7 +13,6 @@ import com.pharmacopoeia.repository.QuestionRepository;
 import com.pharmacopoeia.repository.QuickAskAuditLogRepository;
 import com.pharmacopoeia.repository.QuickAskRepository;
 import com.pharmacopoeia.util.IpUtils;
-import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.security.core.context.SecurityContextHolder;
@@ -23,6 +22,9 @@ import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 
 import java.util.*;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
 import java.util.function.Consumer;
 
 @Service
@@ -389,7 +391,7 @@ public class AdminKnowledgeService {
         int updated = 0;
         for (Map<String, Object> item : items) {
             int id = ((Number) item.get("id")).intValue();
-            int sortOrder = ((Number) item.get("sort_order")).intValue();
+            int sortOrder = ((Number) item.get("sortOrder")).intValue();
             updated += quickAskRepository.updateSortOrder(id, sortOrder, operator);
         }
         return Map.of("ok", updated > 0, "message", "已更新 " + updated + " 条排序");
@@ -416,14 +418,21 @@ public class AdminKnowledgeService {
         return "unknown";
     }
 
-    public Map<String, Object> listQuickAskAuditLog(int page, int pageSize, String action) {
-        var pageable = org.springframework.data.domain.PageRequest.of(page - 1, pageSize);
-        Page<QuickAskAuditLog> result;
-        if (action != null && !action.isBlank()) {
-            result = auditLogRepository.findByActionOrderByCreatedAtDesc(action, pageable);
-        } else {
-            result = auditLogRepository.findAllByOrderByCreatedAtDesc(pageable);
-        }
+    public Map<String, Object> listQuickAskAuditLog(int page, int pageSize, String action,
+                                                       String startDate, String endDate) {
+        var pageable = PageRequest.of(page - 1, pageSize);
+
+        Instant startTime = startDate != null && !startDate.isBlank()
+                ? LocalDate.parse(startDate).atStartOfDay(ZoneOffset.UTC).toInstant()
+                : null;
+        Instant endTime = endDate != null && !endDate.isBlank()
+                ? LocalDate.parse(endDate).plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant()
+                : null;
+
+        var result = auditLogRepository.findByFilters(
+                action != null && !action.isBlank() ? action : null,
+                startTime, endTime, pageable);
+
         return Map.of(
                 "items", result.getContent(),
                 "page", page,