cc пре 3 недеља
родитељ
комит
b188cee3d8

+ 5 - 5
ai-frontend/src/ai/api/chatApi.ts

@@ -27,17 +27,17 @@ export function getSession(sessionId: string): Promise<ChatSession> {
 
 /** 重命名会话 */
 export function updateSessionTitle(sessionId: string, title: string): Promise<void> {
-  return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/title`, undefined, { title });
+  return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/title`, { title });
 }
 
 /** 删除会话 */
 export function deleteSession(sessionId: string): Promise<void> {
-  return aiHttp.deleteRaw<void>(`/chat/sessions/${sessionId}`);
+  return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/delete`);
 }
 
 /** 置顶 / 取消置顶 */
 export function togglePinSession(sessionId: string): Promise<void> {
-  return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/pin`);
+  return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/pin`);
 }
 
 /* ------------------------------------------------------------------ *
@@ -56,12 +56,12 @@ export function sendMessage(params: SendMessageParams): Promise<ChatMessageVO> {
 
 /** 删除消息 */
 export function deleteMessage(messageId: string): Promise<void> {
-  return aiHttp.deleteRaw<void>(`/chat/messages/${messageId}`);
+  return aiHttp.getRaw<void>(`/chat/messages/${messageId}`);
 }
 
 /** 收藏 / 取消收藏 */
 export function toggleStarMessage(messageId: string): Promise<void> {
-  return aiHttp.putRaw<void>(`/chat/messages/${messageId}/star`);
+  return aiHttp.getRaw<void>(`/chat/messages/${messageId}/star`);
 }
 
 /* ------------------------------------------------------------------ *

+ 2 - 2
ai-frontend/src/ai/api/modelApi.ts

@@ -29,10 +29,10 @@ export function updateModel(id: string, params: UpdateModelParams): Promise<void
 
 /** 删除模型 */
 export function deleteModel(id: string): Promise<void> {
-  return aiHttp.delete<void>(`/models/${id}`);
+  return aiHttp.get<void>(`/models/${id}`);
 }
 
 /** 设为默认模型 */
 export function setDefaultModel(id: string): Promise<void> {
-  return aiHttp.putJson<void>(`/models/${id}/default`);
+  return aiHttp.get<void>(`/models/${id}/default`);
 }

+ 1 - 1
ai-frontend/src/graph/insight/api.ts

@@ -59,7 +59,7 @@ export function getInsightMessageTrace(
 
 /** 删除会话(消息随外键级联) */
 export function deleteInsightSession(id: string | number, caseId: string | number): Promise<void> {
-  return aiHttp.deleteRaw<void>(`${BASE}/sessions/${id}`, { caseId });
+  return aiHttp.getRaw<void>(`${BASE}/sessions/${id}/delete`, { caseId });
 }
 
 /** 线索聚合(为「线索推送」页预留,本期不接页面) */

+ 2 - 2
ai-frontend/src/person/api/personApi.ts

@@ -96,7 +96,7 @@ export const createPersonBasicInfo = (data: PersonBasicInfoDTO) =>
  * 删除人员信息
  */
 export const deletePersonBasicInfo = (personName: string) =>
-  defHttp.delete<void>(
+  defHttp.get<void>(
     { url: adminPath + '/pbi/delete', params: { personName } },
     { skipSuccessMessage: true, skipErrorMessage: true },
   );
@@ -193,7 +193,7 @@ export const addPersonToGroup = (data: AddPersonGroupDTO) =>
  * 从分组删除人员
  */
 export const remPersonFromGroup = (relId: string) =>
-  defHttp.delete<void>(
+  defHttp.get<void>(
     { url: adminPath + '/pg/remPerson', params: { relId } },
     { skipSuccessMessage: true, skipErrorMessage: true },
   );

+ 1 - 1
ai-frontend/src/plat/api/case/caseApi.ts

@@ -163,7 +163,7 @@ export const update = (data: UpdateCaseDTO) =>
  * @param id 案件 ID
  * @param pwd 案件密码
  */
-export const deleteById = (id: number) => defHttp.delete<void>({ url: adminPath + '/case/delete', params: { id } });
+export const deleteById = (id: number) => defHttp.get<void>({ url: adminPath + '/case/delete', params: { id } });
 
 /**
  * 更新案件密码

+ 1 - 1
ai-frontend/src/plat/api/tpl/tplApi.ts

@@ -72,4 +72,4 @@ export const tplUpdate = (params?: any, data?: TableInfo) =>
  * 删除模板
  */
 export const tplDelete = (params: { id: number }) =>
-  defHttp.delete<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });
+  defHttp.get<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });

+ 3 - 3
ai-frontend/src/trans/api/transApi.ts

@@ -65,7 +65,7 @@ export const createOrUpdateCashKey = (data: TransCashKey) =>
  * 根据ID删除现金关键字
  */
 export const deleteCashKey = (id: string | number) =>
-  defHttp.delete<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
+  defHttp.get<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
 
 // ==================== 金融理财关键字管理 ====================
 
@@ -85,7 +85,7 @@ export const createOrUpdateFinancialKey = (data: TransFinancialKey) =>
  * 根据ID删除金融理财关键字
  */
 export const deleteFinancialKey = (id: string | number) =>
-  defHttp.delete<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
+  defHttp.get<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
 
 // ==================== 定期理财关键字管理 ====================
 
@@ -105,7 +105,7 @@ export const createOrUpdateFixedDepositKey = (data: TransFixedDepositKey) =>
  * 根据ID删除定期理财关键字
  */
 export const deleteFixedDepositKey = (id: number | string) =>
-  defHttp.delete<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
+  defHttp.get<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
 
 // ==================== 大额交易分析 ====================
 

+ 5 - 5
ai-server/src/main/java/com/zsjz/ai/module/agent/controller/AgentChatController.java

@@ -59,7 +59,7 @@ public class AgentChatController {
     /**
      * 更新会话标题
      */
-    @PutMapping("/sessions/{sessionId}/title")
+    @GetMapping("/sessions/{sessionId}/title")
     public void updateSessionTitle(@PathVariable Long sessionId, @RequestParam String title) {
         agentChatService.updateSessionTitle(sessionId, title);
     }
@@ -67,7 +67,7 @@ public class AgentChatController {
     /**
      * 删除会话
      */
-    @DeleteMapping("/sessions/{sessionId}")
+    @GetMapping("/sessions/{sessionId}/delete")
     public void deleteSession(@PathVariable Long sessionId) {
         agentChatService.deleteSession(sessionId);
     }
@@ -75,7 +75,7 @@ public class AgentChatController {
     /**
      * 置顶/取消置顶会话
      */
-    @PutMapping("/sessions/{sessionId}/pin")
+    @GetMapping("/sessions/{sessionId}/pin")
     public void togglePinSession(@PathVariable Long sessionId) {
         agentChatService.togglePinSession(sessionId);
     }
@@ -99,7 +99,7 @@ public class AgentChatController {
     /**
      * 删除消息
      */
-    @DeleteMapping("/messages/{messageId}")
+    @GetMapping("/messages/{messageId}")
     public void deleteMessage(@PathVariable Long messageId) {
         agentChatService.deleteMessage(messageId);
     }
@@ -107,7 +107,7 @@ public class AgentChatController {
     /**
      * 收藏/取消收藏消息
      */
-    @PutMapping("/messages/{messageId}/star")
+    @GetMapping("/messages/{messageId}/star")
     public void toggleStarMessage(@PathVariable Long messageId) {
         agentChatService.toggleStarMessage(messageId);
     }

+ 2 - 2
ai-server/src/main/java/com/zsjz/ai/module/agent/controller/AgentModelController.java

@@ -62,7 +62,7 @@ public class AgentModelController {
     /**
      * 删除模型
      */
-    @DeleteMapping("/{id}")
+    @GetMapping("/{id}")
     public Result<Void> deleteModel(@PathVariable Long id) {
         agentModelService.deleteModel(id);
         return Result.succeed();
@@ -71,7 +71,7 @@ public class AgentModelController {
     /**
      * 设置默认模型
      */
-    @PutMapping("/{id}/default")
+    @GetMapping("/{id}/default")
     public Result<Void> setDefaultModel(@PathVariable Long id) {
         agentModelService.setDefaultModel(id);
         return Result.succeed();

+ 1 - 2
ai-server/src/main/java/com/zsjz/ai/module/agent/insight/controller/InsightController.java

@@ -14,7 +14,6 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.http.MediaType;
 import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -111,7 +110,7 @@ public class InsightController {
     /**
      * 删除会话(消息随外键级联)。
      */
-    @DeleteMapping("/sessions/{id}")
+    @GetMapping("/sessions/{id}/delete")
     public void deleteSession(@PathVariable Long id, @RequestParam Long caseId) {
         insightService.deleteSession(id, caseId);
     }

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

@@ -32,8 +32,8 @@ public class PersonBasicInfoController {
      *
      * @param personName 人员信息personName
      */
-    @DeleteMapping("/delete")
-    public Result<Void> delete(String personName) {
+    @GetMapping("/delete")
+    public Result<Void> delete(@RequestParam String personName) {
         personBasicInfoService.delete(personName);
         return Result.succeed();
     }

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

@@ -70,8 +70,8 @@ public class PersonGroupController {
     /**
      * 删除人员
      */
-    @DeleteMapping("/remPerson")
-    public Result<Void> remPerson(Long relId) {
+    @GetMapping("/remPerson")
+    public Result<Void> remPerson(@RequestParam Long relId) {
         personGroupService.remPerson(relId);
         return Result.succeed();
     }

+ 1 - 2
ai-server/src/main/java/com/zsjz/ai/module/plat/controller/CaseInfoController.java

@@ -7,7 +7,6 @@ import com.zsjz.ai.common.model.plat.entity.CaseInfo;
 import com.zsjz.ai.module.plat.service.CaseInfoService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -60,7 +59,7 @@ public class CaseInfoController {
      *
      * @param id 案件ID
      */
-    @DeleteMapping("/delete")
+    @GetMapping("/delete")
     public Result<Void> delete(Long id) {
         caseInfoService.delete(id);
         return Result.succeed();

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

@@ -11,7 +11,6 @@ import com.zsjz.ai.module.plat.service.TableInfoService;
 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;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -84,7 +83,7 @@ public class TableInfoController {
         return Result.succeed();
     }
 
-    @DeleteMapping("/delete")
+    @GetMapping("/delete")
     public Result<Void> delete(Integer id) {
         tableInfoService.delete(id);
         return Result.succeed();

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

@@ -6,7 +6,6 @@ import com.zsjz.ai.module.trans.service.TransCashKeyService;
 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;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -52,7 +51,7 @@ public class CashKeyController {
      * @param id 现金关键字 ID
      * @return 操作结果,成功返回 true,失败返回 false
      */
-    @DeleteMapping("/delete")
+    @GetMapping("/delete")
     public Result<Boolean> delete(Long id) {
         return Result.succeed(transCashKeyService.removeById(id));
     }

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

@@ -46,7 +46,7 @@ public class FinancialKeyController {
      * @param id 金融理财关键字 ID
      * @return 操作结果,成功返回 true,失败返回 false
      */
-    @DeleteMapping("/delete")
+    @GetMapping("/delete")
     public Result<Boolean> delete(Long id) {
         return Result.succeed(transFinancialKeyService.removeById(id));
     }

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

@@ -6,7 +6,6 @@ import com.zsjz.ai.module.trans.service.FixedDepositKeyService;
 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;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -48,7 +47,7 @@ public class FixedDepositKeyController {
      * @param id 定期理财关键字 ID
      * @return 操作结果,成功返回 true,失败返回 false
      */
-    @DeleteMapping("/delete")
+    @GetMapping("/delete")
     public Result<Boolean> delete(Long id) {
         return Result.succeed(fixedDepositKeyService.removeById(id));
     }

+ 323 - 0
api-method-refactor-plan.md

@@ -0,0 +1,323 @@
+# 接口方法规范改造计划(禁用 PUT / DELETE)
+
+- 项目:`E:\workspace\zsjz-ai`(后端 `ai-server`,前端 `ai-frontend`)
+- 更新时间:2026-09-18
+- 状态:**已执行完成**(后端编译 BUILD SUCCESS、前端构建成功;豁免项保持原样)
+- v2 修订:新增 §1.4 保持类豁免、§1.3 前端改动边界(禁止改封装工具)
+- v3 修订:新增 §1.5 的 2 处路径变更(GET 路由冲突),补充执行与验证实测结果
+
+---
+
+## 1. 执行口径(硬性)
+
+### 1.1 改造规则
+
+1. 禁止 `@PutMapping` / `@DeleteMapping` / `@PatchMapping` / `@RequestMapping(method=PUT|DELETE|PATCH)`。
+2. 方法带 `@RequestBody` → 必须 POST。
+3. 无 `@RequestBody` 时:形参 > 3 → POST;≤ 3 → GET。
+4. 形参个数按方法签名的形参计,不按 DTO 内部字段数计。
+
+### 1.2 保持类豁免(最高优先级,严格执行)
+
+**符合以下任一条件的接口,一律不改造,保持原样:**
+
+- **A 类**:当前已经是 `@GetMapping` 的接口(含绑定 Query / DTO 对象形参的 GET);
+- **B 类**:方法形参中已带 `@RequestBody` 的接口。
+
+**本次实际改造范围 = 既不是 `@GetMapping`、又没有 `@RequestBody` 的接口。**
+
+### 1.3 前端改动边界(严格执行)
+
+**只改「调用哪个请求方法」这一处,禁止改动任何已封装好的请求工具。** 以下文件一个字节都不动:
+
+| 文件 | 说明 |
+|---|---|
+| `src/core/utils/http/axios/Axios.ts` | 底层 `defHttp`,其中 `put()` / `delete()` 方法保留(豁免项仍在用 `put`) |
+| `src/core/utils/http/axios/index.ts` | `beforeRequestHook` / `transformRequestHook` 拦截逻辑 |
+| `src/ai/api/http.ts` | `aiHttp` 封装,`putRaw` / `deleteRaw` / `putJson` / `delete` / `withQuery` 全部保留原样 |
+
+前端改动只落在 api 层调用点(§3):`defHttp.delete(...)` → `defHttp.get(...)`、`aiHttp.deleteRaw(...)` → `aiHttp.getRaw(...)` 这类**调用替换**,不涉及工具本身。
+
+### 1.4 过滤结果
+
+| 类别 | 数量 | 处理 |
+|---|---|---|
+| PUT / DELETE 且**无** `@RequestBody` | **15** | 后端改 `@GetMapping` + 前端调用改 GET(清单见 §2) |
+| PUT / DELETE 且**带** `@RequestBody` | **1**(`AgentModelController#updateModel`) | **豁免,保持 `@PutMapping` 原样**(§4.1) |
+| 原本就是 `@GetMapping` | 47 | **豁免,不动** |
+| 原本就是 `@PostMapping`(含带/不带 `@RequestBody`) | 82 | **豁免,不动** |
+
+> 附带说明(不改造):5 个不带 `@RequestBody` 的 POST(`DmController.preFileUpload`、`AuthController.logout`、`SystemController.noNet`、`SystemController.uploadUpgrade`、`TowerController.covFile`)按规则 3 本是 GET 候选,但它们已经是 POST,不违反任何规则,保持不动。
+
+### 1.5 路径兼容性
+
+改造不动 URL 与路径变量,只换 HTTP 方法。路由、拦截器、Sa-Token 鉴权配置全部不变。
+
+**唯一例外(2 处,已执行)**:以下两个删除接口改 GET 后与既有 GET 详情接口同路径,会触发 Spring「Ambiguous mapping」启动异常,故加 `/delete` 后缀(与项目 `/case/delete`、`/tpl/delete` 风格一致),前端同步:
+
+| 接口 | 原路径(DELETE) | 新路径(GET) | 冲突对象 |
+|---|---|---|---|
+| `AgentChatController#deleteSession` | `/chat/sessions/{sessionId}` | `/chat/sessions/{sessionId}/delete` | 既有 `GET /chat/sessions/{sessionId}`(getSession) |
+| `InsightController#deleteSession` | `/insight/sessions/{id}` | `/insight/sessions/{id}/delete` | 既有 `GET /insight/sessions/{id}`(getSession) |
+
+其余 13 处路径零变化。
+
+---
+
+## 2. 后端改造清单(15 处)
+
+| # | 文件(相对 `ai-server/src/main/java/com/zsjz/ai/`) | 行 | 现状 | 接口 | 形参 | 目标 | 前端传参 |
+|---|---|---|---|---|---|---|---|
+| 1 | `module/agent/controller/AgentChatController.java` | 62 | PUT | `/chat/sessions/{sessionId}/title` updateSessionTitle | 2(path+param) | **GET** | query: `title` |
+| 2 | 同上 | 70 | DELETE | ~~`/chat/sessions/{sessionId}`~~ → `/chat/sessions/{sessionId}/delete` deleteSession | 1 | **GET** | — |
+| 3 | 同上 | 78 | PUT | `/chat/sessions/{sessionId}/pin` togglePinSession | 1 | **GET** | — |
+| 4 | 同上 | 102 | DELETE | `/chat/messages/{messageId}` deleteMessage | 1 | **GET** | — |
+| 5 | 同上 | 110 | PUT | `/chat/messages/{messageId}/star` toggleStarMessage | 1 | **GET** | — |
+| 6 | `module/agent/controller/AgentModelController.java` | 65 | DELETE | `/models/{id}` deleteModel | 1 | **GET** | — |
+| 7 | 同上 | 74 | PUT | `/models/{id}/default` setDefaultModel | 1 | **GET** | — |
+| 8 | `module/agent/insight/controller/InsightController.java` | 114 | DELETE | ~~`/insight/sessions/{id}`~~ → `/insight/sessions/{id}/delete` deleteSession | 2(path+param) | **GET** | query: `caseId` |
+| 9 | `module/person/controller/PersonBasicInfoController.java` | 35 | DELETE | `/pbi/delete` delete | 1(`String personName`) | **GET** | query: `personName` |
+| 10 | `module/person/controller/PersonGroupController.java` | 73 | DELETE | `/pg/remPerson` remPerson | 1(`Long relId`) | **GET** | query: `relId` |
+| 11 | `module/plat/controller/CaseInfoController.java` | 63 | DELETE | `/case/delete` delete | 1(`Long id`) | **GET** | query: `id` |
+| 12 | `module/plat/controller/TableInfoController.java` | 87 | DELETE | `/tpl/delete` delete | 1(`Integer id`) | **GET** | query: `id` |
+| 13 | `module/trans/controller/CashKeyController.java` | 55 | DELETE | `/trans/cashKey/delete` delete | 1(`Long id`) | **GET** | query: `id` |
+| 14 | `module/trans/controller/FinancialKeyController.java` | 49 | DELETE | `/trans/financialKey/delete` delete | 1(`Long id`) | **GET** | query: `id` |
+| 15 | `module/trans/controller/FixedDepositKeyController.java` | 51 | DELETE | `/fixedDepositKey/delete` delete | 1(`Long id`) | **GET** | query: `id` |
+
+### 2.1 后端改动样板
+
+单参数(#2/#4/#6/#11/#12/#13/#14/#15):
+
+```java
+// before
+@DeleteMapping("/sessions/{sessionId}")
+public void deleteSession(@PathVariable Long sessionId) { ... }
+
+// after
+@GetMapping("/sessions/{sessionId}")
+public void deleteSession(@PathVariable Long sessionId) { ... }
+```
+
+带简单类型参数(#1/#8/#9/#10)——顺手补 `@RequestParam`,行为不变:
+
+```java
+// before
+@DeleteMapping("/delete")
+public Result<Void> delete(Long id) { ... }
+
+// after
+@GetMapping("/delete")
+public Result<Void> delete(@RequestParam Long id) { ... }
+```
+
+### 2.2 import 清理
+
+改为 GET 后删除无用 import 行 `import org.springframework.web.bind.annotation.DeleteMapping;`:
+`InsightController`、`CaseInfoController`、`TableInfoController`、`CashKeyController`、`FixedDepositKeyController`。
+
+`AgentChatController`、`AgentModelController`、`PersonBasicInfoController`、`PersonGroupController`、`FinancialKeyController` 用的是 `web.bind.annotation.*` 通配,不动。
+
+---
+
+## 3. 前端配合改造(15 处调用点)
+
+只替换请求方法调用,不改任何封装工具(§1.3)。所有调用都走 api 层函数,视图组件只 import 函数名,改完 api 层后 `.vue` / store 层零改动(调用点见 §3.4)。
+
+### 3.1 `src/ai/api/chatApi.ts`(5 处)
+
+```ts
+// #1 before
+return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/title`, undefined, { title });
+// after
+return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/title`, { title });
+
+// #2 before
+return aiHttp.deleteRaw<void>(`/chat/sessions/${sessionId}`);
+// after(路径加 /delete,原因见 §1.5)
+return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/delete`);
+
+// #3 before
+return aiHttp.putRaw<void>(`/chat/sessions/${sessionId}/pin`);
+// after
+return aiHttp.getRaw<void>(`/chat/sessions/${sessionId}/pin`);
+
+// #4 before
+return aiHttp.deleteRaw<void>(`/chat/messages/${messageId}`);
+// after
+return aiHttp.getRaw<void>(`/chat/messages/${messageId}`);
+
+// #5 before
+return aiHttp.putRaw<void>(`/chat/messages/${messageId}/star`);
+// after
+return aiHttp.getRaw<void>(`/chat/messages/${messageId}/star`);
+```
+
+### 3.2 `src/ai/api/modelApi.ts`(2 处)
+
+```ts
+// #6 before
+return aiHttp.delete<void>(`/models/${id}`);
+// after
+return aiHttp.get<void>(`/models/${id}`);
+
+// #7 before
+return aiHttp.putJson<void>(`/models/${id}/default`);
+// after
+return aiHttp.get<void>(`/models/${id}/default`);
+```
+
+> `modelApi.ts:27` 的 `updateModel`(`aiHttp.putJson`)**保持不动**,对应后端 §4.1 豁免项。
+
+### 3.3 其余模块(8 处)
+
+```ts
+// #8  src/graph/insight/api.ts:62
+// before
+return aiHttp.deleteRaw<void>(`${BASE}/sessions/${id}`, { caseId });
+// after(路径加 /delete,原因见 §1.5)
+return aiHttp.getRaw<void>(`${BASE}/sessions/${id}/delete`, { caseId });
+
+// #9  src/person/api/personApi.ts:99
+// before  defHttp.delete<void>({ url: adminPath + '/pbi/delete', params: { personName } }, {...})
+// after   defHttp.get<void>({ url: adminPath + '/pbi/delete', params: { personName } }, {...})
+
+// #10 src/person/api/personApi.ts:196
+// before  defHttp.delete<void>({ url: adminPath + '/pg/remPerson', params: { relId } }, {...})
+// after   defHttp.get<void>({ url: adminPath + '/pg/remPerson', params: { relId } }, {...})
+
+// #11 src/plat/api/tpl/tplApi.ts:75
+// before  defHttp.delete<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });
+// after   defHttp.get<void>({ url: adminPath + '/tpl/delete', params }, { skipSuccessMessage: true });
+
+// #12 src/plat/api/case/caseApi.ts:166
+// before  defHttp.delete<void>({ url: adminPath + '/case/delete', params: { id } });
+// after   defHttp.get<void>({ url: adminPath + '/case/delete', params: { id } });
+
+// #13 src/trans/api/transApi.ts:68
+// before  defHttp.delete<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
+// after   defHttp.get<void>({ url: adminPath + '/trans/cashKey/delete', params: { id } });
+
+// #14 src/trans/api/transApi.ts:88
+// before  defHttp.delete<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
+// after   defHttp.get<void>({ url: adminPath + '/trans/financialKey/delete', params: { id } });
+
+// #15 src/trans/api/transApi.ts:108
+// before  defHttp.delete<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
+// after   defHttp.get<void>({ url: adminPath + '/fixedDepositKey/delete', params: { id } });
+```
+
+### 3.4 调用点(不改,仅用于回归验证)
+
+| api 函数 | 调用方 |
+|---|---|
+| `updateSessionTitle` / `deleteSession` / `togglePinSession` / `deleteMessage` / `toggleStarMessage` | `src/ai/store/chatStream.ts` |
+| `modelApi.updateModel`(豁免项) | `src/ai/components/ModelFormModal.vue:82` |
+| `modelApi.setDefaultModel` / `deleteModel` | `src/ai/views/aiModel/index.vue` |
+| `deleteInsightSession` | `src/graph/insight/hooks/useInsightStream.ts` |
+| `deletePersonBasicInfo` / `remPersonFromGroup` | `src/case/views/dm/portrait.vue` |
+| `tplDelete` | `src/case/views/data/index.vue` |
+| `deleteById`(案件) | `src/plat/views/case/case.vue` |
+| `deleteCashKey` | `src/trans/views/cashTrans/index.vue` |
+| `deleteFinancialKey` | `src/trans/views/financialWealth/index.vue` |
+| `deleteFixedDepositKey` | `src/trans/views/fixedDeposit/index.vue` |
+
+### 3.5 前端改动文件清单(仅这 7 个)
+
+`src/ai/api/chatApi.ts`、`src/ai/api/modelApi.ts`、`src/graph/insight/api.ts`、`src/person/api/personApi.ts`、`src/plat/api/tpl/tplApi.ts`、`src/plat/api/case/caseApi.ts`、`src/trans/api/transApi.ts`。
+
+封装工具文件 `src/ai/api/http.ts`、`src/core/utils/http/axios/Axios.ts`、`src/core/utils/http/axios/index.ts` **不在改动清单内**。
+
+---
+
+## 4. 豁免清单(明确不改造)
+
+### 4.1 `AgentModelController#updateModel`(唯一带 body 的 PUT)
+
+- 后端 `AgentModelController.java:56`:`@PutMapping("/{id}")`,形参含 `@Valid @RequestBody UpdateModelDTO` → **命中 B 类豁免,保持 `PUT` + `@RequestBody` 原样**;
+- 前端 `src/ai/api/modelApi.ts:27`:`aiHttp.putJson` **保持不动**;
+- 结果:改造后 `@DeleteMapping` 为 0、`@PutMapping` 残留 1 处,此条为豁免白名单,§6 的 grep 校验需排除它。
+
+### 4.2 其余豁免
+
+- 全部 47 个 `@GetMapping` 接口(含 `InsightController#listMessages`、`DataProfileController#getTransOtherNamePage`、`TableInfoController#page`、`SpecialDateController#delete` 这类 Query/DTO 对象形参的 GET);
+- 全部 82 个 `@PostMapping` 接口。
+
+### 4.3 附带记录(不在本次改造范围)
+
+`src/person/api/personApi.ts:79` 的 `deleteSpecialDateConfig` 用 `defHttp.delete` 调用 `/sdc/delete`,后端 `SpecialDateController.java:39` 是 `@GetMapping` —— 方法不匹配(现网表现为 405)。后端是 GET,命中 A 类豁免,本次不动;前端调用方式本批也不动,仅记录。
+
+---
+
+## 5. 执行顺序
+
+1. 前置校验:逐条确认待改方法既不是 `@GetMapping`、也没有 `@RequestBody`,命中任一即跳过。
+2. 后端 15 处注解改为 `@GetMapping`(§2)+ 清理 5 个无用 `DeleteMapping` import。
+3. 处理 2 处 GET 路由冲突:`AgentChatController#deleteSession`、`InsightController#deleteSession` 路径加 `/delete`(§1.5)。
+4. 前端 15 处调用点替换请求方法(§3.1、§3.2、§3.3),只动 §3.5 列出的 7 个文件。
+5. 编译与类型检查(§6)。
+6. 全仓复扫:确认 `@DeleteMapping` 为 0、`@PutMapping` 仅剩 §4.1 白名单 1 处。
+7. 豁免复核:`git diff` 中只应出现 §2 的后端文件 + §3.5 的 7 个前端文件;封装工具文件、47 个 GET 接口、82 个 POST 接口一个都不能被改到。
+
+---
+
+## 6. 验证清单
+
+**编译 / 类型**
+- 后端:`mvn -q -pl ai-server compile`,零错误。
+- 前端:`vue-tsc --noEmit` + `pnpm build`,零错误。
+- 部署时必须替换线上 `dist`,否则 api 层改动不生效。
+
+**冒烟(浏览器逐一操作)**
+
+| # | 功能 | 页面 | 预期 |
+|---|---|---|---|
+| 1 | 会话重命名 | AI 数据分析左侧会话条 | 标题更新,Network 显示 GET |
+| 2 | 删除会话 | 同上 | 会话消失 |
+| 3 | 会话置顶/取消 | 同上 | 排序变化 |
+| 4 | 删除消息 | 对话区消息悬浮菜单 | 消息消失 |
+| 5 | 消息收藏/取消 | 同上 | 星标切换 |
+| 6 | 删除模型 | AI 模型管理 | 列表刷新(GET) |
+| 7 | 设为默认模型 | AI 模型管理 | 默认标记切换(GET) |
+| 8 | 编辑模型(豁免项,保持 PUT) | AI 模型管理 - 编辑弹窗 | 保存成功,Network 仍为 PUT |
+| 9 | 删除研判会话 | 对象关系分析 - 历史 | 会话消失 |
+| 10 | 删除人员 | 人物画像 `case/views/dm/portrait.vue` | 人员移除 |
+| 11 | 分组移除成员 | 同上 | 成员移除 |
+| 12 | 删除模板 | 数据管理 `case/views/data/index.vue` | 模板消失 |
+| 13 | 删除案件 | 案件管理 `plat/views/case/case.vue` | 案件消失 |
+| 14 | 删除现金关键字 | 资金交易 - 现金交易 | 列表刷新 |
+| 15 | 删除金融理财关键字 | 资金交易 - 金融理财 | 列表刷新 |
+| 16 | 删除定期理财关键字 | 资金交易 - 定期理财 | 列表刷新 |
+
+**交叉确认**(改造后已实测):
+- 后端 `@DeleteMapping`:**0**;`@PutMapping`:**1**(`AgentModelController.java:56`,白名单)。
+- 前端 api 调用点中 `defHttp.delete` / `defHttp.put` / `aiHttp.deleteRaw` / `aiHttp.putRaw` / `aiHttp.delete`:**0**;`aiHttp.putJson`:**1**(`modelApi.ts:27`,白名单)。
+- `src/ai/api/http.ts` 与 `src/core/utils/http/axios/*`:**零改动**。
+
+**编译 / 构建实测结果(2026-09-18 19:26 / 19:28)**
+- 后端 `mvn -pl ai-server compile`:**BUILD SUCCESS**(686 个源文件,耗时 1m02s)。
+- 前端 `pnpm build`:**成功**(vite build,耗时 1m39s,`dist` 已重新产出)。
+- 前端 `vue-tsc --noEmit`:项目存在约 100+ 条**存量**类型错误(与本批改动无关,集中在 `graph/views/graph/index.vue`、`case/views/dm/portrait.vue`、`otg/utils/timeSeriesJump.ts` 等);本批改动的 7 个前端文件中**没有新增错误**,仅 `person/api/personApi.ts:119`(`isShowLoading`)一条既有报错,非本次改动行。
+
+**改动文件清单(`git diff --name-only`,共 17 个)**
+后端 10 个:`AgentChatController`、`AgentModelController`、`InsightController`、`PersonBasicInfoController`、`PersonGroupController`、`CaseInfoController`、`TableInfoController`、`CashKeyController`、`FinancialKeyController`、`FixedDepositKeyController`。
+前端 7 个:`ai/api/chatApi.ts`、`ai/api/modelApi.ts`、`graph/insight/api.ts`、`person/api/personApi.ts`、`plat/api/case/caseApi.ts`、`plat/api/tpl/tplApi.ts`、`trans/api/transApi.ts`。
+
+---
+
+## 7. 执行须知
+
+1. 删除操作走 GET,请求会被浏览器历史与代理日志记录;将来若接入 WAF / 网关的「只读放行 GET」策略,这些删除接口会失去保护。
+2. GET 的浏览器缓存不存在问题 —— 前端 `beforeRequestHook`(`core/utils/http/axios/index.ts:147-156`)对 GET 自动追加 `_t` 时间戳。
+3. `/pbi/delete?personName=张三` 走 URL 传参,依赖服务端 URI 编码 UTF-8(Spring Boot 3 默认),回归时确认中文姓名能正常删除。
+4. 本批接口参数最多 2 个,无 URL 超长风险。
+5. `dist` 未重新构建会导致改动看似未生效。
+
+---
+
+## 8. 规范条文(写入 `AI_AGENT.md`「接口方法规范」)
+
+1. 只用 **GET / POST**,禁止 `PUT` / `DELETE` / `PATCH`。
+2. 方法带 `@RequestBody` → 必须 POST。
+3. 无 `@RequestBody` 时:形参 > 3 → POST;≤ 3 → GET。
+4. **保持类(优先级高于以上全部)**:已经是 `@GetMapping` 的接口、形参已带 `@RequestBody` 的接口,**一律不再改造**。
+5. 改造只动业务 api 层调用与 Controller 注解,**禁止改动已封装的请求工具**(`src/core/utils/http/**`、`src/ai/api/http.ts`)。