Explorar el Código

refactor(aiclean): 移除 ai_clean_template.case_id_src,模板跨案件全局共享

- 删除实体字段、出口 B 登记写入与 field-labels 词条
- 移除 dataPage 按模板归属案件的 403 校验(跨案复用模板后查看数据被挡的卡点)
- ai_clean.sql 删列;新增存量库迁移脚本 ai_clean_template_drop_case_src.sql
- PG 往返测试清理定位改用 it- 指纹前缀
cc hace 3 días
padre
commit
7d4bd277ae

+ 0 - 6
ai-server/src/main/java/com/zsjz/ai/module/aiclean/entity/AiCleanTemplate.java

@@ -152,12 +152,6 @@ public class AiCleanTemplate implements Serializable {
     @TableField("confidence")
     private BigDecimal confidence;
 
-    /**
-     * 首次识别出该模板的案件 ID
-     */
-    @TableField("case_id_src")
-    private Long caseIdSrc;
-
     @TableField("create_by")
     private Long createBy;
 

+ 2 - 7
ai-server/src/main/java/com/zsjz/ai/module/aiclean/service/AiCleanService.java

@@ -504,7 +504,6 @@ public class AiCleanService {
             tpl.setMatchTier(job.getMatchTier());
             tpl.setVer(1);
             tpl.setNeedsStruct(0);
-            tpl.setCaseIdSrc(job.getCaseId());
             tpl.setConfidence(job.getConfidence());
             tpl.setCreateTime(LocalDateTime.now());
             // 规则覆盖全部列(含按原样保留的 TEXT 列):下次同表头文件才能零模型重放、
@@ -1011,13 +1010,9 @@ public class AiCleanService {
      * 表格组件、翻页、排序都不用加特例。
      */
     public Map<String, Object> dataPage(Long aiTemplateId, String orderKey, boolean asc, long page, long size) {
-        Long openCaseId = caseAccessGuard.requireOpenCaseId();
+        // 模板全局共享、动态表按案件路由,取数仍要求先打开案件
+        caseAccessGuard.requireOpenCaseId();
         AiCleanTemplate tpl = templateMapper.selectById(aiTemplateId);
-        // 动态表在当前案件库里:模板若记录了来源案件,必须与当前案件一致
-        if (tpl != null && tpl.getCaseIdSrc() != null
-                && !openCaseId.equals(tpl.getCaseIdSrc())) {
-            throw new com.zsjz.ai.common.exception.ServerException(403, "该模板不属于当前打开的案件");
-        }
         Map<String, Object> out = new LinkedHashMap<>();
         List<AiCleanField> fields = tpl == null ? List.of()
                 : fieldMapper.selectList(Wrappers.<AiCleanField>lambdaQuery()

+ 0 - 2
ai-server/src/main/resources/agent/field-labels.json

@@ -64,7 +64,6 @@
     "cardType": "卡片类型",
     "caseBrief": "简要案情",
     "caseDate": "立案日期",
-    "caseIdSrc": "首次识别出该模板的案件 ID",
     "caseNo": "案件编号",
     "caseType": "案件类别",
     "caseUnit": "立案单位",
@@ -2712,7 +2711,6 @@
     },
     "com.zsjz.ai.module.aiclean.entity.AiCleanTemplate": {
       "blockNo": "单 sheet 多表头时的块序号",
-      "caseIdSrc": "首次识别出该模板的案件 ID",
       "category": "业务分类",
       "categoryL2": "二级分类",
       "confidence": "登记时的置信度",

+ 3 - 4
ai-server/src/test/java/com/zsjz/ai/module/aiclean/AiCleanPgRoundTripTest.java

@@ -71,7 +71,6 @@ class AiCleanPgRoundTripTest {
             tpl.setHeaderMd5("it-md5-" + SENTINEL_CASE);
             tpl.setStatus("ONLINE");
             tpl.setCategory("TRANSACTION");
-            tpl.setCaseIdSrc(SENTINEL_CASE);
 
             AiCleanField f = new AiCleanField();
             f.setColumnName("c0");
@@ -164,7 +163,6 @@ class AiCleanPgRoundTripTest {
         t.setStatus("ONLINE");
         t.setVer(1);
         t.setNeedsStruct(0);
-        t.setCaseIdSrc(SENTINEL_CASE);
         t.setCreateTime(LocalDateTime.now());
         return t;
     }
@@ -184,8 +182,9 @@ class AiCleanPgRoundTripTest {
     }
 
     private void cleanUp() {
+        // 用例的指纹都以 it- 开头(哨兵前缀),按它清理模板;字段/规则挂在模板 id 下
         List<AiCleanTemplate> tpls = templateMapper.selectList(Wrappers.<AiCleanTemplate>lambdaQuery()
-                .eq(AiCleanTemplate::getCaseIdSrc, SENTINEL_CASE));
+                .likeRight(AiCleanTemplate::getHeaderMd5, "it-"));
         for (AiCleanTemplate t : tpls) {
             fieldMapper.delete(Wrappers.<AiCleanField>lambdaQuery()
                     .eq(AiCleanField::getAiTemplateId, t.getId()));
@@ -193,7 +192,7 @@ class AiCleanPgRoundTripTest {
                     .eq(AiCleanRule::getAiTemplateId, t.getId()));
         }
         templateMapper.delete(Wrappers.<AiCleanTemplate>lambdaQuery()
-                .eq(AiCleanTemplate::getCaseIdSrc, SENTINEL_CASE));
+                .likeRight(AiCleanTemplate::getHeaderMd5, "it-"));
         jobMapper.delete(Wrappers.<AiCleanJob>lambdaQuery()
                 .eq(AiCleanJob::getCaseId, SENTINEL_CASE));
     }

+ 0 - 1
sql/ai_clean.sql

@@ -35,7 +35,6 @@ create table if not exists ai_clean_template
     status               varchar(20)  default 'DRAFT',     -- DRAFT/ONLINE/OFFLINE;OFFLINE = 从治理树摘除
     ver                  integer      default 1,
     confidence           numeric(6, 4),
-    case_id_src          bigint,                           -- 首次识别出该模板的案件(跨案复用时不回写)
     create_by            bigint,
     create_time          timestamp    default current_timestamp,
     update_time          timestamp

+ 10 - 0
sql/ai_clean_template_drop_case_src.sql

@@ -0,0 +1,10 @@
+-- ============================================================================
+-- ai_clean_template:移除 case_id_src(2026-10-25)
+--
+-- 所有模板跨案件共享(案件 B 命中案件 A 识别出的模板时直接零模型复用),
+-- 不再记录「首次识别出该模板的案件」;配套的 dataPage 案件归属 403 校验一并移除,
+-- 否则复用模板的案件查看自己的数据会被挡住。
+-- 本脚本用于**已存在的** ai_clean_template 表;新环境直接按 ai_clean.sql 建表即可。
+-- ============================================================================
+
+alter table ai_clean_template drop column if exists case_id_src;