cc hace 3 semanas
padre
commit
94bcb55f95
Se han modificado 35 ficheros con 420 adiciones y 90 borrados
  1. 74 0
      .workbuddy/memory/2026-09-16.md
  2. 18 0
      ai-server/src/main/java/com/zsjz/ai/common/model/person/dto/DeletePersonGroupDTO.java
  3. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallContinuousController.java
  4. 3 3
      ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallNightController.java
  5. 2 1
      ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallRecordController.java
  6. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallSensitiveController.java
  7. 6 6
      ai-server/src/main/java/com/zsjz/ai/module/govern/controller/GovernTreeController.java
  8. 5 4
      ai-server/src/main/java/com/zsjz/ai/module/graph/controller/GraphController.java
  9. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/otg/controller/SpecialDateController.java
  10. 4 3
      ai-server/src/main/java/com/zsjz/ai/module/otg/controller/TimeSeriesController.java
  11. 10 13
      ai-server/src/main/java/com/zsjz/ai/module/person/controller/DataProfileController.java
  12. 2 1
      ai-server/src/main/java/com/zsjz/ai/module/person/controller/IntimacyController.java
  13. 3 3
      ai-server/src/main/java/com/zsjz/ai/module/person/controller/PersonBasicInfoController.java
  14. 7 8
      ai-server/src/main/java/com/zsjz/ai/module/person/controller/PersonGroupController.java
  15. 3 3
      ai-server/src/main/java/com/zsjz/ai/module/plat/controller/TableInfoController.java
  16. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/ExpressInfoController.java
  17. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackCellTowerController.java
  18. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackEnLocalController.java
  19. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackMeetController.java
  20. 5 4
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackTogetherLiveController.java
  21. 4 3
      ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackTogetherTravelController.java
  22. 2 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/CashKeyController.java
  23. 1 1
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/FinancialKeyController.java
  24. 2 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/FixedDepositKeyController.java
  25. 4 3
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransBigController.java
  26. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransCardHoldController.java
  27. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransCashFlowController.java
  28. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransContinuousController.java
  29. 2 1
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFinancialController.java
  30. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFixedDepositController.java
  31. 2 1
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFrequencyController.java
  32. 4 3
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFundFlowController.java
  33. 2 1
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransRecordController.java
  34. 3 2
      ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransSensitiveController.java
  35. 219 0
      controller-request-body-audit.md

+ 74 - 0
.workbuddy/memory/2026-09-16.md

@@ -33,3 +33,77 @@
   `/c/Users/cc/.workbuddy/binaries/node/versions/22.22.2-3/node.exe ./node_modules/eslint/bin/eslint.js ...`
   同理 `./node_modules/vue-tsc/bin/vue-tsc.js`。`git` 可用;`rm` 用 node 的 `fs.unlinkSync` 兜底。
 - 类型检查输出重定向到仓库内文件 + Grep 工具过滤,比试图用管道 grep 更可靠(用完记得删)。
+
+---
+
+## ★★ 全量 Controller `@RequestBody` 缺失审计(2026-09-16 下午)
+
+用户要求:「检查项目中所有 controller 中有些接口是不是没有加 @RequestBody」。
+
+### 结论(报告:`controller-request-body-audit.md`,仓库根)
+`ai-server` 45 个 controller / 98 个写端点(POST/PUT/PATCH)中,**76 个端点参数没有绑定注解**,
+其中 **75 个已被确认为真实缺陷**(前端用 `defHttp.postJson` 即 JSON body 调用 → body 被丢弃、参数全 null),
+1 个暂无前端调用方(`/trans/cashFlow/statTransCashCallBeforeAfterTimeLine`)。
+已正确 21 个(含上一轮修的 `/chat/**`、`/dm/preFile`、`/case/create|open|updatePwd` 等)+ 1 个 multipart。
+
+### ★ 判定标准(这套判据以后可直接复用)
+- 前端 axios **默认 content-type 是 `application/x-www-form-urlencoded`**(`core/utils/http/axios/index.ts:275`),
+  `defHttp.post` 的 `data` 会被 `qs.stringify` 成表单 —— **不加注解的 POJO 能正常绑定**;
+  **只有 `defHttp.postJson`**(`Axios.ts:187`,显式 `application/json` + `data` 作 body)才要求后端有 `@RequestBody`。
+- 所以「POST 端点没加 @RequestBody」本身不是 bug,**必须交叉核对前端调用方式**才能定性。
+- 已排除会推翻结论的因素:项目**没有**自定义 `HandlerMethodArgumentResolver`/`WebMvcConfigurer`,
+  也**没有**重写 body→parameter 的 Filter/`HttpServletRequestWrapper`(全仓 grep 0 命中)→ 走 Spring 默认 ModelAttribute 绑定。
+
+### 需特殊修法的 4 个端点(不能无脑加注解)
+| 端点 | 现状 | 说明 |
+| --- | --- | --- |
+| `/pg/delete` | 后端 `delete(Long id)`,前端 body `{id}` | 直接加 `@RequestBody` 会 400(对象→Long);应改 `@RequestParam`+前端 params,或引入 IdDTO |
+| `/intimacy/modify` | `List<Intimacy>`,前端发数组 | `@RequestBody List<Intimacy>` 即可 |
+| `/pbi/personOrder` | `List<PersonBasicInfo>`,前端发数组 | 同上 |
+| `/call/night/statSecondCallNight` | 参数误写成 `@Param("query")`(MyBatis 注解) | 去掉 `@Param` 换 `@RequestBody` |
+
+### 其它发现
+- `ResidentPopulationController` 只有类级 `@RequestMapping("/rp")`、**零个方法**(空壳类)。
+- 9 个 controller 只有 GET 端点:System/Tower/Govern/Search/CleanErrorLog/AgentResult/AgentPythonFile/TransFastFundFlow/ResidentPopulation。
+
+### ★ 修复(用户催「一点活也没干」后当日执行完毕)
+- **75 个端点全部补上 `@RequestBody`**:32 个 controller 改动(74 个 POJO 参数前插注解 +
+  `/pg/delete` 改 DTO + `statSecondCallNight` 的 MyBatis `@Param("query")` 替换),新增 DTO
+  `common/model/person/dto/DeletePersonGroupDTO.java`(前端发 `{id}`,简单类型不能直接加注解)。
+- 清理:删掉被替换后失效的 `import org.apache.ibatis.annotations.Param`(CallNightController)、
+  4 处与 `annotation.*` 通配符重复的显式 `RequestBody` import、3 个 controller 里未使用的 MyBatis `@Delete` import。
+- **验证三连**:① 结构比对(修复前后:映射注解/URL **零改动**,签名除注解外零改动,新增行 = 75 签名行 + 32 import);
+  ② `mvn -pl ai-server -B clean compile` → **BUILD SUCCESS**(621 源文件);③ 复扫 audit → `broken=0 / missingBindingAnnotation=0 / annotated=97 + multipart=1`。
+- 报告 `controller-request-body-audit.md` 顶部加「〇、修复记录」,第 1~8 节保留修复前状态留档。
+- 备份:`C:/Users/cc/AppData/Local/Temp/zsjz-audit/backup-controllers/`(45 个 controller 修复前副本)。
+  ★ 32 个文件中 **`DataProfileController.java` 在我修复前就与 HEAD 不同**(import 被改成 `annotation.*` 通配符,
+  非我所为,已保留)→ 该文件不能用 `git checkout` 回退(会连带丢掉那处改动),要用备份副本;其余 31 个可 `git checkout`。
+- 未做:运行期端到端验证(起服务发 JSON body 请求确认筛选生效)。
+
+### ★★ 本机 Maven 调用方式(shim 太残,cygpath/bash 都不可用)
+`mvn.cmd`、`mvn-run.sh` 都跑不起来(shim 里连 `bash`/`cygpath` 都 command not found)。**可行解**:直接调 java + classworlds,
+全用 Windows 路径,HOST 用托管 JDK(JAVA_HOME 是 BellSoft JDK 25,能编 release 17 的代码 + Lombok):
+
+```bash
+cd /e/workspace/zsjz-ai && "/c/Program Files/BellSoft/LibericaJDK-25-Full/bin/java.exe" \
+  -classpath "D:\soft\apache-maven-3.9.12-bin\boot\plexus-classworlds-2.9.0.jar" \
+  "-Dclassworlds.conf=D:\soft\apache-maven-3.9.12-bin\bin\m2.conf" \
+  "-Dmaven.home=D:\soft\apache-maven-3.9.12-bin" \
+  "-Dmaven.multiModuleProjectDirectory=E:\workspace\zsjz-ai" \
+  org.codehaus.plexus.classworlds.launcher.Launcher -pl ai-server -B clean compile \
+  > E:/workspace/zsjz-ai/.build-log.txt 2>&1; echo "EXIT=$?"
+```
+(注意 plexus-classworlds 版本是 **2.9.0** 不是 2.8.0;输出重定向到文件再用 Grep 工具过滤,管道 grep 不可用。)
+
+### 复用工具(已固化为 skill)
+`~/.workbuddy/skills/spring-requestbody-audit/`:
+`scripts/audit.cjs`(审计+交叉比对+生成报告)、`scripts/fix.cjs`(按精确偏移批量补注解,dry-run/--apply/--skip)、
+`scripts/verify-fix.cjs`(结构比对,强制断言「URL/签名除注解外零改动」)。
+SKILL.md 里写了完整 9 步修复流程与本机编译方式。
+★ 写这类脚本踩过的 3 个解析坑(务必照抄规避):
+1. TS 泛型里可能含 `{`(`postJson<{ [key: string]: X }>`)→ 找参数对象必须从「`(` 之后」开始找 `{`;
+2. **嵌套泛型** `<Page<X>>` / `<Record<string, any>>` 会让 `<[^>]*>` 正则整个失配 → 必须手写「跳过可选泛型块」的扫描;
+3. 后端类级 `@RequestMapping("cr")` **不带前导斜杠**(45 个里只有这 1 个)→ 拼路径时要补 `/`,否则匹配不上前端 URL。
+审计覆盖率自查法:统计前端 `defHttp.(postJson|post|put|patch|uploadFile|request)` 总数(本次 174)与解析出的调用点数(171),
+差值必须能逐个解释(本次 3 个全是注释里的假命中)。
+

+ 18 - 0
ai-server/src/main/java/com/zsjz/ai/common/model/person/dto/DeletePersonGroupDTO.java

@@ -0,0 +1,18 @@
+package com.zsjz.ai.common.model.person.dto;
+
+import lombok.Data;
+
+/**
+ * 删除分组请求 DTO
+ *
+ * <p>前端 {@code person/api/personApi.ts} 的 {@code deletePersonGroup} 以 JSON body
+ * 提交 {@code {id}},因此后端必须用 {@code @RequestBody} 绑定到本 DTO;
+ * 若直接写 {@code Long id},即使加了 {@code @RequestBody} 也会因为
+ * 「JSON 对象 → Long」反序列化失败而报 400。</p>
+ */
+@Data
+public class DeletePersonGroupDTO {
+
+    /** 分组 ID(person_group.id) */
+    private Long id;
+}

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallContinuousController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.call.query.CallContinuousQuery;
 import com.zsjz.ai.module.call.service.CallContinuousService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -32,7 +33,7 @@ public class CallContinuousController {
      * @return 分页的连续通话 DTO 列表
      */
     @PostMapping("/statFirstCallContinuous")
-    public Result<Page<CallContinuousDTO>> statFirstCallContinuous(CallContinuousQuery query) {
+    public Result<Page<CallContinuousDTO>> statFirstCallContinuous(@RequestBody CallContinuousQuery query) {
         return Result.succeed(callContinuousService.statFirstCallContinuous(query));
     }
 
@@ -44,7 +45,7 @@ public class CallContinuousController {
      * @return 分页的连续通话 DTO 列表
      */
     @PostMapping("/statSecondCallContinuous")
-    public Result<Page<CallContinuousDTO>> statSecondCallContinuous(CallContinuousQuery query) {
+    public Result<Page<CallContinuousDTO>> statSecondCallContinuous(@RequestBody CallContinuousQuery query) {
         return Result.succeed(callContinuousService.statSecondCallContinuous(query));
     }
 }

+ 3 - 3
ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallNightController.java

@@ -5,9 +5,9 @@ import com.zsjz.ai.common.config.Result;
 import com.zsjz.ai.common.model.call.dto.CallNightDTO;
 import com.zsjz.ai.common.model.call.query.CallNightQuery;
 import com.zsjz.ai.module.call.service.CallNightService;
-import org.apache.ibatis.annotations.Param;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -35,7 +35,7 @@ public class CallNightController {
      * @return 分页的夜间通话 DTO 列表,按时间段展示通话统计
      */
     @PostMapping("/statFirstCallNight")
-    public Result<Page<CallNightDTO>> statFirstCallNight(CallNightQuery query) {
+    public Result<Page<CallNightDTO>> statFirstCallNight(@RequestBody CallNightQuery query) {
         return Result.succeed(callNightService.statFirstCallNight(query));
     }
 
@@ -47,7 +47,7 @@ public class CallNightController {
      * @return 夜间通话 DTO 列表,包含详细的夜间通话统计信息
      */
     @PostMapping("/statSecondCallNight")
-    public Result<List<CallNightDTO>> statSecondCallNight(@Param("query") CallNightQuery query) {
+    public Result<List<CallNightDTO>> statSecondCallNight(@RequestBody CallNightQuery query) {
         return Result.succeed(callNightService.statSecondCallNight(query));
     }
 }

+ 2 - 1
ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallRecordController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.call.query.CallRecordQuery;
 import com.zsjz.ai.module.call.service.CallRecordService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -31,7 +32,7 @@ public class CallRecordController {
      * @return 分页的通话记录列表
      */
     @PostMapping("getCallRecord")
-    public Result<Page<CallRecord>> getCallRecord(CallRecordQuery query) {
+    public Result<Page<CallRecord>> getCallRecord(@RequestBody CallRecordQuery query) {
         return Result.succeed(callRecordService.getCallRecord(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/call/controller/CallSensitiveController.java

@@ -8,6 +8,7 @@ import com.zsjz.ai.common.model.call.query.CallSensitiveQuery;
 import com.zsjz.ai.module.call.service.CallSensitiveService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -33,7 +34,7 @@ public class CallSensitiveController {
      * @return 分页的敏感通话 DTO 列表
      */
     @PostMapping("/statFirstCallSensitive")
-    public Result<Page<CallSensitiveDTO>> statFirstCallSensitive(CallSensitiveQuery query) {
+    public Result<Page<CallSensitiveDTO>> statFirstCallSensitive(@RequestBody CallSensitiveQuery query) {
         return Result.succeed(callSensitiveService.statFirstCallSensitive(query));
     }
 
@@ -45,7 +46,7 @@ public class CallSensitiveController {
      * @return 分页的通话记录列表
      */
     @PostMapping("/statSecondCallSensitive")
-    public Result<Page<CallRecord>> statSecondCallSensitive(CallSensitiveQuery query) {
+    public Result<Page<CallRecord>> statSecondCallSensitive(@RequestBody CallSensitiveQuery query) {
         return Result.succeed(callSensitiveService.statSecondCallSensitive(query));
     }
 }

+ 6 - 6
ai-server/src/main/java/com/zsjz/ai/module/govern/controller/GovernTreeController.java

@@ -56,7 +56,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为人员列表和总数
      */
     @PostMapping("/getTreeTransPersonPage")
-    public Result<Map<String, Object>> getTreeTransPersonPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeTransPersonPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeTransPersonPage(dto));
     }
 
@@ -68,7 +68,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为银行卡列表和总数
      */
     @PostMapping("/getTreeTransBankPage")
-    public Result<Map<String, Object>> getTreeTransBankPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeTransBankPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeTransBankPage(dto));
     }
 
@@ -80,7 +80,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为人员列表和总数
      */
     @PostMapping("/getTreeCallPersonPage")
-    public Result<Map<String, Object>> getTreeCallPersonPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeCallPersonPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeCallPersonPage(dto));
     }
 
@@ -92,7 +92,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为对方号码列表和总数
      */
     @PostMapping("/getTreeCallOperPage")
-    public Result<Map<String, Object>> getTreeCallOperPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeCallOperPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeCallOperPage(dto));
     }
 
@@ -104,7 +104,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为开户信息列表和总数
      */
     @PostMapping("/getTreeCallPersonUseOpenInfoPage")
-    public Result<Map<String, Object>> getTreeCallPersonUseOpenInfoPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeCallPersonUseOpenInfoPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeCallPersonUseOpenInfoPage(dto));
     }
 
@@ -116,7 +116,7 @@ public class GovernTreeController {
      * @return 包含分页数据的 Map,key 为"list"和"total",分别为开户信息列表和总数
      */
     @PostMapping("/getTreeCallOperUseOpenInfoPage")
-    public Result<Map<String, Object>> getTreeCallOperUseOpenInfoPage(GovernTreeQuery dto) {
+    public Result<Map<String, Object>> getTreeCallOperUseOpenInfoPage(@RequestBody GovernTreeQuery dto) {
         return Result.succeed(governTreeService.getTreeCallOperUseOpenInfoPage(dto));
     }
 }

+ 5 - 4
ai-server/src/main/java/com/zsjz/ai/module/graph/controller/GraphController.java

@@ -10,6 +10,7 @@ import com.zsjz.ai.common.model.graph.query.GraphTransDetailQuery;
 import com.zsjz.ai.common.model.trans.entity.TransRecord;
 import com.zsjz.ai.module.graph.service.GraphService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -37,7 +38,7 @@ public class GraphController {
      * @return 图谱数据(节点和边的集合)
      */
     @PostMapping("/view")
-    public Result<Map<String, Object>> graph(GraphQuery query) {
+    public Result<Map<String, Object>> graph(@RequestBody GraphQuery query) {
         return Result.succeed(graphService.graph(query));
     }
 
@@ -49,7 +50,7 @@ public class GraphController {
      * @return 分页的交易记录列表
      */
     @PostMapping("/transDetail")
-    public Result<Page<TransRecord>> transDetail(GraphTransDetailQuery query) {
+    public Result<Page<TransRecord>> transDetail(@RequestBody GraphTransDetailQuery query) {
         return Result.succeed(graphService.transDetail(query));
     }
 
@@ -61,12 +62,12 @@ public class GraphController {
      * @return 分页的通话记录列表
      */
     @PostMapping("/callDetail")
-    public Result<Page<CallRecord>> callDetail(GraphCallDetailQuery query) {
+    public Result<Page<CallRecord>> callDetail(@RequestBody GraphCallDetailQuery query) {
         return Result.succeed(graphService.callDetail(query));
     }
 
     @PostMapping("/nodeDetail")
-    public Result<Map<String, Object>> nodeDetail(GraphCallDetailQuery query) {
+    public Result<Map<String, Object>> nodeDetail(@RequestBody GraphCallDetailQuery query) {
         return Result.succeed(graphService.nodeDetail(query));
     }
 

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/otg/controller/SpecialDateController.java

@@ -6,6 +6,7 @@ import com.zsjz.ai.module.otg.service.SpecialDateService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -24,13 +25,13 @@ public class SpecialDateController {
     }
 
     @PostMapping("/create")
-    public Result<Void> create(SpecialDateRecord sdr) {
+    public Result<Void> create(@RequestBody SpecialDateRecord sdr) {
         specialDateService.create(sdr);
         return Result.succeed();
     }
 
     @PostMapping("/update")
-    public Result<Void> update(SpecialDateRecord sdr) {
+    public Result<Void> update(@RequestBody SpecialDateRecord sdr) {
         specialDateService.update(sdr);
         return Result.succeed();
     }

+ 4 - 3
ai-server/src/main/java/com/zsjz/ai/module/otg/controller/TimeSeriesController.java

@@ -6,6 +6,7 @@ import com.zsjz.ai.common.model.otg.query.TimeSeriesQuery;
 import com.zsjz.ai.module.otg.service.TimeSeriesService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -20,17 +21,17 @@ public class TimeSeriesController {
     private TimeSeriesService timeSeriesService;
 
     @PostMapping("/list")
-    public Result<List<TimeSeries>> getTimeSeries(TimeSeriesQuery query) {
+    public Result<List<TimeSeries>> getTimeSeries(@RequestBody TimeSeriesQuery query) {
         return Result.succeed(timeSeriesService.getTimeSeries(query));
     }
 
     @PostMapping("/detailTimeSeries")
-    public Result<Map<String, Object>> detailTimeSeries(TimeSeriesQuery query) {
+    public Result<Map<String, Object>> detailTimeSeries(@RequestBody TimeSeriesQuery query) {
         return Result.succeed(timeSeriesService.detailTimeSeries(query));
     }
 
     @PostMapping("/jump")
-    public Result<List<TimeSeries>> jumpTimeSeries(TimeSeriesQuery query) {
+    public Result<List<TimeSeries>> jumpTimeSeries(@RequestBody TimeSeriesQuery query) {
         return Result.succeed(timeSeriesService.jumpTimeSeries(query));
     }
 }

+ 10 - 13
ai-server/src/main/java/com/zsjz/ai/module/person/controller/DataProfileController.java

@@ -12,10 +12,7 @@ import com.zsjz.ai.common.model.trans.query.TransBankCardInfoQuery;
 import com.zsjz.ai.module.person.service.DataProfileService;
 import com.zsjz.ai.module.person.service.IntimacyService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -54,7 +51,7 @@ public class DataProfileController {
      */
     @PostMapping("/callOftenTop10")
     //@Cache(key = "#{query.cacheKey()}", tags = StrConsts.CACHE_TAG_QING_JIAN)
-    public Page<CallOftenTop10DTO> callOftenTop10(CallOftenTop10Query query) {
+    public Page<CallOftenTop10DTO> callOftenTop10(@RequestBody CallOftenTop10Query query) {
         return dataProfileService.callOftenTop10(query);
     }
 
@@ -67,7 +64,7 @@ public class DataProfileController {
      */
     @PostMapping("/callStatStation")
     //@Cache(key = "#{query.cacheKey()}", tags = StrConsts.CACHE_TAG_QING_JIAN)
-    public List<CallStatStationDTO> callStatStation(CallStatStationQuery query) {
+    public List<CallStatStationDTO> callStatStation(@RequestBody CallStatStationQuery query) {
         return dataProfileService.callStatStation(query);
     }
 
@@ -79,7 +76,7 @@ public class DataProfileController {
      * @return 分页的通话记录汇总数据,包含通话详情及统计信息
      */
     @PostMapping("/getCallRecordSummary")
-    public Result<Page<CallRecordSummaryDTO>> getCallRecordSummary(CallRecordSummaryQuery query) {
+    public Result<Page<CallRecordSummaryDTO>> getCallRecordSummary(@RequestBody CallRecordSummaryQuery query) {
         return Result.succeed(dataProfileService.getCallRecordSummary(query));
     }
 
@@ -91,7 +88,7 @@ public class DataProfileController {
      * @return 手机号码及运营商信息列表,包含未匹配到的号码补充信息
      */
     @PostMapping("/getCallOperPhoneInfo")
-    public Result<List<CallOpenInfo>> getCallOperPhoneInfo(CallOperPhoneInfoQuery query) {
+    public Result<List<CallOpenInfo>> getCallOperPhoneInfo(@RequestBody CallOperPhoneInfoQuery query) {
         return Result.succeed(dataProfileService.getCallOperPhoneInfo(query));
     }
 
@@ -118,7 +115,7 @@ public class DataProfileController {
      * @return 分页的最常交易 TOP10 列表,包含交易对手信息及交易频次统计
      */
     @PostMapping("/transOfPersons")
-    public Result<Page<TransOftenTop10DTO>> transOfPersons(TransOftenTop10Query query) {
+    public Result<Page<TransOftenTop10DTO>> transOfPersons(@RequestBody TransOftenTop10Query query) {
         return Result.succeed(dataProfileService.transOfPersons(query));
     }
 
@@ -130,7 +127,7 @@ public class DataProfileController {
      * @return 分页的交易记录汇总数据,包含交易统计信息
      */
     @PostMapping("/getTransRecordSummary")
-    public Result<Page<TransRecordSummaryDTO>> getTransRecordSummary(TransRecordSummaryQuery query) {
+    public Result<Page<TransRecordSummaryDTO>> getTransRecordSummary(@RequestBody TransRecordSummaryQuery query) {
         return Result.succeed(dataProfileService.statTransRecordSummary(query));
     }
 
@@ -154,7 +151,7 @@ public class DataProfileController {
      * @return 银行卡交易详细信息列表,包含收支汇总、净额、账户余额及开户销户时间等
      */
     @PostMapping("/getTransBankCardInfo")
-    public Result<List<TransBankCardInfoDTO>> getTransBankCardInfo(TransBankCardInfoQuery query) {
+    public Result<List<TransBankCardInfoDTO>> getTransBankCardInfo(@RequestBody TransBankCardInfoQuery query) {
         return Result.succeed(dataProfileService.getTransBankCardInfo(query));
     }
 
@@ -166,7 +163,7 @@ public class DataProfileController {
      * @return 月度交易金额趋势列表,包含月份和对应的交易金额
      */
     @PostMapping("/transAmountTrendYM")
-    public Result<List<TransTrendDTO>> transAmountTrendYM(TransTrendQuery query) {
+    public Result<List<TransTrendDTO>> transAmountTrendYM(@RequestBody TransTrendQuery query) {
         return Result.succeed(dataProfileService.transAmountTrendYM(query));
     }
 
@@ -178,7 +175,7 @@ public class DataProfileController {
      * @return 年度交易金额趋势列表,包含年份和对应的交易金额
      */
     @PostMapping("/transAmountTrendY")
-    public Result<List<TransTrendDTO>> transAmountTrendY(TransTrendQuery query) {
+    public Result<List<TransTrendDTO>> transAmountTrendY(@RequestBody TransTrendQuery query) {
         return Result.succeed(dataProfileService.transAmountTrendY(query));
     }
 

+ 2 - 1
ai-server/src/main/java/com/zsjz/ai/module/person/controller/IntimacyController.java

@@ -6,6 +6,7 @@ import com.zsjz.ai.module.person.service.IntimacyService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -30,7 +31,7 @@ public class IntimacyController {
     }
 
     @PostMapping("/modify")
-    public Result<Void> update(List<Intimacy> intimacyList) {
+    public Result<Void> update(@RequestBody List<Intimacy> intimacyList) {
         intimacyService.update(intimacyList);
         return Result.succeed();
     }

+ 3 - 3
ai-server/src/main/java/com/zsjz/ai/module/person/controller/PersonBasicInfoController.java

@@ -22,7 +22,7 @@ public class PersonBasicInfoController {
      * @param dto 人员信息
      */
     @PostMapping("/create")
-    public Result<Void> create(PersonBasicInfoDTO dto) {
+    public Result<Void> create(@RequestBody PersonBasicInfoDTO dto) {
         personBasicInfoService.create(dto);
         return Result.succeed();
     }
@@ -44,7 +44,7 @@ public class PersonBasicInfoController {
      * @param dto 人员信息
      */
     @PostMapping("/update")
-    public Result<Void> update(PersonBasicInfoDTO dto) {
+    public Result<Void> update(@RequestBody PersonBasicInfoDTO dto) {
         personBasicInfoService.update(dto);
         return Result.succeed();
     }
@@ -55,7 +55,7 @@ public class PersonBasicInfoController {
     }
 
     @PostMapping("/personOrder")
-    public Result<Void> personOrder(List<PersonBasicInfo> list) {
+    public Result<Void> personOrder(@RequestBody List<PersonBasicInfo> list) {
         personBasicInfoService.personOrder(list);
         return Result.succeed();
     }

+ 7 - 8
ai-server/src/main/java/com/zsjz/ai/module/person/controller/PersonGroupController.java

@@ -1,14 +1,13 @@
 package com.zsjz.ai.module.person.controller;
 
 import com.zsjz.ai.common.model.person.dto.AddPersonGroupDTO;
+import com.zsjz.ai.common.model.person.dto.DeletePersonGroupDTO;
 import com.zsjz.ai.common.config.Result;
 import com.zsjz.ai.common.model.person.entity.PersonGroup;
 import com.zsjz.ai.module.person.service.PersonGroupService;
-import org.apache.ibatis.annotations.Delete;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
-
 import java.util.List;
 
 @RestController
@@ -29,7 +28,7 @@ public class PersonGroupController {
      * @param personGroup 分组信息
      */
     @PostMapping("/create")
-    public Result<Void> create(PersonGroup personGroup) {
+    public Result<Void> create(@RequestBody PersonGroup personGroup) {
         personGroupService.create(personGroup);
         return Result.succeed();
     }
@@ -40,7 +39,7 @@ public class PersonGroupController {
      * @param personGroup 分组信息
      */
     @PostMapping("/update")
-    public Result<Void> update(PersonGroup personGroup) {
+    public Result<Void> update(@RequestBody PersonGroup personGroup) {
         personGroupService.updateById(personGroup);
         return Result.succeed();
     }
@@ -48,11 +47,11 @@ public class PersonGroupController {
     /**
      * 删除分组
      *
-     * @param id 分组ID
+     * @param dto 分组 ID(前端以 JSON body 提交 {@code {id}})
      */
     @PostMapping("/delete")
-    public Result<Void> delete(Long id) {
-        personGroupService.deleteById(id);
+    public Result<Void> delete(@RequestBody DeletePersonGroupDTO dto) {
+        personGroupService.deleteById(dto.getId());
         return Result.succeed();
     }
 
@@ -63,7 +62,7 @@ public class PersonGroupController {
      * @param dto 添加人员信息
      */
     @PostMapping("/addPerson")
-    public Result<Void> addPerson(AddPersonGroupDTO dto) {
+    public Result<Void> addPerson(@RequestBody AddPersonGroupDTO dto) {
         personGroupService.addPerson(dto);
         return Result.succeed();
     }

+ 3 - 3
ai-server/src/main/java/com/zsjz/ai/module/plat/controller/TableInfoController.java

@@ -8,8 +8,8 @@ import com.zsjz.ai.common.enums.HasInnerEnum;
 import com.zsjz.ai.common.model.plat.TableInfoQuery;
 import com.zsjz.ai.common.model.plat.entity.TableInfo;
 import com.zsjz.ai.module.plat.service.TableInfoService;
-import org.apache.ibatis.annotations.Delete;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -70,7 +70,7 @@ public class TableInfoController {
      * 创建模板
      */
     @PostMapping("/create")
-    public Result<Void> create(TableInfo tableInfo) {
+    public Result<Void> create(@RequestBody TableInfo tableInfo) {
         tableInfoService.create(tableInfo, null);
         return Result.succeed();
     }
@@ -79,7 +79,7 @@ public class TableInfoController {
      * 更新模板
      */
     @PostMapping("/update")
-    public Result<Void> update(TableInfo tableInfo) {
+    public Result<Void> update(@RequestBody TableInfo tableInfo) {
         tableInfoService.update(tableInfo);
         return Result.succeed();
     }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/track/controller/ExpressInfoController.java

@@ -8,6 +8,7 @@ import com.zsjz.ai.common.model.track.query.ExpressInfoQuery;
 import com.zsjz.ai.module.track.service.TrackExpressInfoService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -30,7 +31,7 @@ public class ExpressInfoController {
      * @return 快递信息 DTO 分页结果
      */
     @PostMapping("/statFirstExpressInfo")
-    public Result<Page<ExpressDTO>> statFirstExpressInfo(ExpressInfoQuery query) {
+    public Result<Page<ExpressDTO>> statFirstExpressInfo(@RequestBody ExpressInfoQuery query) {
         return Result.succeed(trackExpressInfoService.statFirstExpressInfo(query));
     }
 
@@ -41,7 +42,7 @@ public class ExpressInfoController {
      * @return 快递信息实体分页结果
      */
     @PostMapping("/statSecondExpressInfo")
-    public Result<Page<ExpressInfo>> statSecondExpressInfo(ExpressInfoQuery query) {
+    public Result<Page<ExpressInfo>> statSecondExpressInfo(@RequestBody ExpressInfoQuery query) {
         return Result.succeed(trackExpressInfoService.statSecondExpressInfo(query));
     }
 

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackCellTowerController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.track.dto.TrackCellTowerSecondDTO;
 import com.zsjz.ai.common.model.track.query.TrackCellTowerQuery;
 import com.zsjz.ai.module.track.service.TrackCellTowerService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -30,7 +31,7 @@ public class TrackCellTowerController {
      * @return 分页的基站轨迹数据传输对象列表,包含基站信息、通信次数、通信时间区间等
      */
     @PostMapping("/statFirstTrackCellTower")
-    public Result<Page<TrackCellTowerDTO>> statFirstTrackCellTower(TrackCellTowerQuery query) {
+    public Result<Page<TrackCellTowerDTO>> statFirstTrackCellTower(@RequestBody TrackCellTowerQuery query) {
         return Result.succeed(trackCellTowerService.statFirstTrackCellTower(query));
     }
 
@@ -42,7 +43,7 @@ public class TrackCellTowerController {
      * @return 分页的基站轨迹数据传输对象列表,包含基站信息、通信次数、通信时间区间等
      */
     @PostMapping("/statSecondTrackCellTower")
-    public Result<Page<TrackCellTowerSecondDTO>> statSecondTrackCellTower(TrackCellTowerQuery query) {
+    public Result<Page<TrackCellTowerSecondDTO>> statSecondTrackCellTower(@RequestBody TrackCellTowerQuery query) {
         return Result.succeed(trackCellTowerService.statSecondTrackCellTower(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackEnLocalController.java

@@ -8,6 +8,7 @@ import com.zsjz.ai.common.model.track.query.TrackEnLocalQuery;
 import com.zsjz.ai.module.track.service.TrackEnLocalService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -33,13 +34,13 @@ public class TrackEnLocalController {
      * @return 按人员姓名分组的轨迹数据列表
      */
     @PostMapping("/statFirstTrackEnLocal")
-    public Result<Map<String, List<TrackEnLocalDTO>>> statFirstTrackEnLocal(TrackEnLocalQuery query) {
+    public Result<Map<String, List<TrackEnLocalDTO>>> statFirstTrackEnLocal(@RequestBody TrackEnLocalQuery query) {
         return Result.succeed(trackEnLocalService.statFirstTrackEnLocal(query));
     }
 
 
     @PostMapping("/statSecondTrackEnLocal")
-    public Result<Page<CallRecord>> statSecondTrackEnLocal(TrackEnLocalQuery query) {
+    public Result<Page<CallRecord>> statSecondTrackEnLocal(@RequestBody TrackEnLocalQuery query) {
         return Result.succeed(trackEnLocalService.statSecondTrackEnLocal(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackMeetController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.track.query.TrackMeetQuery;
 import com.zsjz.ai.module.track.service.TrackMeetService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -31,7 +32,7 @@ public class TrackMeetController {
      * @return 碰面汇总 DTO 列表,包含人员配对、碰面次数及详细信息
      */
     @PostMapping("/statFirstTrackMeet")
-    public Result<List<TrackMeetSummeryDTO>> statFirstTrackMeet(TrackMeetQuery query) {
+    public Result<List<TrackMeetSummeryDTO>> statFirstTrackMeet(@RequestBody TrackMeetQuery query) {
         return Result.succeed(trackMeetService.statFirstTrackMeet(query));
     }
 
@@ -43,7 +44,7 @@ public class TrackMeetController {
      * @return 碰面详情 DTO 列表,包含碰面地点、时间、间隔分钟数等
      */
     @PostMapping("/statSecondTrackMeet")
-    public Result<List<TrackMeetDTO>> statSecondTrackMeet(TrackMeetQuery query) {
+    public Result<List<TrackMeetDTO>> statSecondTrackMeet(@RequestBody TrackMeetQuery query) {
         return Result.succeed(trackMeetService.statSecondTrackMeet(query));
     }
 }

+ 5 - 4
ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackTogetherLiveController.java

@@ -11,6 +11,7 @@ import com.zsjz.ai.common.model.track.query.TrackTogetherLiveQuery;
 import com.zsjz.ai.module.track.service.TrackTogetherLiveService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -34,12 +35,12 @@ public class TrackTogetherLiveController {
      * @return 同住统计结果列表,按人员分组展示同住关系
      */
     @PostMapping("/statFirstTrackTogetherLive")
-    public Result<List<TrackPersonTogetherLiveDTO>> statFirstTrackTogetherLive(TrackTogetherLiveQuery query) {
+    public Result<List<TrackPersonTogetherLiveDTO>> statFirstTrackTogetherLive(@RequestBody TrackTogetherLiveQuery query) {
         return Result.succeed(trackTogetherLiveService.statFirstTrackTogetherLive(query));
     }
 
     @PostMapping("/statSecondTrackTogetherLive")
-    public Result<Page<TogetherLiveDTO>> statSecondTrackTogetherLive(TrackTogetherLiveQuery query) {
+    public Result<Page<TogetherLiveDTO>> statSecondTrackTogetherLive(@RequestBody TrackTogetherLiveQuery query) {
         return Result.succeed(trackTogetherLiveService.statSecondTrackTogetherLive(query));
     }
     /**
@@ -50,7 +51,7 @@ public class TrackTogetherLiveController {
      * @return 分页的旅馆住宿信息
      */
     @PostMapping("/hotelStayInfoDetail")
-    public Result<Page<HotelStayInfo>> hotelStayInfoDetail(TogetherLiveDetailQuery togetherLiveDetailQuery) {
+    public Result<Page<HotelStayInfo>> hotelStayInfoDetail(@RequestBody TogetherLiveDetailQuery togetherLiveDetailQuery) {
         return Result.succeed(trackTogetherLiveService.hotelStayInfoDetail(togetherLiveDetailQuery));
     }
 
@@ -62,7 +63,7 @@ public class TrackTogetherLiveController {
      * @return 分页的同住服务信息
      */
     @PostMapping("/togetherLiveInfoDetail")
-    public Result<Page<TogetherLiveInfo>> togetherLiveInfoDetail(TogetherLiveDetailQuery togetherLiveDetailQuery) {
+    public Result<Page<TogetherLiveInfo>> togetherLiveInfoDetail(@RequestBody TogetherLiveDetailQuery togetherLiveDetailQuery) {
         return Result.succeed(trackTogetherLiveService.togetherLiveInfoDetail(togetherLiveDetailQuery));
     }
 

+ 4 - 3
ai-server/src/main/java/com/zsjz/ai/module/track/controller/TrackTogetherTravelController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.track.query.TrackTogetherTravelQuery;
 import com.zsjz.ai.module.track.service.TrackTogetherTravelService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -31,17 +32,17 @@ public class TrackTogetherTravelController {
      * @return 同行时间线 DTO 列表,包含人员配对及同行次数等信息
      */
     @PostMapping("statTogetherTravel")
-    public Result<List<TravelTimelineDTO>> statTogetherTravel(TrackTogetherTravelQuery query) {
+    public Result<List<TravelTimelineDTO>> statTogetherTravel(@RequestBody TrackTogetherTravelQuery query) {
         return Result.succeed(trackTogetherTravelService.statTogetherTravel(query));
     }
 
     @PostMapping("statSecondTogetherTravel")
-    public Result<List<TravelRecordDTO>> statSecondTogetherTravel(TrackTogetherTravelQuery query) {
+    public Result<List<TravelRecordDTO>> statSecondTogetherTravel(@RequestBody TrackTogetherTravelQuery query) {
         return Result.succeed(trackTogetherTravelService.statSecondTogetherTravel(query));
     }
 
     @PostMapping("statThreeTogetherTravel")
-    public Result<Object> statThreeTogetherTravel(TrackTogetherTravelQuery query) {
+    public Result<Object> statThreeTogetherTravel(@RequestBody TrackTogetherTravelQuery query) {
         return Result.succeed(trackTogetherTravelService.statThreeTogetherTravel(query));
     }
 }

+ 2 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/CashKeyController.java

@@ -3,8 +3,8 @@ package com.zsjz.ai.module.trans.controller;
 import com.zsjz.ai.common.model.trans.entity.TransCashKey;
 import com.zsjz.ai.common.config.Result;
 import com.zsjz.ai.module.trans.service.TransCashKeyService;
-import org.apache.ibatis.annotations.Delete;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -42,7 +42,7 @@ public class CashKeyController {
      * @return 操作结果,成功返回 true,失败返回 false
      */
     @PostMapping("/createOrUpdate")
-    public Result<Boolean> create(TransCashKey transCashKey) {
+    public Result<Boolean> create(@RequestBody TransCashKey transCashKey) {
         return Result.succeed(transCashKeyService.saveOrUpdate(transCashKey));
     }
 

+ 1 - 1
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/FinancialKeyController.java

@@ -36,7 +36,7 @@ public class FinancialKeyController {
      * @return 操作结果,成功返回 true,失败返回 false
      */
     @PostMapping("/createOrUpdate")
-    public Result<Boolean> createOrUpdate(TransFinancialKey transFinancialKey) {
+    public Result<Boolean> createOrUpdate(@RequestBody TransFinancialKey transFinancialKey) {
         return Result.succeed(transFinancialKeyService.saveOrUpdate(transFinancialKey));
     }
 

+ 2 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/FixedDepositKeyController.java

@@ -3,8 +3,8 @@ package com.zsjz.ai.module.trans.controller;
 import com.zsjz.ai.common.model.trans.entity.TransFixedDepositKey;
 import com.zsjz.ai.common.config.Result;
 import com.zsjz.ai.module.trans.service.FixedDepositKeyService;
-import org.apache.ibatis.annotations.Delete;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,7 +38,7 @@ public class FixedDepositKeyController {
      * @return 操作结果,成功返回 true,失败返回 false
      */
     @PostMapping("/createOrUpdate")
-    public Result<Boolean> createOrUpdate(TransFixedDepositKey transFixedDepositKey) {
+    public Result<Boolean> createOrUpdate(@RequestBody TransFixedDepositKey transFixedDepositKey) {
         return Result.succeed(fixedDepositKeyService.saveOrUpdate(transFixedDepositKey));
     }
 

+ 4 - 3
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransBigController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.module.trans.service.TransBigService;
 import org.springframework.beans.factory.annotation.Autowired;
 
 
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -37,7 +38,7 @@ public class TransBigController {
      * @return 分页的交易统计结果,包含对手方信息、交易次数、总金额
      */
     @PostMapping("/statFirstTransBig")
-    public Result<Page<TransBigDTO>> statFirstTransBig(TransBigQuery query) {
+    public Result<Page<TransBigDTO>> statFirstTransBig(@RequestBody TransBigQuery query) {
         return Result.succeed(transBigService.statFirstTransBig(query));
     }
 
@@ -49,7 +50,7 @@ public class TransBigController {
      * @return 分页的交易聚合结果,按日期分组,包含聚合的交易详情
      */
     @PostMapping("/statSecondTransBig")
-    public Result<Page<TransBigDTO>> statSecondTransBig(TransBigQuery query) {
+    public Result<Page<TransBigDTO>> statSecondTransBig(@RequestBody TransBigQuery query) {
         return Result.succeed(transBigService.statSecondTransBig(query));
     }
 
@@ -61,7 +62,7 @@ public class TransBigController {
      * @return 按日期分组的交易明细列表,每个日期对应一个包含多笔交易的列表
      */
     @PostMapping("/statThirdTransBig")
-    public Result<List<TransBigDTO>> statThirdTransBig(TransBigQuery query) {
+    public Result<List<TransBigDTO>> statThirdTransBig(@RequestBody TransBigQuery query) {
         return Result.succeed(transBigService.statThirdTransBig(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransCardHoldController.java

@@ -8,6 +8,7 @@ import com.zsjz.ai.common.model.trans.query.StatTransCardHoldQuery;
 import com.zsjz.ai.module.trans.service.TransCardHoldService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -53,7 +54,7 @@ public class TransCardHoldController {
      * @return 一致行动交易统计结果列表,按时间窗口分组展示
      */
     @PostMapping("/statTogetherDoTrans")
-    public Result<List<StatTogetherDoTransDTO>> statTogetherDoTrans(StatTogetherDoTransQuery query) {
+    public Result<List<StatTogetherDoTransDTO>> statTogetherDoTrans(@RequestBody StatTogetherDoTransQuery query) {
         return Result.succeed(transCardHoldService.statTogetherDoTrans(query));
     }
 
@@ -73,7 +74,7 @@ public class TransCardHoldController {
      * @return 银行卡代持统计结果,包含主体对象名称及关联的银行卡代持人员列表
      */
     @PostMapping("/statTransCardHold")
-    public Result<StatTransCardHoldDTO> statTransCardHold(StatTransCardHoldQuery query) {
+    public Result<StatTransCardHoldDTO> statTransCardHold(@RequestBody StatTransCardHoldQuery query) {
         return Result.succeed(transCardHoldService.statTransCardHold(query));
     }
 

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransCashFlowController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.common.model.trans.query.TransCashCallBeforeAfterQuery;
 import com.zsjz.ai.module.trans.service.TransCashFlowService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -31,7 +32,7 @@ public class TransCashFlowController {
      * @return 交易流水统计列表
      */
     @PostMapping("/statFirstTransCashFlow")
-    public Result<Page<TransRecordSummaryDTO>> statFirstTransCashFlow(TransRecordSummaryQuery query) {
+    public Result<Page<TransRecordSummaryDTO>> statFirstTransCashFlow(@RequestBody TransRecordSummaryQuery query) {
         return Result.succeed(transCashFlowService.statFirstTransCashFlow(query));
     }
 
@@ -43,7 +44,7 @@ public class TransCashFlowController {
      * @return 分页的时间线数据(包含通话和交易记录)
      */
     @PostMapping("/statTransCashCallBeforeAfterTimeLine")
-    public Result<Page<TransCashCallBeforeAfterTimeLineDTO>> statTransCashCallBeforeAfterTimeLine(TransCashCallBeforeAfterQuery query) {
+    public Result<Page<TransCashCallBeforeAfterTimeLineDTO>> statTransCashCallBeforeAfterTimeLine(@RequestBody TransCashCallBeforeAfterQuery query) {
         return Result.succeed(transCashFlowService.statTransCashCallBeforeAfterTimeLine(query));
     }
 

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransContinuousController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.module.trans.service.TransContinuousService;
 import org.springframework.beans.factory.annotation.Autowired;
 
 
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,7 +33,7 @@ public class TransContinuousController {
      * @return 分页的连续交易 DTO 列表,包含交易双方信息、连续月份、交易汇总等
      */
     @PostMapping("/statFirstTransContinuous")
-    public Result<Page<TransContinuousDTO>> statFirstTransContinuous(TransContinuousQuery query) {
+    public Result<Page<TransContinuousDTO>> statFirstTransContinuous(@RequestBody TransContinuousQuery query) {
         return Result.succeed(transContinuousService.statFirstTransContinuous(query));
     }
 
@@ -44,7 +45,7 @@ public class TransContinuousController {
      * @return 分页的连续交易 DTO 列表,包含更详细的分组信息和连续时间段
      */
     @PostMapping("/statSecondTransContinuous")
-    public Result<Page<TransContinuousDTO>> statSecondTransContinuous(TransContinuousQuery query) {
+    public Result<Page<TransContinuousDTO>> statSecondTransContinuous(@RequestBody TransContinuousQuery query) {
         return Result.succeed(transContinuousService.statSecondTransContinuous(query));
     }
 }

+ 2 - 1
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFinancialController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.trans.query.TransFinancialQuery;
 import com.zsjz.ai.module.trans.service.TransFinancialService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -29,7 +30,7 @@ public class TransFinancialController {
      * @return 分页的交易金融 DTO 数据
      */
     @PostMapping("statFirstTransFinancial")
-    public Result<Page<TransFinancialDTO>> statFirstTransFinancial(TransFinancialQuery query) {
+    public Result<Page<TransFinancialDTO>> statFirstTransFinancial(@RequestBody TransFinancialQuery query) {
         return Result.succeed(transFinancialService.statFirstTransFinancial(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFixedDepositController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.module.trans.service.TransFixedDepositService;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -34,7 +35,7 @@ public class TransFixedDepositController {
      * @return 人员定期存款汇总列表
      */
     @PostMapping("/statFirstTransFixedDeposit")
-    public Result<List<TransPersonFixedDepositDTO>> statFirstTransFixedDeposit(TransFixedDepositQuery query) {
+    public Result<List<TransPersonFixedDepositDTO>> statFirstTransFixedDeposit(@RequestBody TransFixedDepositQuery query) {
         return Result.succeed(transFixedDepositService.statFirstTransFixedDeposit(query));
     }
 
@@ -46,7 +47,7 @@ public class TransFixedDepositController {
      * @return 分页的定期存款明细列表
      */
     @PostMapping("/statSecondTransFixedDepositList")
-    public Result<Page<TransPersonFixedDepositDetailDTO>> statSecondTransFixedDepositList(TransFixedDepositQuery query) {
+    public Result<Page<TransPersonFixedDepositDetailDTO>> statSecondTransFixedDepositList(@RequestBody TransFixedDepositQuery query) {
         return Result.succeed(transFixedDepositService.statSecondTransFixedDepositList(query));
     }
 

+ 2 - 1
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFrequencyController.java

@@ -8,6 +8,7 @@ import com.zsjz.ai.module.trans.service.TransFrequencyService;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -31,7 +32,7 @@ public class TransFrequencyController {
      * @return 分页的交易频率统计结果
      */
     @PostMapping("/statFirstTransFrequency")
-    public Result<Page<TransFrequencyDTO>> statFirstTransFrequency(TransFrequencyQuery query) {
+    public Result<Page<TransFrequencyDTO>> statFirstTransFrequency(@RequestBody TransFrequencyQuery query) {
         return Result.succeed(transFrequencyService.statFirstTransFrequency(query));
     }
 }

+ 4 - 3
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransFundFlowController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.common.model.trans.query.TransRecordQuery;
 import com.zsjz.ai.module.trans.service.TransFundFlowService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -29,7 +30,7 @@ public class TransFundFlowController {
      * @return 资金流向分页数据
      */
     @PostMapping("getTransFundFlowPage")
-    public Result<Page<TransFundFlowDTO>> getTransFundFlowPage(TransRecordQuery query) {
+    public Result<Page<TransFundFlowDTO>> getTransFundFlowPage(@RequestBody TransRecordQuery query) {
         return Result.succeed(transFundFlowService.getTransFundFlowPage(query));
     }
 
@@ -40,7 +41,7 @@ public class TransFundFlowController {
      * @return 资金流向树形结构
      */
     @PostMapping("/graph")
-    public Result<TransFlowDTO> transFlowGraph(TransFlowGraphQuery query) {
+    public Result<TransFlowDTO> transFlowGraph(@RequestBody TransFlowGraphQuery query) {
         return Result.succeed(transFundFlowService.transFlowGraph(query));
     }
 
@@ -51,7 +52,7 @@ public class TransFundFlowController {
      * @return 资金流向树形结构
      */
     @PostMapping("/trace")
-    public Result<TransFlowDTO> transFlowTrace(TransFlowGraphQuery param) {
+    public Result<TransFlowDTO> transFlowTrace(@RequestBody TransFlowGraphQuery param) {
         return Result.succeed(transFundFlowService.transFlowTrace(param));
     }
 

+ 2 - 1
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransRecordController.java

@@ -7,6 +7,7 @@ import com.zsjz.ai.common.model.trans.query.TransRecordQuery;
 import com.zsjz.ai.module.trans.service.TransRecordService;
 import org.springframework.beans.factory.annotation.Autowired;
 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.RestController;
 
@@ -17,7 +18,7 @@ public class TransRecordController {
     @Autowired
     private TransRecordService transRecordService;
     @PostMapping("getTransRecord")
-    public Result<Page<TransRecord>> getTransRecord(TransRecordQuery query) {
+    public Result<Page<TransRecord>> getTransRecord(@RequestBody TransRecordQuery query) {
         return Result.succeed(transRecordService.getTransRecord(query));
     }
 }

+ 3 - 2
ai-server/src/main/java/com/zsjz/ai/module/trans/controller/TransSensitiveController.java

@@ -9,6 +9,7 @@ import com.zsjz.ai.module.trans.service.TransSensitiveService;
 
 import org.springframework.beans.factory.annotation.Autowired;
 
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -32,7 +33,7 @@ public class TransSensitiveController {
      * @return 分页的敏感交易 DTO 列表,包含交易双方信息和交易次数
      */
     @PostMapping("/statFirstTransSensitive")
-    public Result<Page<TransSensitiveDTO>> statFirstTransSensitive(TransSensitiveQuery query) {
+    public Result<Page<TransSensitiveDTO>> statFirstTransSensitive(@RequestBody TransSensitiveQuery query) {
         return Result.succeed(transSensitiveService.statFirstTransSensitive(query));
     }
 
@@ -44,7 +45,7 @@ public class TransSensitiveController {
      * @return 分页的交易记录列表,包含完整的交易详情
      */
     @PostMapping("/statSecondTransSensitive")
-    public Result<Page<TransRecord>> statSecondTransSensitive(TransSensitiveQuery query) {
+    public Result<Page<TransRecord>> statSecondTransSensitive(@RequestBody TransSensitiveQuery query) {
         return Result.succeed(transSensitiveService.statSecondTransSensitive(query));
     }
 }

+ 219 - 0
controller-request-body-audit.md

@@ -0,0 +1,219 @@
+# Controller 接口 `@RequestBody` 缺失审计
+
+> 审计时间:2026-09-16  ·  范围:`ai-server/src/main/java/**/*Controller.java`(45 个 controller)
+> 生成方式:脚本静态扫描后端映射注解与方法签名 + 交叉比对前端全部 `defHttp` POST 调用点
+
+## 〇、修复记录(2026-09-16 当日完成)
+
+**结论:76 个缺注解端点已全部处理完毕;复扫 `broken = 0`、`missingBindingAnnotation = 0`。**
+下方第一~八节保留的是**修复前**的审计状态,作为问题清单与判定依据留档。
+
+| 项 | 内容 |
+| --- | --- |
+| 改动文件 | 32 个 controller + 新增 1 个 DTO(`common/model/person/dto/DeletePersonGroupDTO.java`) |
+| 改动内容 | 74 个 POJO 参数前加 `@RequestBody`;`/pg/delete` 改 `@RequestBody DeletePersonGroupDTO`;`statSecondCallNight` 的无效 MyBatis `@Param("query")` 替换为 `@RequestBody` |
+| 清理 | 删除被替换后失效的 `import org.apache.ibatis.annotations.Param`(CallNightController);删除 4 处与通配符 import 重复的显式 `RequestBody` import;顺带删除 3 个 controller 中未使用的 `org.apache.ibatis.annotations.Delete` import |
+| 结构校验 | 脚本比对修复前后:**映射注解(URL)零改动**、方法签名除 `@RequestBody` 外零改动、新增行仅 75 条签名行 + 32 条 import |
+| 编译 | `mvn -pl ai-server clean compile` → **BUILD SUCCESS**(621 源文件) |
+| 复扫 | `writeEndpoints=98 / missingBindingAnnotation=0 / broken=0 / annotated=97 + multipart=1` |
+| 回退方式 | 32 个文件中有 31 个改动前与 HEAD 一致 → `git checkout -- <文件>` 可完整回退;**`DataProfileController.java` 修复前已有他人/既有本地改动**(import 由 4 行显式改为 `annotation.*` 通配符),`git checkout` 会连带丢弃该改动,回退请用备份副本 |
+
+**尚未做**:运行期端到端验证(起后端发 JSON body 请求确认筛选条件真正生效)。静态层面已闭环。
+
+
+## 一、结论摘要
+
+| 指标 | 数量 |
+| --- | --- |
+| Controller 文件 | 45(其中 36 个含 POST/PUT 端点,9 个仅 GET,1 个为空壳) |
+| 写端点(POST/PUT/PATCH)总数 | 98 |
+| **缺 `@RequestBody` 的端点** | **76** |
+| ├ 其中**已确认有问题**(前端以 JSON body 调用) | **75** |
+| └ 其中暂无前端调用方(需人工确认) | 1 |
+| 已正确(含 `@RequestBody`) | 21 |
+| multipart 上传端点(写法正确) | 1 |
+
+## 二、判定标准(为什么是「有问题」而不是「风格问题」)
+
+1. 前端 axios 默认 `content-type` 是 **`application/x-www-form-urlencoded`**(`core/utils/http/axios/index.ts`),
+   只有 `defHttp.postJson()` 会显式设成 `application/json` 并把 `data` 作为 **JSON 请求体**发出。
+2. 后端方法参数**不加注解**时,Spring MVC 走 `ModelAttributeMethodProcessor`,只从 **query string / form 字段**绑定,
+   **完全不会解析 JSON body**。
+3. ⇒ 前端发 JSON body + 后端参数无注解 = **body 被丢弃,参数对象所有字段为 null**。
+   表现:筛选条件(号码/时间/分页)静默失效、返回全量或空数据;个别场景直接 500/NPE。
+
+> 同类缺陷在本仓库已有先例并被修过:`/case/create`、`/case/open`、`/dm/preFile` 等(提交前用 `curl` 观察 `parameters={}` → 500)。
+
+## 三、确认有问题的端点(75 个,按模块分组)
+
+### 通信分析(7)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/CallContinuousController.java:34` | `statFirstCallContinuous` | `/call/continuous/statFirstCallContinuous` | `CallContinuousQuery query` | `api/callApi.ts:14` |
+| 2 | `controller/CallContinuousController.java:46` | `statSecondCallContinuous` | `/call/continuous/statSecondCallContinuous` | `CallContinuousQuery query` | `api/callApi.ts:23` |
+| 3 | `controller/CallNightController.java:37` | `statFirstCallNight` | `/call/night/statFirstCallNight` | `CallNightQuery query` | `api/callApi.ts:34` |
+| 4 | `controller/CallNightController.java:49` | `statSecondCallNight` | `/call/night/statSecondCallNight` | `@Param("query") CallNightQuery query` | `api/callApi.ts:40` |
+| 5 | `controller/CallRecordController.java:33` | `getCallRecord` | `/cr/getCallRecord` | `CallRecordQuery query` | `api/callApi.ts:62` |
+| 6 | `controller/CallSensitiveController.java:35` | `statFirstCallSensitive` | `/call/sensitive/statFirstCallSensitive` | `CallSensitiveQuery query` | `api/callApi.ts:48` |
+| 7 | `controller/CallSensitiveController.java:47` | `statSecondCallSensitive` | `/call/sensitive/statSecondCallSensitive` | `CallSensitiveQuery query` | `api/callApi.ts:54` |
+
+### 数据治理(6)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/GovernTreeController.java:58` | `getTreeTransPersonPage` | `/gt/getTreeTransPersonPage` | `GovernTreeQuery dto` | `govern/governApi.ts:117` |
+| 2 | `controller/GovernTreeController.java:70` | `getTreeTransBankPage` | `/gt/getTreeTransBankPage` | `GovernTreeQuery dto` | `govern/governApi.ts:123` |
+| 3 | `controller/GovernTreeController.java:82` | `getTreeCallPersonPage` | `/gt/getTreeCallPersonPage` | `GovernTreeQuery dto` | `govern/governApi.ts:129` |
+| 4 | `controller/GovernTreeController.java:94` | `getTreeCallOperPage` | `/gt/getTreeCallOperPage` | `GovernTreeQuery dto` | `govern/governApi.ts:135` |
+| 5 | `controller/GovernTreeController.java:106` | `getTreeCallPersonUseOpenInfoPage` | `/gt/getTreeCallPersonUseOpenInfoPage` | `GovernTreeQuery dto` | `govern/governApi.ts:141` |
+| 6 | `controller/GovernTreeController.java:118` | `getTreeCallOperUseOpenInfoPage` | `/gt/getTreeCallOperUseOpenInfoPage` | `GovernTreeQuery dto` | `govern/governApi.ts:147` |
+
+### 关系图谱(4)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/GraphController.java:39` | `graph` | `/graph/view` | `GraphQuery query` | `api/analysis.ts:1249` |
+| 2 | `controller/GraphController.java:51` | `transDetail` | `/graph/transDetail` | `GraphTransDetailQuery query` | `api/analysis.ts:1264` |
+| 3 | `controller/GraphController.java:63` | `callDetail` | `/graph/callDetail` | `GraphCallDetailQuery query` | `api/analysis.ts:1277` |
+| 4 | `controller/GraphController.java:68` | `nodeDetail` | `/graph/nodeDetail` | `GraphCallDetailQuery query` | `api/analysis.ts:1289` |
+
+### 时空/轨迹基础(5)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/SpecialDateController.java:26` | `create` | `/sdc/create` | `SpecialDateRecord sdr` | `api/personApi.ts:61` |
+| 2 | `controller/SpecialDateController.java:32` | `update` | `/sdc/update` | `SpecialDateRecord sdr` | `api/personApi.ts:70` |
+| 3 | `controller/TimeSeriesController.java:22` | `getTimeSeries` | `/otg/timeSeries/list` | `TimeSeriesQuery query` | `api/otgApi.ts:54` |
+| 4 | `controller/TimeSeriesController.java:27` | `detailTimeSeries` | `/otg/timeSeries/detailTimeSeries` | `TimeSeriesQuery query` | `api/otgApi.ts:65` |
+| 5 | `controller/TimeSeriesController.java:32` | `jumpTimeSeries` | `/otg/timeSeries/jump` | `TimeSeriesQuery query` | `api/otgApi.ts:76` |
+
+### 对象画像(15)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/DataProfileController.java:52` | `callOftenTop10` | `/dp/callOftenTop10` | `CallOftenTop10Query query` | `api/dpApi.ts:51` |
+| 2 | `controller/DataProfileController.java:65` | `callStatStation` | `/dp/callStatStation` | `CallStatStationQuery query` | `api/dpApi.ts:57` |
+| 3 | `controller/DataProfileController.java:78` | `getCallRecordSummary` | `/dp/getCallRecordSummary` | `CallRecordSummaryQuery query` | `api/dpApi.ts:63` |
+| 4 | `controller/DataProfileController.java:90` | `getCallOperPhoneInfo` | `/dp/getCallOperPhoneInfo` | `CallOperPhoneInfoQuery query` | `api/dpApi.ts:69` |
+| 5 | `controller/DataProfileController.java:153` | `getTransBankCardInfo` | `/dp/getTransBankCardInfo` | `TransBankCardInfoQuery query` | `api/dpApi.ts:95` |
+| 6 | `controller/DataProfileController.java:165` | `transAmountTrendYM` | `/dp/transAmountTrendYM` | `TransTrendQuery query` | `api/dpApi.ts:107` |
+| 7 | `controller/DataProfileController.java:177` | `transAmountTrendY` | `/dp/transAmountTrendY` | `TransTrendQuery query` | `api/dpApi.ts:113` |
+| 8 | `controller/IntimacyController.java:32` | `update` | `/intimacy/modify` | `List<Intimacy> intimacyList` | `api/personApi.ts:43` |
+| 9 | `controller/PersonBasicInfoController.java:24` | `create` | `/pbi/create` | `PersonBasicInfoDTO dto` | `api/personApi.ts:90` |
+| 10 | `controller/PersonBasicInfoController.java:46` | `update` | `/pbi/update` | `PersonBasicInfoDTO dto` | `api/personApi.ts:108` |
+| 11 | `controller/PersonBasicInfoController.java:57` | `personOrder` | `/pbi/personOrder` | `List<PersonBasicInfo> list` | `api/personApi.ts:141` |
+| 12 | `controller/PersonGroupController.java:31` | `create` | `/pg/create` | `PersonGroup personGroup` | `api/personApi.ts:160` |
+| 13 | `controller/PersonGroupController.java:42` | `update` | `/pg/update` | `PersonGroup personGroup` | `api/personApi.ts:169` |
+| 14 | `controller/PersonGroupController.java:53` | `delete` | `/pg/delete` | `Long id` | `api/personApi.ts:178` |
+| 15 | `controller/PersonGroupController.java:65` | `addPerson` | `/pg/addPerson` | `AddPersonGroupDTO dto` | `api/personApi.ts:187` |
+
+### 平台(表/案件/系统)(2)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/TableInfoController.java:72` | `create` | `/tpl/create` | `TableInfo tableInfo` | `tpl/tplApi.ts:63` |
+| 2 | `controller/TableInfoController.java:81` | `update` | `/tpl/update` | `TableInfo tableInfo` | `tpl/tplApi.ts:69` |
+
+### 活动轨迹(15)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/ExpressInfoController.java:32` | `statFirstExpressInfo` | `/expressInfo/statFirstExpressInfo` | `ExpressInfoQuery query` | `api/trackApi.ts:51` |
+| 2 | `controller/ExpressInfoController.java:43` | `statSecondExpressInfo` | `/expressInfo/statSecondExpressInfo` | `ExpressInfoQuery query` | `api/trackApi.ts:60` |
+| 3 | `controller/TrackCellTowerController.java:32` | `statFirstTrackCellTower` | `/track/cellTower/statFirstTrackCellTower` | `TrackCellTowerQuery query` | `api/trackApi.ts:71` |
+| 4 | `controller/TrackCellTowerController.java:44` | `statSecondTrackCellTower` | `/track/cellTower/statSecondTrackCellTower` | `TrackCellTowerQuery query` | `api/trackApi.ts:77` |
+| 5 | `controller/TrackEnLocalController.java:35` | `statFirstTrackEnLocal` | `/track/enLocal/statFirstTrackEnLocal` | `TrackEnLocalQuery query` | `api/trackApi.ts:85` |
+| 6 | `controller/TrackEnLocalController.java:41` | `statSecondTrackEnLocal` | `/track/enLocal/statSecondTrackEnLocal` | `TrackEnLocalQuery query` | `api/trackApi.ts:94` |
+| 7 | `controller/TrackMeetController.java:33` | `statFirstTrackMeet` | `/track/meet/statFirstTrackMeet` | `TrackMeetQuery query` | `api/trackApi.ts:112` |
+| 8 | `controller/TrackMeetController.java:45` | `statSecondTrackMeet` | `/track/meet/statSecondTrackMeet` | `TrackMeetQuery query` | `api/trackApi.ts:121` |
+| 9 | `controller/TrackTogetherLiveController.java:36` | `statFirstTrackTogetherLive` | `/track/togetherLive/statFirstTrackTogetherLive` | `TrackTogetherLiveQuery query` | `api/trackApi.ts:132` |
+| 10 | `controller/TrackTogetherLiveController.java:41` | `statSecondTrackTogetherLive` | `/track/togetherLive/statSecondTrackTogetherLive` | `TrackTogetherLiveQuery query` | `api/trackApi.ts:141` |
+| 11 | `controller/TrackTogetherLiveController.java:52` | `hotelStayInfoDetail` | `/track/togetherLive/hotelStayInfoDetail` | `TogetherLiveDetailQuery togetherLiveDetailQuery` | `api/trackApi.ts:153` |
+| 12 | `controller/TrackTogetherLiveController.java:64` | `togetherLiveInfoDetail` | `/track/togetherLive/togetherLiveInfoDetail` | `TogetherLiveDetailQuery togetherLiveDetailQuery` | `api/trackApi.ts:165` |
+| 13 | `controller/TrackTogetherTravelController.java:33` | `statTogetherTravel` | `/track/togetherTravel/statTogetherTravel` | `TrackTogetherTravelQuery query` | `api/trackApi.ts:179` |
+| 14 | `controller/TrackTogetherTravelController.java:38` | `statSecondTogetherTravel` | `/track/togetherTravel/statSecondTogetherTravel` | `TrackTogetherTravelQuery query` | `api/trackApi.ts:188` |
+| 15 | `controller/TrackTogetherTravelController.java:43` | `statThreeTogetherTravel` | `/track/togetherTravel/statThreeTogetherTravel` | `TrackTogetherTravelQuery query` | `api/trackApi.ts:200` |
+
+### 交易分析(21)
+
+| # | 位置 | 方法 | 路径 | 缺注解的参数 | 前端调用点(postJson) |
+| --- | --- | --- | --- | --- | --- |
+| 1 | `controller/CashKeyController.java:44` | `create` | `/trans/cashKey/createOrUpdate` | `TransCashKey transCashKey` | `api/transApi.ts:62` |
+| 2 | `controller/FinancialKeyController.java:38` | `createOrUpdate` | `/trans/financialKey/createOrUpdate` | `TransFinancialKey transFinancialKey` | `api/transApi.ts:82` |
+| 3 | `controller/FixedDepositKeyController.java:40` | `createOrUpdate` | `/fixedDepositKey/createOrUpdate` | `TransFixedDepositKey transFixedDepositKey` | `api/transApi.ts:102` |
+| 4 | `controller/TransBigController.java:39` | `statFirstTransBig` | `/trans/big/statFirstTransBig` | `TransBigQuery query` | `api/transApi.ts:128` |
+| 5 | `controller/TransBigController.java:51` | `statSecondTransBig` | `/trans/big/statSecondTransBig` | `TransBigQuery query` | `api/transApi.ts:134` |
+| 6 | `controller/TransBigController.java:63` | `statThirdTransBig` | `/trans/big/statThirdTransBig` | `TransBigQuery query` | `api/transApi.ts:140` |
+| 7 | `controller/TransCardHoldController.java:55` | `statTogetherDoTrans` | `/trans/cardHold/statTogetherDoTrans` | `StatTogetherDoTransQuery query` | `api/transApi.ts:206` |
+| 8 | `controller/TransCardHoldController.java:75` | `statTransCardHold` | `/trans/cardHold/statTransCardHold` | `StatTransCardHoldQuery query` | `api/transApi.ts:215` |
+| 9 | `controller/TransCashFlowController.java:33` | `statFirstTransCashFlow` | `/trans/cashFlow/statFirstTransCashFlow` | `TransRecordSummaryQuery query` | `api/transApi.ts:116` |
+| 10 | `controller/TransContinuousController.java:34` | `statFirstTransContinuous` | `/trans/continuous/statFirstTransContinuous` | `TransContinuousQuery query` | `api/transApi.ts:148` |
+| 11 | `controller/TransContinuousController.java:46` | `statSecondTransContinuous` | `/trans/continuous/statSecondTransContinuous` | `TransContinuousQuery query` | `api/transApi.ts:157` |
+| 12 | `controller/TransFinancialController.java:31` | `statFirstTransFinancial` | `/trans/financial/statFirstTransFinancial` | `TransFinancialQuery query` | `api/transApi.ts:265` |
+| 13 | `controller/TransFixedDepositController.java:36` | `statFirstTransFixedDeposit` | `/trans/fixedDeposit/statFirstTransFixedDeposit` | `TransFixedDepositQuery query` | `api/transApi.ts:273` |
+| 14 | `controller/TransFixedDepositController.java:48` | `statSecondTransFixedDepositList` | `/trans/fixedDeposit/statSecondTransFixedDepositList` | `TransFixedDepositQuery query` | `api/transApi.ts:282` |
+| 15 | `controller/TransFrequencyController.java:33` | `statFirstTransFrequency` | `/trans/frequency/statFirstTransFrequency` | `TransFrequencyQuery query` | `api/transApi.ts:226` |
+| 16 | `controller/TransFundFlowController.java:31` | `getTransFundFlowPage` | `/trans/fundsFlow/getTransFundFlowPage` | `TransRecordQuery query` | `api/transApi.ts:168` |
+| 17 | `controller/TransFundFlowController.java:42` | `transFlowGraph` | `/trans/fundsFlow/graph` | `TransFlowGraphQuery query` | `api/transApi.ts:177` |
+| 18 | `controller/TransFundFlowController.java:53` | `transFlowTrace` | `/trans/fundsFlow/trace` | `TransFlowGraphQuery param` | `api/transApi.ts:186` |
+| 19 | `controller/TransRecordController.java:19` | `getTransRecord` | `/trans/getTransRecord` | `TransRecordQuery query` | `api/transApi.ts:257` |
+| 20 | `controller/TransSensitiveController.java:34` | `statFirstTransSensitive` | `/trans/sensitive/statFirstTransSensitive` | `TransSensitiveQuery query` | `api/transApi.ts:237` |
+| 21 | `controller/TransSensitiveController.java:46` | `statSecondTransSensitive` | `/trans/sensitive/statSecondTransSensitive` | `TransSensitiveQuery query` | `api/transApi.ts:246` |
+
+## 四、暂无前端调用方(1 个,需人工确认)
+
+| 位置 | 方法 | 路径 | 参数 |
+| --- | --- | --- | --- |
+| `controller/TransCashFlowController.java:45` | `statTransCashCallBeforeAfterTimeLine` | `/trans/cashFlow/statTransCashCallBeforeAfterTimeLine` | `TransCashCallBeforeAfterQuery query` |
+
+> 前端未在 `ai-frontend/src/**` 中找到调用点(可能:未接入、由旧页面/外部调用、或拼 URL 方式特殊)。
+> 若确认前端会用 JSON body 调用,同样需要补 `@RequestBody`。
+
+## 五、特殊修法(不能简单加注解)
+
+| 端点 | 现状 | 问题 | 建议 |
+| --- | --- | --- | --- |
+| `POST /pg/delete`(PersonGroupController:53) | 后端 `delete(Long id)`,前端 body `{ id }` | 直接给 `Long` 加 `@RequestBody` 会变成"JSON 对象 → Long"反序列化失败(400) | 前端改 `params: { id }` + 后端 `@RequestParam Long id`;或新增 `IdDTO` 用 `@RequestBody` |
+| `POST /intimacy/modify`(IntimacyController:32) | 参数 `List<Intimacy>`,前端发数组 | 需 `@RequestBody List<Intimacy>`(数组体) | 加 `@RequestBody` 即可,字段与前端 `IntimacyConfigDTO` 兼容 |
+| `POST /pbi/personOrder`(PersonBasicInfoController:57) | 参数 `List<PersonBasicInfo>`,前端发数组 | 同上 | 加 `@RequestBody` |
+| `POST /call/night/statSecondCallNight`(CallNightController:49) | 参数写成 `@Param("query") CallNightQuery query` | `@Param` 是 MyBatis 注解,在 controller 上无效,仍属"无绑定注解" | 去掉 `@Param` 换 `@RequestBody` |
+
+## 六、写法正确的对照(21 个 + 1 个 multipart,供参照)
+
+- `/chat/sessions` —— `controller/AgentChatController.java:35`
+- `/chat/sessions/{sessionId}/title` —— `controller/AgentChatController.java:59`
+- `/chat/sessions/{sessionId}/pin` —— `controller/AgentChatController.java:75`
+- `/chat/messages` —— `controller/AgentChatController.java:91`
+- `/chat/messages/{messageId}/star` —— `controller/AgentChatController.java:107`
+- `/chat/stream` —— `controller/AgentChatController.java:129`
+- `/models` —— `controller/AgentModelController.java:48`
+- `/models/{id}` —— `controller/AgentModelController.java:56`
+- `/models/{id}/default` —— `controller/AgentModelController.java:74`
+- `/dm/preFile` —— `controller/DmController.java:57`
+- `/dm/rawPreview` —— `controller/DmController.java:93`
+- `/dm/doClean` —— `controller/DmController.java:104`
+- `/dm/getFiles` —— `controller/DmController.java:139`
+- `/dm/deletedFiles` —— `controller/DmController.java:149`
+- `/dm/saveGovernCon` —— `controller/DmController.java:168`
+- `/gt/treeTablePage` —— `controller/GovernTreeController.java:46`
+- `/dp/transOfPersons` —— `controller/DataProfileController.java:117`
+- `/dp/getTransRecordSummary` —— `controller/DataProfileController.java:129`
+- `/case/create` —— `controller/CaseInfoController.java:50`
+- `/case/updatePwd` —— `controller/CaseInfoController.java:73`
+- `/case/open` —— `controller/CaseInfoController.java:85`
+- `/dm/preFileUpload`(multipart,写法正确)—— `controller/DmController.java:78`
+
+## 七、其它发现
+
+- `ResidentPopulationController` 只有类级 `@RequestMapping("/rp")`、**没有任何端点方法**,属空壳类(可删或待补)。
+- 9 个 controller 只有 GET 端点(`SystemController`/`TowerController`/`GovernController`/`SearchController`/`CleanErrorLogController`/`AgentResultController`/`AgentPythonFileController`/`TransFastFundFlowController`/`ResidentPopulationController`),本次审计不涉及。
+- AI Agent 模块(`AgentChatController`/`AgentModelController`/`DmController`)此前已补过注解,本次复扫全部通过。
+
+## 八、修复建议(已于当日执行完毕,见第〇节)
+
+对 75 个端点:给唯一的 POJO/实体参数加 `@RequestBody`(`import org.springframework.web.bind.annotation.RequestBody;`),
+属机械改动、可用脚本批量处理;改完 `mvn -pl ai-server clean compile` 通过即可。
+`/pg/delete` 与 `/call/night/statSecondCallNight` 需按上表特殊处理。
+
+验证方式:起后端后对 1~2 个端点发 JSON body 请求,确认筛选条件生效(对照今天的日志里是否出现 `parameters={}`)。