Ver código fonte

Merge branch 'master' of http://git.yangzhiqiang.tech/jiayq/ai-tagging

jiayongqiang 1 dia atrás
pai
commit
02484364a0
17 arquivos alterados com 418 adições e 35 exclusões
  1. 11 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/AitagTagCategoryController.java
  2. 44 6
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/AitagTagInfoController.java
  3. 1 1
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/FastApiController.java
  4. 29 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/dto/TagImportDto.java
  5. 23 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/vo/GenerateRegexVo.java
  6. 3 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/vo/fastapivo/AiTaggingResponseVo.java
  7. 8 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/mapper/AitagTagCategoryMapper.java
  8. 6 1
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/AitagTagCategoryService.java
  9. 7 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/AitagTagInfoService.java
  10. 45 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/TagImportListener.java
  11. 23 0
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/impl/AitagTagCategoryServiceImpl.java
  12. 197 3
      server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/impl/AitagTagInfoServiceImpl.java
  13. 5 0
      server/yusp-tagging-core/src/main/resources/mapper/AitagTagCategoryMapper.xml
  14. 1 1
      server/yusp-tagging-core/src/main/resources/mapper/AitagTagLogMapper.xml
  15. 8 1
      server/yusp-tagging-core/src/main/resources/messages/yusp_input_msg.properties
  16. 0 19
      server/yusp-tagging-starter/src/main/java/cn/com/yusys/yusp/detail/App.java
  17. 7 3
      server/yusp-tagging-starter/src/main/resources/application.yml

+ 11 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/AitagTagCategoryController.java

@@ -112,4 +112,15 @@ public class AitagTagCategoryController {
             return Result.error("500", "分页查询失败:" + e.getMessage());
         }
     }
+
+    @ApiOperationType("标签体系详情")
+    @GetMapping("/detail/{id}")
+    public Result<AitagTagCategoryVo> getCategoryDetail(@PathVariable String id) {
+        try {
+            AitagTagCategoryVo categoryDetail = aiTagCategoryService.getCategoryDetail(id);
+            return Result.success(categoryDetail);
+        } catch (Exception e) {
+            return Result.error("500", "查询标签体系详情失败:" + e.getMessage());
+        }
+    }
 }

+ 44 - 6
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/AitagTagInfoController.java

@@ -5,6 +5,7 @@ import cn.com.yusys.yusp.commons.module.adapter.web.rest.ResultDto;
 import cn.com.yusys.yusp.domain.dto.TagInfoDto;
 import cn.com.yusys.yusp.domain.entity.AitagTagInfoEntity;
 import cn.com.yusys.yusp.domain.vo.AitagTagInfoQueryVo;
+import cn.com.yusys.yusp.domain.vo.GenerateRegexVo;
 import cn.com.yusys.yusp.domain.vo.TagNodeVo;
 import cn.com.yusys.yusp.domain.vo.VersionRollbackVo;
 import cn.com.yusys.yusp.service.AitagTagInfoService;
@@ -13,13 +14,11 @@ import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 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;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -151,4 +150,43 @@ public class AitagTagInfoController {
         return ResultDto.success();
     }
 
+    /**
+     * 批量导入
+     *
+     * @param file
+     * @return ResultDto
+     */
+    @ApiOperation("批量导入")
+    @PostMapping("/batchImport")
+    public ResultDto batchImport( @RequestParam("file") MultipartFile file,
+                                  @RequestParam("reviser") String reviser,
+                                  @RequestParam("categoryId") String categoryId) throws IOException {
+
+        if (file.isEmpty()) {
+           throw BizException.of("E002");
+        }
+
+        // 简单的文件类型检查
+        String fileName = file.getOriginalFilename();
+        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
+            throw BizException.of("E003");
+        }
+        aitagTagInfoService.batchImport(file,reviser,categoryId);
+        return ResultDto.success();
+    }
+
+
+    /**
+     * 生成正则表达式
+     *
+     * @param regexVo
+     * @return ResultDto
+     */
+    @ApiOperation("生成正则表达式")
+    @PostMapping("/generateRegex")
+    public ResultDto<String> generateRegex( @RequestBody GenerateRegexVo regexVo) throws IOException {
+        return ResultDto.success(aitagTagInfoService.generateRegex(regexVo));
+    }
+
+
 }

+ 1 - 1
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/controller/FastApiController.java

@@ -63,7 +63,7 @@ public class FastApiController {
     }
 
     @ApiOperationType("AI打标反馈")
-    @GetMapping("/feedback")
+    @PostMapping("/feedback")
     public Result<AiTaggingResponseVo> feedback(
             @RequestParam(required = false) String userId,
             @RequestParam(required = false) String userNm,

+ 29 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/dto/TagImportDto.java

@@ -0,0 +1,29 @@
+package cn.com.yusys.yusp.domain.dto;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class TagImportDto {
+
+    @ExcelProperty("标签名称")
+    private String tagNm;
+
+    @ExcelProperty("父标签名称")
+    private String parentName;
+
+    @ExcelProperty("标签说明")
+    private String tagRemark;
+
+    @ExcelProperty("标签关键词规则")
+    private String reg;
+
+    /**
+     *  运行时填充字段
+     */
+    private String id;
+    private String parentId;
+    private String tagPath;
+}

+ 23 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/vo/GenerateRegexVo.java

@@ -0,0 +1,23 @@
+package cn.com.yusys.yusp.domain.vo;
+
+
+import lombok.Data;
+
+/**
+ * 生成正则表达式入场
+ */
+
+@Data
+public class GenerateRegexVo {
+
+    /**
+     * 标签名称
+     */
+     private String tag_name;
+
+
+    /**
+     * 标签说明
+     */
+    private String tag_remark;
+}

+ 3 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/domain/vo/fastapivo/AiTaggingResponseVo.java

@@ -13,4 +13,7 @@ public class AiTaggingResponseVo {
 
     @ApiModelProperty(value = "消息内容")
     private String message;
+
+    @ApiModelProperty(value = "返回报文体")
+    private String body;
 }

+ 8 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/mapper/AitagTagCategoryMapper.java

@@ -44,4 +44,12 @@ public interface AitagTagCategoryMapper {
 
     // 统计已启用标签体系的数量
     long selectCountEnabled();
+
+    /**
+     * 根据ID查询标签体系详情(包含标签数量)
+     * @param id 标签体系ID
+     * @return 标签体系实体
+     */
+    AitagTagCategory selectDetailById(@Param("id") String id);
+
 }

+ 6 - 1
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/AitagTagCategoryService.java

@@ -18,5 +18,10 @@ public interface AitagTagCategoryService {
     void deleteCategory(String id);
     // 分页查询已启用的标签体系
     Page<AitagTagCategoryVo> listEnabledCategories(int page, int size);
-
+    /**
+     * 根据ID查询标签体系详情
+     * @param id 标签体系ID
+     * @return 标签体系详情VO
+     */
+    AitagTagCategoryVo getCategoryDetail(String id);
 }

+ 7 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/AitagTagInfoService.java

@@ -3,11 +3,14 @@ package cn.com.yusys.yusp.service;
 import cn.com.yusys.yusp.domain.dto.TagInfoDto;
 import cn.com.yusys.yusp.domain.entity.AitagTagInfoEntity;
 import cn.com.yusys.yusp.domain.vo.AitagTagInfoQueryVo;
+import cn.com.yusys.yusp.domain.vo.GenerateRegexVo;
 import cn.com.yusys.yusp.domain.vo.TagNodeVo;
 import cn.com.yusys.yusp.domain.vo.VersionRollbackVo;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -40,5 +43,9 @@ public interface AitagTagInfoService extends IService<AitagTagInfoEntity> {
     void versionRollback(VersionRollbackVo versionRollbackVo);
 
     List<AitagTagInfoEntity> queryList(AitagTagInfoQueryVo aitagTagInfoQueryVo);
+
+    void batchImport(MultipartFile file,String reviser,String categoryId) throws IOException;
+
+    String generateRegex(GenerateRegexVo regexVo);
 }
 

+ 45 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/TagImportListener.java

@@ -0,0 +1,45 @@
+package cn.com.yusys.yusp.service;
+
+import cn.com.yusys.yusp.commons.util.StringUtils;
+import cn.com.yusys.yusp.domain.dto.TagImportDto;
+import cn.com.yusys.yusp.mapper.AitagTagInfoDao;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+
+
+@Slf4j
+public class TagImportListener extends AnalysisEventListener<TagImportDto> {
+    private final List<TagImportDto> dataList = new ArrayList<>();
+
+
+    @Override
+    public void invoke(TagImportDto data, AnalysisContext context) {
+        // 数据清洗
+        if (StringUtils.isBlank(data.getTagNm())) {
+            return;
+        }
+        data.setTagNm(data.getTagNm().trim());
+        if (!StringUtils.isBlank(data.getParentName())) {
+            data.setParentName(data.getParentName().trim());
+        }
+
+        // 生成临时 ID
+        data.setId(UUID.randomUUID().toString().replace("-", ""));
+        dataList.add(data);
+    }
+
+    @Override
+    public void doAfterAllAnalysed(AnalysisContext context) {
+        // 解析完成后自动调用 processData,或者在外部调用
+    }
+    public List<TagImportDto> getDataList() {
+        return dataList;
+    }
+
+}

+ 23 - 0
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/impl/AitagTagCategoryServiceImpl.java

@@ -174,4 +174,27 @@ public class AitagTagCategoryServiceImpl implements AitagTagCategoryService {
         pageObj.setRecords(voList);
         return pageObj;
     }
+
+    @Override
+    public AitagTagCategoryVo getCategoryDetail(String id) {
+        AitagTagCategory category = aiTagCategoryMapper.selectDetailById(id);
+        if (category == null) {
+            throw new RuntimeException("标签体系不存在");
+        }
+
+        AitagTagCategoryVo vo = new AitagTagCategoryVo();
+        vo.setId(category.getId());
+        vo.setCategoryCode(category.getCategoryCode());
+        vo.setCategoryNm(category.getCategoryNm());
+        vo.setCategoryDesc(category.getCategoryDesc());
+        vo.setVisibilityLevel(category.getVisibilityLevel());
+        vo.setState(category.getState());
+        vo.setIsDelete(category.getIsDelete());
+
+        // 计算标签数量
+        int tagNum = aiTagCategoryMapper.countTagsByCategoryId(category.getId());
+        vo.setTagNum(tagNum);
+
+        return vo;
+    }
 }

+ 197 - 3
server/yusp-tagging-core/src/main/java/cn/com/yusys/yusp/service/impl/AitagTagInfoServiceImpl.java

@@ -1,8 +1,15 @@
 package cn.com.yusys.yusp.service.impl;
 
+import cn.com.yusys.yusp.commons.exception.BizException;
 import cn.com.yusys.yusp.commons.util.StringUtils;
 import cn.com.yusys.yusp.commons.util.date.DateUtils;
+import cn.com.yusys.yusp.config.FastApiConfig;
+import cn.com.yusys.yusp.domain.dto.TagImportDto;
+import cn.com.yusys.yusp.domain.entity.AitagTagCategory;
+import cn.com.yusys.yusp.domain.vo.GenerateRegexVo;
 import cn.com.yusys.yusp.domain.vo.VersionRollbackVo;
+import cn.com.yusys.yusp.domain.vo.fastapivo.AiTaggingResponseVo;
+import cn.com.yusys.yusp.mapper.AitagTagCategoryMapper;
 import cn.com.yusys.yusp.mapper.AitagTagInfoVersionDao;
 import cn.com.yusys.yusp.domain.dto.TagInfoDto;
 import cn.com.yusys.yusp.domain.entity.AitagTagInfoVersionEntity;
@@ -11,6 +18,9 @@ import cn.com.yusys.yusp.mapper.AitagTagInfoDao;
 import cn.com.yusys.yusp.domain.entity.AitagTagInfoEntity;
 import cn.com.yusys.yusp.domain.vo.AitagTagInfoQueryVo;
 import cn.com.yusys.yusp.service.AitagTagInfoService;
+import cn.com.yusys.yusp.service.TagImportListener;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.event.AnalysisEventListener;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -18,11 +28,22 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static cn.com.yusys.yusp.config.DataDictionary.*;
 
@@ -34,12 +55,19 @@ import static cn.com.yusys.yusp.config.DataDictionary.*;
  */
 
 @Service("aitagTagInfoService")
+@Slf4j
 public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagTagInfoEntity> implements AitagTagInfoService {
 
 
     @Autowired
     private AitagTagInfoVersionDao aitagTagInfoVersionDao;
 
+    @Autowired
+    private AitagTagCategoryMapper aiTagCategoryMapper;
+
+    @Autowired
+    private FastApiConfig fastApiConfig;
+
     /**
      * 分页查询
      *
@@ -113,10 +141,14 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
             aitagTagInfo.setLevel(1);
         }
         aitagTagInfo.setRevisionTime(DateUtils.getCurrDateTimeStr());
-        aitagTagInfo.setTagVersion("0.1");
+        aitagTagInfo.setTagVersion("1");
         aitagTagInfo.setIsDelete(TAG_UNDELETED);
         aitagTagInfo.setState(TAG_ENABLED);
         this.save(aitagTagInfo);
+        HashMap<String, Object> body = new HashMap<>();
+        String[] ids = {aitagTagInfo.getId()};
+        body.put("tag_ids",ids);
+        callAiTag(body,"/api/aitag/admin/v1/synchronize_tag");
     }
 
     /**
@@ -153,8 +185,13 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
         aitagTagInfoVersionEntity.setId(StringUtils.getUUID());
         this.aitagTagInfoVersionDao.insert(aitagTagInfoVersionEntity);
         aitagTagInfoEntity.setRevisionTime(DateUtils.getCurrDateTimeStr());
-        aitagTagInfoEntity.setTagVersion(Double.parseDouble(tagInfo.getTagVersion())+0.1+"");
+        aitagTagInfoEntity.setTagVersion(Integer.parseInt(tagInfo.getTagVersion())+1+"");
         this.baseMapper.updateById(aitagTagInfoEntity);
+
+        HashMap<String, Object> body = new HashMap<>();
+        String[] ids = {aitagTagInfoEntity.getId()};
+        body.put("tag_ids",ids);
+        callAiTag(body,"/api/aitag/admin/v1/synchronize_tag");
     }
 
     @Override
@@ -166,6 +203,9 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
             aitagTagInfoEntity.setIsDelete(TAG_DELETED);
             this.baseMapper.updateById(aitagTagInfoEntity);
         }
+        HashMap<String, Object> body = new HashMap<>();
+        body.put("tag_ids",list);
+        callAiTag(body,"/api/aitag/admin/v1/delete_tag");
     }
 
     @Override
@@ -188,6 +228,11 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
             AitagTagInfoVersionEntity aitagTagInfoVersionEntity = new AitagTagInfoVersionEntity();
             aitagTagInfoVersionEntity.setIsDelete(TAG_DELETED);
             this.aitagTagInfoVersionDao.update(aitagTagInfoVersionEntity,updateTagVersion);
+
+            HashMap<String, Object> body = new HashMap<>();
+            String[] ids = {aitagTagInfoEntity.getId()};
+            body.put("tag_ids",ids);
+            callAiTag(body,"/api/aitag/admin/v1/synchronize_tag");
         }
     }
 
@@ -234,6 +279,119 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
         return this.baseMapper.selectList(queryWrapper);
     }
 
+    @Override
+    public void batchImport(MultipartFile file, String reviser,String categoryId) throws IOException {
+        log.info("开始处理上传文件:{}", file.getOriginalFilename());
+
+        TagImportListener listener = new TagImportListener();
+        EasyExcel.read(file.getInputStream(), TagImportDto.class, listener)
+                .headRowNumber(1)
+                .sheet(1)
+                .doRead();
+        List<TagImportDto> tagImportDtos = listener.getDataList();
+        if (tagImportDtos.isEmpty()) {
+            throw BizException.of("E004");
+        }
+
+        Map<String, TagImportDto> nameToDtoMap  = new HashMap<>();
+        for (TagImportDto d : tagImportDtos) {
+            if (nameToDtoMap.containsKey(d.getTagNm())) {
+                throw BizException.of("E005",d.getTagNm());
+            }
+            nameToDtoMap.put(d.getTagNm(), d);
+        }
+
+        validateParentTags(nameToDtoMap);
+        resolveHierarchy(nameToDtoMap);
+        saveToDatabase(tagImportDtos,reviser,categoryId);
+
+        HashMap<String, Object> body = new HashMap<>();
+        List<String> tagIds = tagImportDtos.stream().map(TagImportDto::getId).collect(Collectors.toList());
+        body.put("tag_ids",tagIds);
+        callAiTag(body,"/api/aitag/admin/v1/synchronize_tag");
+    }
+
+    @Override
+    public String generateRegex(GenerateRegexVo regexVo) {
+        Map body = JSONObject.parseObject(JSONObject.toJSONString(regexVo), Map.class);
+        AiTaggingResponseVo taggingResponse = callAiTag(body, "/api/aitag/admin/v1/generate_reg");
+        if(StringUtils.equals(taggingResponse.getCode(),"200")){
+            return taggingResponse.getBody();
+        }
+        log.error("生成正则表达式异常:返回参数为:{}",JSON.toJSONString(taggingResponse));
+        throw BizException.of("E008");
+    }
+
+    private void saveToDatabase(List<TagImportDto> tagImportDtos,String reviser,String categoryId) {
+        AitagTagCategory aitagTagCategory = aiTagCategoryMapper.selectById(categoryId);
+        String categoryNm = aitagTagCategory.getCategoryNm();
+        for (TagImportDto tagImportDto: tagImportDtos){
+            AitagTagInfoEntity aitagTagInfo = JSONObject.parseObject(JSONObject.toJSONString(tagImportDto),
+                    AitagTagInfoEntity.class);
+            String tagPath = tagImportDto.getTagPath();
+            aitagTagInfo.setTagPath(categoryNm+"/"+tagPath);
+            aitagTagInfo.setLevel(aitagTagInfo.getTagPath().split("/").length);
+            aitagTagInfo.setRevisionTime(DateUtils.getCurrDateTimeStr());
+            aitagTagInfo.setReviser(reviser);
+            aitagTagInfo.setTagVersion("1");
+            aitagTagInfo.setIsDelete(TAG_UNDELETED);
+            aitagTagInfo.setState(TAG_ENABLED);
+            this.save(aitagTagInfo);
+        }
+
+    }
+
+    /**
+     * 校验父标签存在性并将赋值parentId
+     * @param nameToDtoMap
+     */
+    private void validateParentTags(Map<String, TagImportDto> nameToDtoMap) {
+        Set<String> validNames = nameToDtoMap.keySet();
+        for (TagImportDto d : nameToDtoMap.values()) {
+            if (!StringUtils.isBlank(d.getParentName())) {
+                if(!validNames.contains(d.getParentName())){
+                    throw BizException.of("E006",d.getTagNm(),d.getParentName());
+                }else{
+                    d.setParentId(nameToDtoMap.get(d.getParentName()).getId());
+                }
+
+            }
+        }
+    }
+
+
+    /**
+     * 构建path路径
+     * @param nameToDtoMap
+     */
+    private void resolveHierarchy(Map<String, TagImportDto> nameToDtoMap) {
+        for (TagImportDto current : nameToDtoMap.values()) {
+            current.setTagPath(buildFullPath(current, new HashSet<>(),nameToDtoMap));
+        }
+    }
+
+    private String buildFullPath(TagImportDto current, Set<String> visited,Map<String, TagImportDto> nameToDtoMap) {
+        if (current == null) {
+            return "";
+        }
+        if (visited.contains(current.getTagNm())) {
+            throw BizException.of("E007",  String.join("->", visited) + "->" + current.getTagNm());
+        }
+        visited.add(current.getTagNm());
+
+        StringBuilder path = new StringBuilder();
+        if (current.getParentName() != null && nameToDtoMap.containsKey(current.getParentName())) {
+            TagImportDto parent = nameToDtoMap.get(current.getParentName());
+            String parentPath = buildFullPath(parent, visited, nameToDtoMap);
+            if (!parentPath.isEmpty()) {
+                path.append(parentPath).append("/");
+            }
+        }
+        path.append(current.getTagNm());
+        visited.remove(current.getTagNm());
+        return path.toString();
+    }
+
     /**
      * 将AitagTagInfoEntity列表转换为树形结构
      * @param entities AitagTagInfoEntity列表
@@ -269,4 +427,40 @@ public class AitagTagInfoServiceImpl extends ServiceImpl<AitagTagInfoDao, AitagT
         }
         return rootNodes;
     }
-}
+
+    private AiTaggingResponseVo callAiTag(Map<String,Object> body, String path) {
+        String url = fastApiConfig.getUrl() + path;
+        log.info("调用AI打标接口: {}", url);
+
+        try (CloseableHttpClient httpClient = createHttpClient()) {
+            HttpPost httpPost = new HttpPost(url);
+            httpPost.setHeader("Content-Type", "application/json");
+            // 构造请求体
+            String requestBody = JSON.toJSONString(body);
+            httpPost.setEntity(new StringEntity(requestBody, "UTF-8"));
+
+            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+                String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
+                log.info("AI打标接口响应: {}", responseBody);
+                return JSON.parseObject(responseBody, AiTaggingResponseVo.class);
+            }
+        } catch (Exception e) {
+            log.error("调用AI打标接口失败", e);
+            throw BizException.of("E008");
+        }
+    }
+
+    /**
+     * 创建HTTP客户端
+     */
+    private CloseableHttpClient createHttpClient() {
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(fastApiConfig.getConnectTimeout())
+                .setSocketTimeout(fastApiConfig.getReadTimeout())
+                .build();
+        return HttpClients.custom()
+                .setDefaultRequestConfig(requestConfig)
+                .build();
+    }
+
+}

+ 5 - 0
server/yusp-tagging-core/src/main/resources/mapper/AitagTagCategoryMapper.xml

@@ -71,4 +71,9 @@
     <select id="selectCountEnabled" resultType="long">
         SELECT COUNT(*) FROM aitag_tag_category WHERE is_delete = 0 AND state = 0
     </select>
+
+    <!-- 根据ID查询标签体系详情 -->
+    <select id="selectDetailById" resultType="cn.com.yusys.yusp.domain.entity.AitagTagCategory">
+        SELECT * FROM aitag_tag_category WHERE id = #{id}
+    </select>
 </mapper>

+ 1 - 1
server/yusp-tagging-core/src/main/resources/mapper/AitagTagLogMapper.xml

@@ -24,7 +24,7 @@
     </resultMap>
 
 
-    <select id="selectTagCount" parameterType="cn.com.yusys.yusp.domain.vo.SmartTaggingResultVo">
+    <select id="selectTagCount" resultType="integer" parameterType="cn.com.yusys.yusp.domain.vo.SmartTaggingResultVo">
         SELECT
         COUNT(1) as totalCount
         FROM aitag_tag_log

+ 8 - 1
server/yusp-tagging-core/src/main/resources/messages/yusp_input_msg.properties

@@ -98,4 +98,11 @@ EXTENSION_FIELD_CANNOT_BE_EMPTY=\u6269\u5C55\u5B57\u6BB5\u4E0D\u80FD\u4E3A\u7A7A
 SUPPLEMENTAL_TABLE_CONFIG_NOT_EXIST=\u8865\u5F55\u8868\u914D\u7F6E\u4E0D\u5B58\u5728,\u8BF7\u786E\u8BA4\u540E\u518D\u64CD\u4F5C
 DATA_SOURCE_INFO_NOT_EXIST=\u5F53\u524D\u8868\u6570\u636E\u6E90\u4FE1\u606F\u4E0D\u5B58\u5728
 NO_DATA_PERIOD=\u8BE5\u7EDF\u8BA1\u5468\u671F\u6682\u672A\u5B9E\u73B0
-E001=\u6240\u5C5E\u5927\u7C7B\u4E0D\u80FD\u4E3A\u7A7A
+E001=\u6240\u5C5E\u5927\u7C7B\u4E0D\u80FD\u4E3A\u7A7A
+E002=\u4E0A\u4F20\u6587\u4EF6\u4E0D\u80FD\u4E3A\u7A7A
+E003=\u4EC5\u652F\u6301 .xlsx \u6216 .xls \u683C\u5F0F\u6587\u4EF6
+E004=Excel \u4E2D\u6CA1\u6709\u6709\u6548\u6570\u636E
+E005=\u53D1\u73B0\u91CD\u590D\u7684\u6807\u7B7E\u540D\u79F0:[{0}]
+E006=\u6821\u9A8C\u5931\u8D25\uFF1A\u6807\u7B7E [{0}] \u7684\u7236\u6807\u7B7E [{1}] \u4E0D\u5B58\u5728\u4E8E\u6587\u4EF6\u4E2D\u3002
+E007=\u68C0\u6D4B\u5230\u6807\u7B7E\u5C42\u7EA7\u73AF\u8DEF:{0}
+E008=\u8C03\u7528AI\u6253\u6807\u63A5\u53E3\u5931\u8D25

+ 0 - 19
server/yusp-tagging-starter/src/main/java/cn/com/yusys/yusp/detail/App.java

@@ -18,26 +18,7 @@ import java.net.URL;
 @EnableTransactionManagement
 public class App {
     public static void main(String[] args) {
-        // --- 新增诊断代码开始 ---
-        try {
-            // 尝试强制加载 Claims 类
-            Class.forName("io.jsonwebtoken.Claims");
-            System.out.println(">>> [DIAGNOSTIC] SUCCESS: io.jsonwebtoken.Claims is in classpath!");
 
-            // 打印该类来自哪个 Jar 包
-            String location = Class.forName("io.jsonwebtoken.Claims")
-                    .getProtectionDomain()
-                    .getCodeSource()
-                    .getLocation()
-                    .toString();
-            System.out.println(">>> [DIAGNOSTIC] Loaded from: " + location);
-
-        } catch (ClassNotFoundException e) {
-            System.err.println(">>> [DIAGNOSTIC] FATAL: io.jsonwebtoken.Claims NOT found in classpath!");
-            System.err.println(">>> [DIAGNOSTIC] Current Thread Context ClassLoader: " + Thread.currentThread().getContextClassLoader());
-            e.printStackTrace();
-        }
-        // --- 新增诊断代码结束 ---
 
         SpringApplication.run(App.class, args);
     }

+ 7 - 3
server/yusp-tagging-starter/src/main/resources/application.yml

@@ -18,10 +18,14 @@ spring:
         max-idle: 20 #连接池中的最大空闲连接 默认 8
   application:
     jackson:
-      date-format: yyyy-MM-dd HH:mm:ss #日期格式
+      date-format: yyyy-MM-dd HH:mm:ss  # 您已有的配置
+      time-zone: GMT+8                  # 添加时区配置
       serialization:
-        INDENT_OUTPUT: true #是否格式化输出
-      default-property-inclusion: non_null #null不进行序列化
+        write-dates-as-timestamps: false  # 确保日期以字符串形式序列化
+        INDENT_OUTPUT: true
+      deserialization:
+        fail-on-unknown-properties: false
+      default-property-inclusion: non_null
 #  datasource:
 #    driver-class-name: org.postgresql.Driver # PostgreSQL数据库连接驱动
 #    type: com.zaxxer.hikari.HikariDataSource # 数据库连接池类型