package com.supervision.police.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.TimeInterval; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itextpdf.text.DocumentException; import com.supervision.common.constant.EvidenceConstants; import com.supervision.common.constant.IndexRuleConstants; import com.supervision.minio.domain.MinioFile; import com.supervision.minio.service.MinioService; import com.supervision.police.domain.*; import com.supervision.police.dto.*; import com.supervision.police.mapper.CaseEvidenceMapper; import com.supervision.police.service.*; import com.supervision.police.vo.EvidenceDirectoryReqVO; import com.supervision.police.vo.VerifyEvidenceReqVO; import com.supervision.utils.UserUtil; import com.supervision.utils.WatermarkUtil; import com.supervision.utils.ZipFileUtil; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; @Slf4j @Service @RequiredArgsConstructor public class CaseEvidenceServiceImpl extends ServiceImpl implements CaseEvidenceService { private final EvidenceFileService evidenceFileService; private final ComDictionaryService comDictionaryService; private final CaseStatusManageService caseStatusManageService; private final FileOcrProcessService fileOcrProcessService; private final MinioService minioService; private final ModelCaseService modelCaseService; @Autowired private LLMExtractService llmExtractService; @Autowired private EvidenceDirectoryService evidenceDirectoryService; @Autowired private EvidenceCategoryService evidenceCategoryService; @Autowired private NotePromptService notePromptService; private final XxlJobService xxlJobService; private final CaseEvidencePropertyService caseEvidencePropertyService; @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String saveEvidence(CaseEvidenceDTO caseEvidenceDTO) { // 必填校验 caseEvidencePersistenceAssert(caseEvidenceDTO); // 保存证据信息 CaseEvidence caseEvidence = caseEvidenceDTO.toCaseEvidence(); super.save(caseEvidence); if (CollUtil.isNotEmpty(caseEvidence.getProperty())) { // 同时保存证据属性值 EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryService.listDirectoryTree(caseEvidence.getCaseId())); EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); caseEvidencePropertyService.saveEvidenceProperty(caseEvidence.getId(), directory.getCategoryId(), caseEvidence.getProperty()); } //保存文件关联信息 caseEvidenceDTO.getFileIdList().forEach(fileId -> { EvidenceFile evidenceFile = new EvidenceFile(); evidenceFile.setFileId(fileId); evidenceFile.setEvidenceId(caseEvidence.getId()); evidenceFileService.save(evidenceFile); }); caseStatusManageService.whenUpdateEvidence(caseEvidence.getCaseId()); return caseEvidence.getId(); } private void caseEvidencePersistenceAssert(CaseEvidenceDTO caseEvidenceDTO) { Assert.notEmpty(caseEvidenceDTO.getCaseId(), "案件id不能为空"); Assert.notEmpty(caseEvidenceDTO.getEvidenceName(), "证据名称不能为空"); Assert.notEmpty(caseEvidenceDTO.getEvidenceType(), "证据类型不能为空"); //Assert.notEmpty(caseEvidenceDTO.getProvider(),"证据提供人不能为空"); Assert.notEmpty(caseEvidenceDTO.getFileIdList(), "文件id不能为空"); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String updateEvidence(CaseEvidenceDTO caseEvidenceDTO) { Assert.notEmpty(caseEvidenceDTO.getId(), "证据id不能为空"); caseEvidencePersistenceAssert(caseEvidenceDTO); super.getOptById(caseEvidenceDTO.getId()).orElseThrow(() -> new IllegalArgumentException("证据信息不存在")); // 更新证据信息 CaseEvidence caseEvidence = caseEvidenceDTO.toCaseEvidence(); super.updateById(caseEvidence); // 更新证据属性 EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryService.listDirectoryTree(caseEvidence.getCaseId())); EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); if (null != directory && StrUtil.isNotEmpty(directory.getCategoryId())) { if (CollUtil.isNotEmpty(caseEvidence.getProperty())) { caseEvidencePropertyService.updateEvidenceProperty(caseEvidence.getId(), directory.getCategoryId(), caseEvidence.getProperty()); } else { caseEvidencePropertyService.deleteEvidenceProperty(caseEvidence.getId(), directory.getCategoryId()); } } // 更新文件关联信息 evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, caseEvidence.getId()).remove(); caseEvidenceDTO.getFileIdList().forEach(fileId -> { EvidenceFile evidenceFile = new EvidenceFile(); evidenceFile.setFileId(fileId); evidenceFile.setEvidenceId(caseEvidence.getId()); evidenceFileService.save(evidenceFile); }); caseStatusManageService.whenUpdateEvidence(caseEvidenceDTO.getCaseId()); return caseEvidenceDTO.getId(); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public boolean deleteEvidence(String evidenceId, String fileId) { CaseEvidence caseEvidence = super.getOptById(evidenceId).orElseThrow(() -> new IllegalArgumentException("证据信息不存在")); // 同步删除文件夹 String caseId = caseEvidence.getCaseId(); List evidenceDirectoryS = listDirectoryTree(caseId); deleteEvidence(evidenceId, fileId, evidenceDirectoryS, caseEvidence); return true; } private void deleteEvidence(String evidenceId, String fileId, List evidenceDirectoryS, CaseEvidence caseEvidence) { EvidenceDirectoryDTO directoryDTO = new EvidenceDirectoryDTO(evidenceDirectoryS); EvidenceDirectoryDTO directory = directoryDTO.findDirectory(caseEvidence.getDirectoryId()); if (directory.getLevel() != 3 || StrUtil.isEmpty(fileId)) { // 当前证据不属于三级目录下的证据,删除文件的同时也要清楚证据数据 boolean remove = super.lambdaUpdate().eq(CaseEvidence::getId, evidenceId).remove(); if (remove) { evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, evidenceId).remove(); evidenceDirectoryService.removeDirectoryIf(directory.getId(), () -> directory.getLevel() == 3); caseEvidencePropertyService.deleteEvidenceProperty(evidenceId, directory.getCategoryId()); caseStatusManageService.whenUpdateEvidence(caseEvidence.getCaseId()); } } else { evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, evidenceId) .eq(EvidenceFile::getFileId, fileId).remove(); } } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public boolean batchDeleteEvidence(List wrappers) { if (CollUtil.isEmpty(wrappers)) { return true; } List evidenceIds = wrappers.stream().map(EvidenceIdWrapper::getEvidenceId).toList(); List caseEvidenceList = super.listByIds(evidenceIds); String caseId = CollUtil.getFirst(caseEvidenceList).getCaseId(); List evidenceDirectoryS = listDirectoryTree(caseId); // 同步删除文件夹 Map caseEvidenceMap = caseEvidenceList.stream().collect(Collectors.toMap(CaseEvidence::getId, v -> v)); for (EvidenceIdWrapper evidenceIdWrapper : wrappers) { deleteEvidence(evidenceIdWrapper.getEvidenceId(), evidenceIdWrapper.getFileId(), evidenceDirectoryS, caseEvidenceMap.get(evidenceIdWrapper.getEvidenceId())); } return true; } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public List queryEvidenceList(String caseId) { return super.getBaseMapper().queryEvidenceList(caseId); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public List queryEvidenceList(String caseId, String batchNo) { List caseEvidenceDetailDTOS = queryEvidenceList(caseId); if (StrUtil.isNotEmpty(batchNo)) { for (CaseEvidenceDetailDTO evidenceDetail : caseEvidenceDetailDTOS) { List filter = evidenceDetail.getFileList().stream().filter(file -> StrUtil.equals(file.getBatchNo(), batchNo)).toList(); evidenceDetail.setFileList(filter); } } return caseEvidenceDetailDTOS; } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public IPage pageListEvidence(String caseId, String directoryId, String evidenceName, Integer pageNum, Integer pageSize) { Assert.notEmpty(caseId, "案件id不能为空"); List evidenceDirectoryDTOS = listDirectoryTree(caseId); EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryDTOS); EvidenceDirectoryDTO queryDirectory = rootDirectory.findDirectory(directoryId); IPage fileDTOIPage = pageListCaseEvidence(queryDirectory, caseId, directoryId, evidenceName, new Page<>(pageNum, pageSize)); if (fileDTOIPage.getTotal() == 0) { return PageDTO.of(pageNum, pageSize, 0); } // 查询文件信息 List evidenceIds = fileDTOIPage.getRecords().stream().map(EvidenceFileDTO::getEvidenceId).distinct().toList(); List fileInfoList = evidenceFileService.listFileInfo(evidenceIds); Map> evidenceFileMap = fileInfoList.stream().collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId)); List recordFileDTOS = fileOcrProcessService.queryFileList(fileInfoList.stream().map(EvidenceFileDTO::getFileId).toList()); // 转换分页结果 //查询字典 List evidenceTypeDic = comDictionaryService.lambdaQuery().eq(ComDictionary::getType, "evidence_type").list(); return fileDTOIPage.convert(caseEvidence -> { CaseEvidenceDetailDTO caseEvidenceDetailDTO = new CaseEvidenceDetailDTO(caseEvidence, evidenceFileMap.get(caseEvidence.getEvidenceId())); caseEvidenceDetailDTO.setEvidenceTypeDesc( comDictionaryService.getName(evidenceTypeDic, "evidence_type", caseEvidence.getEvidenceType())); caseEvidenceDetailDTO.setContentTypeValue(recordFileDTOS); EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); caseEvidenceDetailDTO.setEvidenceFormatValue(directory); if (null != queryDirectory && queryDirectory.getLevel() == 3 && StrUtil.isNotEmpty(caseEvidence.getFileName())) { caseEvidenceDetailDTO.setEvidenceName(caseEvidence.getFileName().split("\\.")[0]); } caseEvidenceDetailDTO.setDirectoryNamePath(StrUtil.join("/", rootDirectory.getDirectoryPath(caseEvidence.getDirectoryId()))); return caseEvidenceDetailDTO; }); } private IPage pageListCaseEvidence(EvidenceDirectoryDTO queryDirectory, String caseId, String directoryId, String evidenceName, Page page) { if (null == queryDirectory || queryDirectory.getLevel() != 3) { /*if (null != queryDirectory && CollUtil.isEmpty(queryDirectory.listAllFileId())){ return PageDTO.of(page.getCurrent(), page.getSize(), 0); }*/ List directoryIds = null == queryDirectory ? new ArrayList<>() : queryDirectory.listAllDirectory().stream().map(EvidenceDirectoryDTO::getId).toList(); // 全部 或者一级目录 或者 二级目录查询证据 return super.lambdaQuery().eq(CaseEvidence::getCaseId, caseId) .in(CollUtil.isNotEmpty(directoryIds), CaseEvidence::getDirectoryId, directoryIds) .like(StrUtil.isNotEmpty(evidenceName), CaseEvidence::getEvidenceName, evidenceName) .orderBy(true, false, CaseEvidence::getUpdateTime) .page(page).convert(EvidenceFileDTO::new); } else { // 三级目录查询证据文件 return evidenceFileService.pageListFileInfo( null, caseId, evidenceName, List.of(directoryId), Page.of(page.getCurrent(), page.getSize())); } } @Override public CaseEvidenceDetailDTO queryEvidenceDetail(String evidenceId) { return super.getBaseMapper().queryEvidenceDetail(evidenceId); } @Override public void evidenceAnalysis(String evidenceId) { log.info("证据解析开始。证据ID:【{}】", evidenceId); long start = System.currentTimeMillis(); LLMExtractDto llmExtractDto = new LLMExtractDto(); // 查出证据、文件、如果证据 CaseEvidence caseEvidence = getById(evidenceId); if (caseEvidence == null) { log.error("证据不存在"); return; } List evidenceFiles = evidenceFileService.listFileInfo(List.of(evidenceId)); if (evidenceFiles.isEmpty()) { log.error("证据id:【{}】不存在证据文件", evidenceId); return; } try { // 根据rank升序排序 evidenceFiles.sort(Comparator.comparing(EvidenceFileDTO::getRank)); log.info("OCR识别开始。证据文件ID:【{}】", evidenceFiles.stream().map(EvidenceFileDTO::getFileId).toList()); long ocrStart = System.currentTimeMillis(); List fileOcrProcesses = new ArrayList<>(); for (EvidenceFileDTO evidenceFile : evidenceFiles) { List fileOcrProcess = fileOcrProcessService.multipleTypeOcrProcess(List.of(evidenceFile.getFileId()), evidenceFile.getFileType()); fileOcrProcesses.addAll(fileOcrProcess); } log.info("OCR识别完成。更新证据处理状态为【OCR识别完成】。耗时:【{}】ms", System.currentTimeMillis() - ocrStart); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_OCR_OK); updateById(caseEvidence); // 遍历OCR结果拼接ocrText并赋值给lLMExtractDto的text StringBuilder ocrText = new StringBuilder(); fileOcrProcesses.forEach(fileOcrProcess -> { if (StrUtil.isNotEmpty(fileOcrProcess.getReviseText())) { ocrText.append(fileOcrProcess.getReviseText()); } else { ocrText.append(fileOcrProcess.getOcrText()); } }); llmExtractDto.setText(ocrText.toString()); log.info("标题提取开始。"); long titleStart = System.currentTimeMillis(); llmExtractDto = llmExtractService.extractTitle(Collections.singletonList(llmExtractDto)).get(0); log.info("标题提取完成。更新证据处理状态为【标题提取完成】。标题:【{}】。耗时:【{}】ms", llmExtractDto.getTitle(), System.currentTimeMillis() - titleStart); caseEvidence.setTitle(llmExtractDto.getTitle()); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_TITLE_EXTRACT_OK); updateById(caseEvidence); // 根据证据目录id查询提示词 EvidenceDirectory directory = evidenceDirectoryService.getById(caseEvidence.getDirectoryId()); NotePrompt notePrompt = notePromptService.lambdaQuery().eq(NotePrompt::getEvidenceCategoryId, directory.getCategoryId()).one(); if (notePrompt != null) { // 重新设置extractAttributes属性信息 List attributes = caseEvidencePropertyService.findExtractAttributes(directory.getCategoryId()); notePrompt.setExtractAttributes(attributes); log.info("属性提取开始。"); long attrStart = System.currentTimeMillis(); llmExtractDto.setPrompt(notePrompt.getPrompt()); llmExtractDto.setExtractAttributes(notePrompt.getExtractAttributes()); List llmExtractDtos = llmExtractService.extractAttribute(Collections.singletonList(llmExtractDto)); if (!llmExtractDtos.isEmpty()) { List extractAttributes = llmExtractDtos.get(0).getExtractAttributes() .stream().filter(Objects::nonNull).peek(extractAttribute -> { if (!checkExtractAttributes(extractAttribute)) { extractAttribute.setAttrValue(null); } }).toList(); caseEvidence.setProperty(extractAttributes); // 同时设置案件属性值 caseEvidencePropertyService.deleteEvidenceProperty(evidenceId, directory.getCategoryId()); caseEvidencePropertyService.saveEvidenceProperty(evidenceId, directory.getCategoryId(), extractAttributes); } log.info("属性提取完成。更新证据处理状态为【属性提取完成】。属性:【{}】。耗时:【{}】", caseEvidence.getProperty(), System.currentTimeMillis() - attrStart); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_ATTR_EXTRACT_OK); updateById(caseEvidence); } else { log.info("没有关联提示词,不提取属性"); } log.info("证据解析完成。更新证据处理状态为【处理成功】。"); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_SUCCESS); updateById(caseEvidence); } catch (Exception e) { log.error("证据:【{}】解析失败。更新证据处理状态为【处理失败】。", evidenceId, e); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_FAILED); updateById(caseEvidence); } finally { log.info("证据解析完成。证据ID:【{}】耗时:【{}】ms", evidenceId, System.currentTimeMillis() - start); } } /** * 校验属性值格式是否正确 * * @param extract 属性信息 * @return 校验结果 */ private boolean checkExtractAttributes(NotePromptExtractAttributesDto extract) { if (null == extract) { return false; } String attrValueType = extract.getAttrValueType(); if (StrUtil.equals(attrValueType, IndexRuleConstants.VALUE_TYPE_DATE)) { // 日期 try { new SimpleDateFormat("yyyy-MM-dd").parse(extract.getAttrValue()); return true; } catch (Exception e) { log.error("属性:{},日期:{}格式错误", extract.getAttrName(), extract.getAttrValue(), e); return false; } } if (StrUtil.equals(attrValueType, IndexRuleConstants.VALUE_TYPE_NUMBER)) { // 数字 return NumberUtil.isLong(extract.getAttrValue()) || NumberUtil.isDouble(extract.getAttrValue()); } return true; } @Override public void callEvidenceAnalysis(String evidenceId) { Assert.notEmpty(evidenceId, "证据ID不能为空"); xxlJobService.executeTaskByJobHandler("evidenceAnalysis", evidenceId); } @Override public List listCategoryTree(String caseType) { Assert.notEmpty(caseType, "案件类型不能为空!"); return evidenceCategoryService.listCategoryTree(caseType); } @Override public List listFileTree(String caseId) { return listFileTree(caseId, null); } @Override public List listFileTree(String caseId, String batchNo) { Assert.notEmpty(caseId, "案件ID不能为空!"); List evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId); evidenceDirectoryService.appendFile(evidenceDirectoryDTOS, evidenceFileService.queryFileInfoList(caseId, batchNo)); return evidenceDirectoryDTOS; } @Override public List listFileTree(String caseId, String batchNo, String evidenceId, String directoryId) { Assert.notEmpty(caseId, "案件ID不能为空!"); List evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId); evidenceDirectoryService.appendFile(evidenceDirectoryDTOS, evidenceFileService.queryFileInfoList(caseId, batchNo, evidenceId, directoryId)); return evidenceDirectoryDTOS; } @Override public List listDirectoryTree(String caseId) { Assert.notEmpty(caseId, "案件ID不能为空!"); List evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId); evidenceDirectoryService.appendEvidenceCount(evidenceDirectoryDTOS, super.lambdaQuery().eq(CaseEvidence::getCaseId, caseId).list()); return evidenceDirectoryDTOS; } @Override @Transactional(rollbackFor = Exception.class, transactionManager = "dataSourceTransactionManager") public void initCaseEvidenceDirectory(String caseId, String caseType) { List evidenceCategoryTree = evidenceCategoryService.listCategoryTree(caseType); List evidenceDirectoryTree = evidenceDirectoryService.listDirectoryTree(caseId); initCaseEvidenceDirectory(evidenceCategoryTree, evidenceDirectoryTree, caseId, null); } @Override public void refreshCaseEvidence() { log.info("开始初始化案件的证据目录。=========>>>>"); List list = modelCaseService.list(); List allEvidence = super.list(); List allFile = evidenceFileService.list(); Map catagroyMap = Map.of("1", "1",/*书证*/ "2", "3",/*物证*/ "3", "",/*供述*/ "4", "2",/*电子证据*/ "5", "4",/*鉴定意见*/ "6", "",/*证人证言*/ "7", "5",/*视听资料*/ "8", "6"/*勘验笔录*/); TimeInterval interval = DateUtil.timer(); interval.start(); int successCount = 0; int errorCount = 0; int index = 0; for (ModelCase modelCase : list) { interval.start(modelCase.getId()); log.info("开始初始化案件【{}】的目录。", modelCase.getCaseName()); try { ((CaseEvidenceService) AopContext.currentProxy()).doReplaceEvidence(modelCase, allEvidence, catagroyMap, allFile); successCount++; } catch (Exception e) { log.error("案件{}的目录初始化失败。案件id:{}", modelCase.getCaseName(), modelCase.getId(), e); errorCount++; } index += 1; log.info("案件【{}】的目录初始化完成。耗时:{}秒,占总体进度:{}%", modelCase.getCaseName(), interval.intervalSecond(modelCase.getId()), index / (list.size() * 1.0) * 100); } log.info("<<<<=======初始化案件的证据目录完成。案件总条数:{},总耗时:{}秒,成功个数:{},失败个数:{}", list.size(), interval.intervalSecond(), successCount, errorCount); } @Transactional(rollbackFor = Exception.class, transactionManager = "dataSourceTransactionManager", propagation = Propagation.REQUIRES_NEW) public void doReplaceEvidence(ModelCase modelCase, List allEvidence, Map catagroyMap, List allFile) { String caseType = modelCase.getCaseType(); String id = modelCase.getId(); // 开始初始化 initCaseEvidenceDirectory(id, caseType); EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(listDirectoryTree(id)); List evidenceList = allEvidence.stream().filter(ce -> StrUtil.equals(ce.getCaseId(), id)).toList(); log.info("案件{}证据总数:{}", modelCase.getCaseName(), evidenceList.size()); for (CaseEvidence caseEvidence : evidenceList) { String directoryId = caseEvidence.getDirectoryId(); if (StrUtil.isNotEmpty(directoryId)) { log.warn("证据id:{},证据名:{},已经存在目录id:{},不进行目录绑定操作", caseEvidence.getId(), caseEvidence.getEvidenceName(), directoryId); continue; } if (StrUtil.equalsAny(caseEvidence.getEvidenceType(), "3", "6")) { log.warn("证据id:{},证据名:{},证据类型为【{}】,清除无用数据", caseEvidence.getId(), caseEvidence.getEvidenceName(), caseEvidence.getEvidenceType()); super.removeById(caseEvidence.getId()); continue; } if (!catagroyMap.containsKey(caseEvidence.getEvidenceType())) { log.warn("证据id:{},证据名:{},证据类型为【{}】,没有对应的目录,请检查目录配置", caseEvidence.getId(), caseEvidence.getEvidenceName(), caseEvidence.getEvidenceType()); continue; } if (StrUtil.isEmpty(caseEvidence.getEvidenceType())) { log.warn("证据id:{},证据名:{},证据类型不能为空,默认为书证", caseEvidence.getId(), caseEvidence.getEvidenceName()); caseEvidence.setEvidenceType("1"); } EvidenceDirectoryDTO topDirectory = findTopDirectory(rootDirectory, catagroyMap.get(caseEvidence.getEvidenceType())); if (null == topDirectory) { log.warn("证据id:{},证据名:{},证据类型为【{}】,在根目录下没有对应的目录,请检查目录配置", caseEvidence.getId(), caseEvidence.getEvidenceName(), caseEvidence.getEvidenceType()); continue; } caseEvidence.setDirectoryId(topDirectory.getId()); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_SUCCESS); super.updateById(caseEvidence); List files = allFile.stream().filter(ef -> StrUtil.equals(ef.getEvidenceId(), caseEvidence.getId())).peek(ef -> ef.setDirectoryId(caseEvidence.getDirectoryId())).toList(); Map minioFileMap = minioService.listMinioFile(files.stream().map(EvidenceFile::getFileId).toList()).stream().collect(Collectors.toMap(MinioFile::getId, Function.identity())); for (EvidenceFile file : files) { evidenceFileService.updateById(file); MinioFile minioFile = minioFileMap.get(file.getFileId()); if (null == minioFile) { log.warn("证据id:{},证据名:{},文件id:{}不存在minio上传信息", caseEvidence.getId(), caseEvidence.getEvidenceName(), file.getFileId()); continue; } fileOcrProcessService.multipleTypeOcrProcess(List.of(file.getFileId()), minioFile.getFileType()); } } } private EvidenceDirectoryDTO findTopDirectory(EvidenceDirectoryDTO rootDirectory, String categoryId) { if (StrUtil.equals(rootDirectory.getCategoryId(), categoryId)) { return rootDirectory; } if (CollUtil.isNotEmpty(rootDirectory.getChild())) { for (EvidenceDirectoryDTO child : rootDirectory.getChild()) { EvidenceDirectoryDTO directory = findTopDirectory(child, categoryId); if (directory != null) { return directory; } } } return null; } @Override public Boolean updateDirectory(EvidenceDirectory evidenceDirectory) { Assert.notEmpty(evidenceDirectory.getId(), "目录ID不能为空!"); Assert.notEmpty(evidenceDirectory.getParentId(), "父级目录id不能为空"); return evidenceDirectoryService.lambdaUpdate() .set(EvidenceDirectory::getParentId, evidenceDirectory.getParentId()) .eq(EvidenceDirectory::getId, evidenceDirectory.getId()).update(); } @Override public Boolean moveFile(DirectoryFileDTO evidenceFileDTO) { Assert.notEmpty(evidenceFileDTO.getFileIdList(), "文件id不能为空"); Assert.notEmpty(evidenceFileDTO.getCaseId(), "案件id不能为空"); Assert.notEmpty(evidenceFileDTO.getDirectoryId(), "目录id不能为空"); return evidenceFileService.lambdaUpdate() .set(EvidenceFile::getDirectoryId, evidenceFileDTO.getDirectoryId()) .in(EvidenceFile::getFileId, evidenceFileDTO.getFileIdList()) .update(); } @Override public Boolean removeFile(DirectoryFileDTO evidenceFileDTO) { Assert.notEmpty(evidenceFileDTO.getFileIdList(), "文件id不能为空"); Assert.notEmpty(evidenceFileDTO.getCaseId(), "案件id不能为空"); return evidenceFileService.lambdaUpdate() .in(EvidenceFile::getFileId, evidenceFileDTO.getFileIdList()) .remove(); } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public Boolean removeDirectory(List directoryIdList) { if (CollUtil.isEmpty(directoryIdList)) { return false; } boolean success = evidenceDirectoryService.removeBatchByIds(directoryIdList); if (success) { // 删除目录,意味着证据也要被删除 super.lambdaUpdate().eq(CaseEvidence::getDirectoryId, directoryIdList).remove(); evidenceFileService.lambdaUpdate().in(EvidenceFile::getDirectoryId, directoryIdList).remove(); } return success; } /** * 提取证据信息 * 1. 只对证据文件进行新增操作,不删除已有的文件 * 2. 如果第三级目录下已经存在文件,只新增证据文件,对证据进行ocr识别但不对证据进行重新提取操作 * * @param caseId * @param evidenceFileDTOS 文件信息 */ @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String ocrAndExtract(String caseId, List evidenceFileDTOS) { List oldEvidences = this.queryEvidenceList(caseId); List oldEvidenceDirectoryDTOS = listFileTree(caseId); List newEvidences = toCaseCaseEvidenceDetailDTO(evidenceFileDTOS, oldEvidenceDirectoryDTOS); newEvidences.forEach(caseEvidenceDetailDTO -> caseEvidenceDetailDTO.setCaseId(caseId)); List operationalEvidenceList = findChangedEvidence(oldEvidences, newEvidences); String batchId = updateCaseEvidence(operationalEvidenceList); // 异步调用 ((CaseEvidenceService) AopContext.currentProxy()).syncEvidenceAnalysis(operationalEvidenceList); return batchId; } @Async public void syncEvidenceAnalysis(List evidenceList) { List ocrFileDTOList = evidenceList.stream().filter( // 当前证据下不是所有文件都是新增 evidenceDetail -> !evidenceDetail.getFileList().stream().allMatch(file -> StrUtil.equalsAny(file.getUpdateStatus(), "1", "-1")) ) .flatMap(evidenceDetailDTO -> evidenceDetailDTO.getFileList().stream().filter(file -> StrUtil.equals(file.getUpdateStatus(), "1"))).toList(); if (CollUtil.isNotEmpty(ocrFileDTOList)) { // 在已经存在的目录下追加文件,只需要重新及进行ocr识别 log.info("ocrAndExtract:开始只进行文件内容识别..."); Map> evidenceMap = ocrFileDTOList.stream().collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId)); for (Map.Entry> entry : evidenceMap.entrySet()) { String evidenceId = entry.getKey(); // 首先统一更新为正在处理 CaseEvidence one = this.lambdaQuery().eq(CaseEvidence::getId, evidenceId).one(); updateEvidenceAppendProcessingNewTransaction(evidenceId, one.getProcessStatus(), "1"); } for (Map.Entry> entry : evidenceMap.entrySet()) { String evidenceId = entry.getKey(); List value = entry.getValue(); for (EvidenceFileDTO evidenceFileDTO : value) { fileOcrProcessService.multipleTypeOcrProcess(List.of(evidenceFileDTO.getFileId()), evidenceFileDTO.getFileType()); } log.info("ocrAndExtract:证据:{} 文件内容识别完成", evidenceId); updateEvidenceAppendProcessingNewTransaction(evidenceId, EvidenceConstants.PROCESS_STATUS_SUCCESS, "0"); } } Set evidenceIds = evidenceList.stream().filter( // 当前证据下所有文件都是新增 evidenceDetail -> evidenceDetail.getFileList().stream().allMatch(file -> StrUtil.equalsAny(file.getUpdateStatus(), "1", "-1")) ) .flatMap(evidenceDetailDTO -> evidenceDetailDTO.getFileList().stream().filter(file -> StrUtil.equals(file.getUpdateStatus(), "1")) .map(EvidenceFileDTO::getEvidenceId)).collect(Collectors.toSet()); for (String evidenceId : evidenceIds) { // 文件目录下的所有文件都是新增的,需要重新提取分析 log.info("ocrAndExtract:证据:{} 进行证据分析操作....", evidenceId); xxlJobService.executeTaskByJobHandler("evidenceAnalysis", evidenceId); } } @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW) public void updateEvidenceAppendProcessingNewTransaction(String evidenceId, String status, String appendProcessing) { this.lambdaUpdate().eq(CaseEvidence::getId, evidenceId) .set(StrUtil.isNotEmpty(status), CaseEvidence::getProcessStatus, status) .set(CaseEvidence::getAppendProcessing, appendProcessing) .set(CaseEvidence::getUpdateTime, LocalDateTime.now()).update(); } /** * 更新案件证据信息 note:这个方法中的事务是一个新的事务,不会与之前的事务保持原子操作 * * @param caseEvidenceDetailDTOList 新旧证据信息 * @return */ @Override @Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class) public String updateCaseEvidence(List caseEvidenceDetailDTOList) { String batchNo = DateTime.now().toString("yyyyMMddHHmmss"); for (CaseEvidenceDetailDTO evidence : caseEvidenceDetailDTOList) { if (evidence.getUpdateStatus().equals("1")) { // 新增 CaseEvidence caseEvidence = evidence.toCaseEvidence(); caseEvidence.setProcessStatus(EvidenceConstants.PROCESS_STATUS_UNPROCESSED); this.save(caseEvidence); evidence.setId(caseEvidence.getId()); for (EvidenceFileDTO evidenceFileDTO : evidence.getFileList()) { if (StrUtil.equalsAny(evidenceFileDTO.getUpdateStatus(), "1", "2")) { evidenceFileDTO.setEvidenceId(caseEvidence.getId()); // 新增 EvidenceFile evidenceFile = new EvidenceFile(caseEvidence.getId(), evidenceFileDTO.getFileId()); evidenceFile.setDirectoryId(evidence.getDirectoryId()); evidenceFile.setRank(evidenceFileDTO.getRank()); evidenceFile.setBatchNo(batchNo); evidenceFile.setEvidenceId(caseEvidence.getId()); evidenceFileService.save(evidenceFile); }/*else if (evidenceFileDTO.getUpdateStatus().equals("0")){ // 删除 evidenceFileService.lambdaUpdate() .eq(EvidenceFile::getEvidenceId, evidenceFileDTO.getEvidenceId()) .eq(EvidenceFile::getFileId, evidenceFileDTO.getFileId()).remove(); }else if (evidenceFileDTO.getUpdateStatus().equals("2")){ evidenceFileService.lambdaUpdate() .set(EvidenceFile::getRank, evidenceFileDTO.getRank()) .update(); }*/ } } else if (evidence.getUpdateStatus().equals("-1")) { for (EvidenceFileDTO evidenceFileDTO : evidence.getFileList()) { evidenceFileDTO.setEvidenceId(evidence.getId()); if (StrUtil.equalsAny(evidenceFileDTO.getUpdateStatus(), "1", "2")) { // 新增 EvidenceFile evidenceFile = new EvidenceFile(evidence.getId(), evidenceFileDTO.getFileId()); evidenceFile.setDirectoryId(evidence.getDirectoryId()); evidenceFile.setRank(evidenceFileDTO.getRank()); evidenceFile.setBatchNo(batchNo); evidenceFile.setEvidenceId(evidence.getId()); evidenceFileService.save(evidenceFile); } } }/*else if (evidence.getUpdateStatus().equals("0")){ // 删除 this.removeById(evidence.getId()); evidenceFileService.lambdaUpdate().eq(EvidenceFile::getEvidenceId, evidence.getId()).remove(); }*/ } return batchNo; } @Override public List listOcrAndExtract(String caseId, String batchNo) { Assert.notEmpty(caseId, "案件id不能为空"); ModelCase modelCase = modelCaseService.getById(caseId); Assert.notNull(modelCase, "案件不存在"); List caseEvidenceDetailDTOS = this.queryEvidenceList(caseId, batchNo); if (CollUtil.isEmpty(caseEvidenceDetailDTOS)) { return new ArrayList<>(); } List processDTOList = caseEvidenceDetailDTOS.stream() .filter(evidenceDetail -> CollUtil.isNotEmpty(evidenceDetail.getFileList())) .map(EvidenceProcessDTO::new).collect(Collectors.toList()); List evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId); List categoryList = evidenceCategoryService.lambdaQuery().eq(EvidenceCategory::getCaseType, modelCase.getCaseType()).list(); for (EvidenceProcessDTO evidenceProcessDTO : processDTOList) { evidenceProcessDTO.setTemplateInfo(evidenceDirectoryDTOS, categoryList); evidenceProcessDTO.setEvidenceTypeName(categoryList); } return processDTOList; } @Override public void verifyEvidence(List evidenceVerifyDTOS, String caseId, String batchNo) { Assert.notEmpty(caseId, "案件id不能为空"); if (CollUtil.isEmpty(evidenceVerifyDTOS)) { return; } List caseEvidenceDetailDTOS = queryEvidenceList(caseId, null); List directoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId); EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(directoryDTOS); Map> evidenceMap = evidenceVerifyDTOS.stream().collect(Collectors.groupingBy(EvidenceVerifyDTO::getEvidenceId)); for (Map.Entry> entry : evidenceMap.entrySet()) { String evidenceId = entry.getKey(); List value = entry.getValue(); // 更新证据属性 和 核实状态 this.lambdaUpdate().eq(CaseEvidence::getId, evidenceId) .set(CaseEvidence::getProperty, JSONUtil.toJsonStr(CollUtil.getFirst(value).getProperties())) .set(CaseEvidence::getTitle, CollUtil.getFirst(value).getTitle()) .set(CaseEvidence::getProvider, CollUtil.getFirst(value).getProvider()) .set(CaseEvidence::getProcessStatus, EvidenceConstants.PROCESS_STATUS_VERIFIED)// 设置状态为已核实 .set(CaseEvidence::getEvidenceName, CollUtil.getFirst(value).getEvidenceName()) .update(); // 同时更新证据属性值 String categoryId = rootDirectory.findDirectory(CollUtil.getFirst(value).getDirectoryId()).getCategoryId(); Map> map = caseEvidencePropertyService.listEvidenceProperty(categoryId, Collections.singletonList(evidenceId)); if (CollUtil.isEmpty(map.get(categoryId))) { caseEvidencePropertyService.saveEvidenceProperty(evidenceId, categoryId, CollUtil.getFirst(value).getProperties()); } else { caseEvidencePropertyService.updateEvidenceProperty(evidenceId, categoryId, CollUtil.getFirst(value).getProperties()); } // 修改ocr内容 for (EvidenceVerifyDTO verifyDTO : value) { if (StrUtil.isNotEmpty(verifyDTO.getOcrText())) { fileOcrProcessService.lambdaUpdate() .eq(FileOcrProcess::getFileId, verifyDTO.getFileId()) .set(FileOcrProcess::getReviseText, verifyDTO.getOcrText()).update(); } } // 调整顺序 CaseEvidenceDetailDTO evidenceDetail = findEvidenceDetail(evidenceId, caseEvidenceDetailDTOS); if (evidenceDetail != null) { List fileList = evidenceDetail.getFileList(); int initOrder = 0; if (StrUtil.isNotEmpty(batchNo) && !CollUtil.isNotEmpty(fileList)) { // 如果批次不为空,则只对当前批次的文件进行排序 initOrder = fileList.size(); } List list = value.stream().map(EvidenceVerifyDTO::getFileId).toList(); for (EvidenceFileDTO evidenceFileDTO : evidenceDetail.getFileList()) { evidenceFileDTO.setRank(initOrder + findRank(list, evidenceFileDTO.getFileId())); evidenceFileService.lambdaUpdate().eq(EvidenceFile::getFileId, evidenceFileDTO.getFileId()) .eq(EvidenceFile::getEvidenceId, evidenceId) .set(EvidenceFile::getRank, evidenceFileDTO.getRank()).update(); } } } } @Override public void verifyEvidence(VerifyEvidenceReqVO verifyEvidenceReqVO) { List evidenceDirectoryList = verifyEvidenceReqVO.getEvidenceDirectoryList(); if (CollUtil.isEmpty(evidenceDirectoryList)) { return; } // 重新把外层的信息设置到证据文件对象中 verifyEvidenceReqVO.getEvidenceDirectoryList().forEach(EvidenceDirectoryDTO::replaceEvidence); List evidenceVerifyDTOS = evidenceDirectoryList.stream() .flatMap(evidenceDirectoryDTO -> evidenceDirectoryDTO.listAllFile().stream()) .map(fileDTO -> { EvidenceVerifyDTO evidenceVerifyDTO = new EvidenceVerifyDTO(); evidenceVerifyDTO.setEvidenceId(fileDTO.getEvidenceId()); evidenceVerifyDTO.setFileId(fileDTO.getFileId()); evidenceVerifyDTO.setOcrText(fileDTO.getOcrText()); CaseEvidenceDTO evidenceInfo = fileDTO.getEvidenceInfo(); evidenceVerifyDTO.setDirectoryId(fileDTO.getDirectoryId()); if (null != evidenceInfo) { evidenceVerifyDTO.setProperties(evidenceInfo.getProperty()); evidenceVerifyDTO.setTitle(evidenceInfo.getTitle()); evidenceVerifyDTO.setProvider(evidenceInfo.getProvider()); evidenceVerifyDTO.setEvidenceName(evidenceInfo.getEvidenceName()); } return evidenceVerifyDTO; }).toList(); this.verifyEvidence(evidenceVerifyDTOS, verifyEvidenceReqVO.getCaseId(), verifyEvidenceReqVO.getBatchNo()); } @Override public List evidenceDetails(String caseId, String batchNo, String evidenceId) { List evidenceDirectoryDTOS = listFileTree(caseId, batchNo, evidenceId, null); List caseEvidenceList = this.lambdaQuery().eq(CaseEvidence::getCaseId, caseId).list(); this.redoExtractAttributes(caseId, caseEvidenceList); EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryDTOS); // 强行翻译 rebuildEvidenceProperties(rootDirectory, caseEvidenceList); List categoryPromptDTOS = evidenceDirectoryService.listCategoryPrompt(caseId); Map caseEvidenceMap = caseEvidenceList.stream().map(CaseEvidenceDTO::new).peek(e -> e.setDirectoryNamePathValue(rootDirectory)).collect(Collectors.toMap(CaseEvidenceDTO::getId, Function.identity())); Map categoryPromptMap = categoryPromptDTOS.stream().collect(Collectors.toMap(CategoryPromptDTO::getDirectoryId, k -> k, (v1, v2) -> v1)); Iterator iterator = evidenceDirectoryDTOS.iterator(); while (iterator.hasNext()) { EvidenceDirectoryDTO evidenceDirectoryDTO = iterator.next(); evidenceDirectoryDTO.setFileEvidence(caseEvidenceMap, categoryPromptMap); evidenceDirectoryDTO.removeEmptyDirectory(); List fileInfoList = evidenceDirectoryDTO.getFileInfoList(); if (CollUtil.isEmpty(evidenceDirectoryDTO.getChild()) && CollUtil.isEmpty(fileInfoList)) { // 移除自身 iterator.remove(); } } return evidenceDirectoryDTOS; } public void redoExtractAttributes(String caseId, List caseEvidences) { EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryService.listDirectoryTree(caseId)); Map> categoryMapEvidence = new HashMap<>(); for (CaseEvidence caseEvidence : caseEvidences) { EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); if (null != directory && StrUtil.isNotEmpty(directory.getCategoryId())) { List evidenceIds = categoryMapEvidence.getOrDefault(directory.getCategoryId(), new ArrayList<>()); evidenceIds.add(caseEvidence.getId()); categoryMapEvidence.put(directory.getCategoryId(), evidenceIds); } } Map> map = new HashMap<>(); for (Map.Entry> entry : categoryMapEvidence.entrySet()) { map.putAll(caseEvidencePropertyService.listEvidenceProperty(entry.getKey(), entry.getValue())); } for (CaseEvidence caseEvidence : caseEvidences) { List attributesDtos = map.get(caseEvidence.getId()); // 兼容老数据 if (CollUtil.isNotEmpty(attributesDtos)) { caseEvidence.setProperty(attributesDtos); } } } @Override public void downloadEvidence(String evidenceId, HttpServletResponse response) throws IOException, DocumentException { List evidenceFileDTOList = evidenceFileService.listFileInfo(List.of(evidenceId)); Map fileInputStreamMap = new HashMap<>(); for (EvidenceFileDTO evidenceFileDTO : evidenceFileDTOList) { MinioFile minioFile = minioService.getMinioFile(evidenceFileDTO.getFileId()); if (null != minioFile) { if (StrUtil.equalsAnyIgnoreCase(minioFile.getFileType(), "pdf")) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); WatermarkUtil.pdfByText(minioService.getObjectInputStream(minioFile), bos, UserUtil.getUser().getUserName(), Map.of()); fileInputStreamMap.put(minioFile.getFilename(), new ByteArrayInputStream(bos.toByteArray())); } else if (StrUtil.equalsAnyIgnoreCase(minioFile.getFileType(), "jpg", "png", "jpeg", "bmp")) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); WatermarkUtil.imageByText(UserUtil.getUser().getUserName(), minioService.getObjectInputStream(minioFile), bos, Map.of("formatName", minioFile.getFileType())); fileInputStreamMap.put(minioFile.getFilename(), new ByteArrayInputStream(bos.toByteArray())); } else { fileInputStreamMap.put(minioFile.getFilename(), minioService.getObjectInputStream(minioFile)); } } } try { ZipFileUtil.createZipAndDownload(response, getById(evidenceId).getEvidenceName(), fileInputStreamMap); } catch (IOException e) { log.error("下载证据文件失败", e); } } /** * 重新构建证据属性数据 * * @param rootDirectory 根目录 * @param caseEvidenceList 案件证据列表 */ private void rebuildEvidenceProperties(EvidenceDirectoryDTO rootDirectory, List caseEvidenceList) { Map directoryIdMapCategoryId = caseEvidenceList.stream() .filter(e -> StrUtil.isNotEmpty(e.getDirectoryId()) && null != rootDirectory.findDirectory(e.getDirectoryId())) .map(CaseEvidence::getDirectoryId).distinct().collect( Collectors.toMap(directoryId -> directoryId, di -> rootDirectory.findDirectory(di).getCategoryId())); Map> categoryIdMapExtractAttributes = new HashMap<>(); for (CaseEvidence caseEvidence : caseEvidenceList) { EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId()); if (null == directory || StrUtil.isEmpty(directory.getCategoryId())) { continue; } String categoryId = directory.getCategoryId(); if (!categoryIdMapExtractAttributes.containsKey(categoryId)) { categoryIdMapExtractAttributes.put(categoryId, caseEvidencePropertyService.findExtractAttributes(categoryId)); } } for (CaseEvidence caseEvidence : caseEvidenceList) { if (StrUtil.isEmpty(caseEvidence.getDirectoryId())) { continue; } String categoryId = directoryIdMapCategoryId.get(caseEvidence.getDirectoryId()); if (StrUtil.isEmpty(categoryId)) { continue; } List merged = mergeExtractAttributes(caseEvidence.getProperty(), categoryIdMapExtractAttributes.get(categoryId)); if (null != merged) { merged = merged.stream().filter(Objects::nonNull).peek(e -> { if (!checkExtractAttributes(e)) { e.setAttrValue(null); } }).toList(); } caseEvidence.setProperty(merged); } } private List mergeExtractAttributes(List property, List attributesTemplates) { if (CollUtil.isEmpty(attributesTemplates) || CollUtil.isEmpty(property)) { return attributesTemplates; } for (NotePromptExtractAttributesDto attributesTemplate : attributesTemplates) { String attrName = attributesTemplate.getAttrName(); for (NotePromptExtractAttributesDto attributesDto : property) { if (StrUtil.equals(attributesDto.getAttrName(), attrName)) { attributesTemplate.setAttrValue(attributesDto.getAttrValue()); break; } } } return attributesTemplates; } @Override public String generateDirectoryName(String caseId, String categoryId, String provider) { Assert.notEmpty(caseId, "案件id不能为空"); Assert.notEmpty(categoryId, "目录id不能为空"); Assert.notEmpty(provider, "提供方不能为空"); EvidenceCategory category = evidenceCategoryService.getById(categoryId); Assert.notNull(category, "目录不存在"); List directoryList = evidenceDirectoryService.lambdaQuery() .eq(EvidenceDirectory::getCaseId, caseId) .eq(EvidenceDirectory::getCategoryId, categoryId).list(); String directoryName = category.getCategoryName() + provider; long count = directoryList.stream().filter(d -> StrUtil.contains(d.getDirectoryName(), provider)).count(); if (count > 0) { directoryName = directoryName + count; } return directoryName; } @Override public EvidenceDirectory createDirectory(EvidenceDirectoryReqVO evidenceDirectory) { List evidenceDirectoryDTOS = listDirectoryTree(evidenceDirectory.getCaseId()); List directoryIdList = null; for (EvidenceDirectoryDTO evidenceDirectoryDTO : evidenceDirectoryDTOS) { directoryIdList = evidenceDirectoryDTO.findDirectoryIdList(evidenceDirectory.getCategoryId()); if (CollUtil.isNotEmpty(directoryIdList)) { break; } } Assert.notEmpty(directoryIdList, "目录分类不存在"); EvidenceDirectoryDTO parentDirectory = null; for (EvidenceDirectoryDTO evidenceDirectoryDTO : evidenceDirectoryDTOS) { parentDirectory = evidenceDirectoryDTO.findDirectory(CollUtil.getFirst(directoryIdList)); if (null != parentDirectory) { break; } } Assert.notNull(parentDirectory, "目录不存在"); long count = evidenceDirectoryService.lambdaQuery().eq(EvidenceDirectory::getParentId, parentDirectory.getId()) .list().stream() .filter(d -> StrUtil.contains(d.getDirectoryName(), evidenceDirectory.getDirectoryName())).count(); if (count > 0) { evidenceDirectory.setDirectoryName(evidenceDirectory.getDirectoryName() + (count + 1)); } // 创建目录 EvidenceDirectory directory = new EvidenceDirectory(); directory.setCaseId(evidenceDirectory.getCaseId()); directory.setCategoryId(evidenceDirectory.getCategoryId()); directory.setDirectoryName(evidenceDirectory.getDirectoryName()); directory.setParentId(parentDirectory.getId()); evidenceDirectoryService.save(directory); // 目录创建完成,创建证据 CaseEvidence caseEvidence = new CaseEvidence(); caseEvidence.setEvidenceName(evidenceDirectory.getDirectoryName()); caseEvidence.setEvidenceType(directory.getCategoryId()); caseEvidence.setCaseId(evidenceDirectory.getCaseId()); caseEvidence.setDirectoryId(directory.getId()); caseEvidence.setProvider(evidenceDirectory.getProvider()); this.save(caseEvidence); return directory; } private CaseEvidenceDetailDTO findEvidenceDetail(String evidenceId, List caseEvidenceDetailDTOS) { for (CaseEvidenceDetailDTO caseEvidenceDetailDTO : caseEvidenceDetailDTOS) { if (StrUtil.equals(caseEvidenceDetailDTO.getId(), evidenceId)) { return caseEvidenceDetailDTO; } } return null; } private List toCaseCaseEvidenceDetailDTO(List newDirectoryDTOS, List oldEvidenceDirectoryDTOS) { if (CollUtil.isEmpty(newDirectoryDTOS)) { return new ArrayList<>(); } EvidenceDirectoryDTO oldRootDirectory = new EvidenceDirectoryDTO(oldEvidenceDirectoryDTOS); List fileIdList = newDirectoryDTOS.stream().flatMap(directoryDTO -> directoryDTO.listAllFileId().stream()).toList(); Map fileMap = minioService.listMinioFile(fileIdList).stream() .collect(Collectors.toMap(MinioFile::getId, Function.identity())); List floatNewDirectoryDTOS = newDirectoryDTOS.stream().flatMap(directoryDTO -> directoryDTO.listAllDirectory().stream()).toList(); List caseEvidenceDetailDTOS = new ArrayList<>(); for (EvidenceDirectoryDTO evidenceFile : floatNewDirectoryDTOS) { String directoryId = evidenceFile.getId(); EvidenceDirectoryDTO directory = oldRootDirectory.findDirectory(directoryId); if (null == directory) { log.warn("toCaseCaseEvidenceDetailDTO:目录id:{}不存在对应的目录分类信息", directoryId); continue; } if (directory.getLevel() == 1 || directory.getLevel() == 2) { for (String fileId : evidenceFile.getFileIdList()) { CaseEvidenceDetailDTO caseEvidenceDetailDTO = new CaseEvidenceDetailDTO(); // 预先生成证据id caseEvidenceDetailDTO.setId(DefaultIdentifierGenerator.getInstance().nextId(null).toString()); caseEvidenceDetailDTO.setEvidenceType(directory.getCategoryId()); caseEvidenceDetailDTO.setDirectoryId(directoryId); caseEvidenceDetailDTO.setDirectoryLevel(directory.getLevel()); EvidenceFileDTO evidenceFileDTO = new EvidenceFileDTO(); evidenceFileDTO.setFileId(fileId); evidenceFileDTO.setProcessStatus(EvidenceConstants.PROCESS_STATUS_UNPROCESSED); MinioFile minioFile = fileMap.get(fileId); if (null != minioFile) { // 证据名为文件名 caseEvidenceDetailDTO.setEvidenceName(minioFile.getFilename().split("\\.")[0]); evidenceFileDTO.setFileType(minioFile.getFileType()); evidenceFileDTO.setFileName(minioFile.getFilename()); evidenceFileDTO.setEvidenceId(caseEvidenceDetailDTO.getId()); } caseEvidenceDetailDTO.setFileList(List.of(evidenceFileDTO)); caseEvidenceDetailDTOS.add(caseEvidenceDetailDTO); } } if (directory.getLevel() == 3) { // 不会存在需要创建目录的场景 CaseEvidence caseEvidence = super.lambdaQuery().eq(CaseEvidence::getDirectoryId, directory.getId()).one(); CaseEvidenceDetailDTO caseEvidenceDetailDTO = new CaseEvidenceDetailDTO(); if (null != caseEvidence) { caseEvidenceDetailDTO.setId(caseEvidence.getId()); } // 证据名为目录名 caseEvidenceDetailDTO.setEvidenceName(evidenceFile.getDirectoryName()); caseEvidenceDetailDTO.setEvidenceType(directory.getCategoryId()); caseEvidenceDetailDTO.setDirectoryId(directoryId); caseEvidenceDetailDTO.setDirectoryLevel(directory.getLevel()); List evidenceFileDTOS = new ArrayList<>(); for (String fileId : evidenceFile.getFileIdList()) { EvidenceFileDTO evidenceFileDTO = new EvidenceFileDTO(); evidenceFileDTO.setFileId(fileId); evidenceFileDTO.setEvidenceId(caseEvidenceDetailDTO.getId()); MinioFile minioFile = fileMap.get(fileId); if (null != minioFile) { evidenceFileDTO.setFileName(minioFile.getFilename()); evidenceFileDTO.setFileType(minioFile.getFileType()); } evidenceFileDTOS.add(evidenceFileDTO); } caseEvidenceDetailDTO.setFileList(evidenceFileDTOS); caseEvidenceDetailDTOS.add(caseEvidenceDetailDTO); } } return caseEvidenceDetailDTOS; } /** * 查找发生改变的证据 * * @param oldEvidenceList 旧证据列表 * @param newEvidenceList 新证据列表 * @return 发生改变的证据 */ private List findChangedEvidence(List oldEvidenceList, List newEvidenceList) { List caseEvidence2DTOList = new ArrayList<>(); if (CollUtil.isEmpty(oldEvidenceList) && CollUtil.isNotEmpty(newEvidenceList)) { // 数据库中不存在数据,则全部新增 for (CaseEvidenceDetailDTO evidenceDetailDTO : newEvidenceList) { List fileIds = evidenceDetailDTO.getFileList().stream().map(EvidenceFileDTO::getFileId).toList(); evidenceDetailDTO.setUpdateStatus("1"); for (EvidenceFileDTO evidenceFileDTO : evidenceDetailDTO.getFileList()) { evidenceFileDTO.setUpdateStatus("1"); evidenceFileDTO.setRank(findRank(fileIds, evidenceFileDTO.getFileId())); } } caseEvidence2DTOList.addAll(newEvidenceList); } if (CollUtil.isNotEmpty(oldEvidenceList) && CollUtil.isEmpty(newEvidenceList)) { // 数据库中存在数据,没有新增数据 for (CaseEvidenceDetailDTO evidenceDetailDTO : oldEvidenceList) { evidenceDetailDTO.setUpdateStatus("0"); for (EvidenceFileDTO evidenceFileDTO : evidenceDetailDTO.getFileList()) { evidenceFileDTO.setUpdateStatus("0"); } } caseEvidence2DTOList.addAll(oldEvidenceList); } if (CollUtil.isNotEmpty(oldEvidenceList) && CollUtil.isNotEmpty(newEvidenceList)) { // 数据库中和新数据都存在 Map> evidenceFileCache = Stream.of(newEvidenceList, oldEvidenceList) .flatMap(Collection::stream) .flatMap(evidenceDetailDTO -> evidenceDetailDTO.getFileList().stream()) .collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId, Collectors.toMap(EvidenceFileDTO::getFileId, Function.identity()))); for (CaseEvidenceDetailDTO oldEvidence : oldEvidenceList) { boolean isFind = false; for (CaseEvidenceDetailDTO newEvidence : newEvidenceList) { Map fileCache = evidenceFileCache.get(newEvidence.getId()); if (StrUtil.equals(oldEvidence.getId(), newEvidence.getId())) { isFind = true; oldEvidence.setUpdateStatus("-1"); List oldFileIds = oldEvidence.getFileList().stream().map(EvidenceFileDTO::getFileId).toList(); List newFileIds = newEvidence.getFileList().stream().map(EvidenceFileDTO::getFileId).toList(); TupleIdRecord tupleIdRecord = compareFileList(newFileIds, oldFileIds); List updateFileList = new ArrayList<>(); // 新增的文件顺序排在原有文件的后面 int initOrder = oldFileIds.size(); for (String addFileId : tupleIdRecord.addFileList) { EvidenceFileDTO evidenceFileDTO = new EvidenceFileDTO(); evidenceFileDTO.setFileId(addFileId); evidenceFileDTO.setUpdateStatus("1"); if (null != fileCache.get(addFileId)) { evidenceFileDTO.setFileType(fileCache.get(addFileId).getFileType()); } evidenceFileDTO.setRank(initOrder + findRank(newFileIds, addFileId)); updateFileList.add(evidenceFileDTO); } for (String deleteFileId : tupleIdRecord.deleteFileList) { EvidenceFileDTO evidenceFileDTO = new EvidenceFileDTO(); evidenceFileDTO.setFileId(deleteFileId); evidenceFileDTO.setUpdateStatus("0"); if (null != fileCache.get(deleteFileId)) { evidenceFileDTO.setFileType(fileCache.get(deleteFileId).getFileType()); } evidenceFileDTO.setRank(findRank(oldFileIds, deleteFileId)); updateFileList.add(evidenceFileDTO); } for (String updateFileId : tupleIdRecord.updateFileList) { EvidenceFileDTO evidenceFileDTO = new EvidenceFileDTO(); evidenceFileDTO.setFileId(updateFileId); evidenceFileDTO.setUpdateStatus("2"); if (null != fileCache.get(updateFileId)) { evidenceFileDTO.setFileType(fileCache.get(updateFileId).getFileType()); } evidenceFileDTO.setRank(findRank(oldFileIds, updateFileId)); updateFileList.add(evidenceFileDTO); } newEvidence.setFileList(updateFileList); caseEvidence2DTOList.add(newEvidence); } } if (!isFind) { oldEvidence.setUpdateStatus("0"); caseEvidence2DTOList.add(oldEvidence); } } for (CaseEvidenceDetailDTO newEvidence : newEvidenceList) { if (StrUtil.isEmpty(newEvidence.getId()) || oldEvidenceList.stream().noneMatch(i -> StrUtil.equals(i.getId(), newEvidence.getId()))) { newEvidence.setUpdateStatus("1"); List newFileIds = newEvidence.getFileList().stream().map(EvidenceFileDTO::getFileId).toList(); for (EvidenceFileDTO evidenceFileDTO : newEvidence.getFileList()) { evidenceFileDTO.setUpdateStatus("1"); evidenceFileDTO.setRank(findRank(newFileIds, evidenceFileDTO.getFileId())); } caseEvidence2DTOList.add(newEvidence); } } } return caseEvidence2DTOList; } private int findRank(List newFileIds, String fileId) { for (int i = 0; i < newFileIds.size(); i++) { if (newFileIds.get(i).equals(fileId)) { return i; } } return -1; } /** * 初始化案件证据目录 * * @param evidenceCategoryTree 证据分类 * @param caseId 案件id * @param evidenceDirectoryTree 父级目录id */ /** * 初始化案件证据目录 * * @param evidenceCategoryTree 证据分类树 * @param evidenceDirectoryTree 父级目录树 * @param caseId 案件id * @param parentId 父目录id */ private void initCaseEvidenceDirectory(List evidenceCategoryTree, List evidenceDirectoryTree, String caseId, String parentId) { if (null == evidenceDirectoryTree) { evidenceDirectoryTree = new ArrayList<>(1); } for (EvidenceCategoryDTO evidenceCategoryDTO : evidenceCategoryTree) { List directoryDTOS = evidenceDirectoryTree.stream().filter(evidenceDirectoryDTO -> evidenceDirectoryDTO.getCategoryId().equals(evidenceCategoryDTO.getId())).toList(); if (CollUtil.isEmpty(directoryDTOS)) { EvidenceDirectory evidenceDirectory = new EvidenceDirectory(); evidenceDirectory.setCaseId(caseId); evidenceDirectory.setDirectoryName(evidenceCategoryDTO.getCategoryName()); evidenceDirectory.setCategoryId(evidenceCategoryDTO.getId()); evidenceDirectory.setParentId(parentId); evidenceDirectoryService.save(evidenceDirectory); EvidenceDirectoryDTO directoryDTO = new EvidenceDirectoryDTO(evidenceDirectory); evidenceDirectoryTree.add(directoryDTO); directoryDTOS = List.of(directoryDTO); } EvidenceDirectoryDTO parentDTO = CollUtil.getFirst(directoryDTOS); if (CollUtil.isNotEmpty(evidenceCategoryDTO.getChild())) { initCaseEvidenceDirectory(evidenceCategoryDTO.getChild(), parentDTO.getChild(), caseId, parentDTO.getId()); } } } /** * left 新增 right 删除 * * @param newFileIdList * @param oldFileIdList * @return */ private TupleIdRecord compareFileList(List newFileIdList, List oldFileIdList) { List addFileList = new ArrayList<>(); List deleteFileList = new ArrayList<>(); List updateFileList = new ArrayList<>(); if (CollUtil.isEmpty(oldFileIdList) && CollUtil.isNotEmpty(newFileIdList)) { addFileList = newFileIdList; } if (CollUtil.isNotEmpty(oldFileIdList) && CollUtil.isEmpty(newFileIdList)) { deleteFileList = oldFileIdList; } if (CollUtil.isNotEmpty(oldFileIdList) && CollUtil.isNotEmpty(newFileIdList)) { deleteFileList = oldFileIdList.stream().filter(fileId -> !newFileIdList.contains(fileId)).collect(Collectors.toList()); addFileList = newFileIdList.stream().filter(fileId -> !oldFileIdList.contains(fileId)).collect(Collectors.toList()); updateFileList = oldFileIdList.stream().filter(newFileIdList::contains).collect(Collectors.toList()); } return new TupleIdRecord(addFileList, updateFileList, deleteFileList); } record TupleIdRecord(List addFileList, List updateFileList, List deleteFileList) { } }