You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
fu-hsi-service/src/main/java/com/supervision/police/service/impl/CaseEvidenceServiceImpl.java

1422 lines
73 KiB
Java

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<CaseEvidenceMapper, CaseEvidence> 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<EvidenceDirectoryDTO> evidenceDirectoryS = listDirectoryTree(caseId);
deleteEvidence(evidenceId, fileId, evidenceDirectoryS, caseEvidence);
return true;
}
private void deleteEvidence(String evidenceId, String fileId,
List<EvidenceDirectoryDTO> 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<EvidenceIdWrapper> wrappers) {
if (CollUtil.isEmpty(wrappers)) {
return true;
}
List<String> evidenceIds = wrappers.stream().map(EvidenceIdWrapper::getEvidenceId).toList();
List<CaseEvidence> caseEvidenceList = super.listByIds(evidenceIds);
String caseId = CollUtil.getFirst(caseEvidenceList).getCaseId();
List<EvidenceDirectoryDTO> evidenceDirectoryS = listDirectoryTree(caseId);
// 同步删除文件夹
Map<String, CaseEvidence> 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<CaseEvidenceDetailDTO> queryEvidenceList(String caseId) {
return super.getBaseMapper().queryEvidenceList(caseId);
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
public List<CaseEvidenceDetailDTO> queryEvidenceList(String caseId, String batchNo) {
List<CaseEvidenceDetailDTO> caseEvidenceDetailDTOS = queryEvidenceList(caseId);
if (StrUtil.isNotEmpty(batchNo)) {
for (CaseEvidenceDetailDTO evidenceDetail : caseEvidenceDetailDTOS) {
List<EvidenceFileDTO> 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<CaseEvidenceDetailDTO> pageListEvidence(String caseId, String directoryId, String evidenceName, Integer pageNum, Integer pageSize) {
Assert.notEmpty(caseId, "案件id不能为空");
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = listDirectoryTree(caseId);
EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryDTOS);
EvidenceDirectoryDTO queryDirectory = rootDirectory.findDirectory(directoryId);
IPage<EvidenceFileDTO> fileDTOIPage = pageListCaseEvidence(queryDirectory, caseId, directoryId,
evidenceName, new Page<>(pageNum, pageSize));
if (fileDTOIPage.getTotal() == 0) {
return PageDTO.of(pageNum, pageSize, 0);
}
// 查询文件信息
List<String> evidenceIds = fileDTOIPage.getRecords().stream().map(EvidenceFileDTO::getEvidenceId).distinct().toList();
List<EvidenceFileDTO> fileInfoList = evidenceFileService.listFileInfo(evidenceIds);
Map<String, List<EvidenceFileDTO>> evidenceFileMap = fileInfoList.stream().collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId));
List<RecordFileDTO> recordFileDTOS = fileOcrProcessService.queryFileList(fileInfoList.stream().map(EvidenceFileDTO::getFileId).toList());
// 转换分页结果
//查询字典
List<ComDictionary> 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<EvidenceFileDTO> pageListCaseEvidence(EvidenceDirectoryDTO queryDirectory,
String caseId, String directoryId, String evidenceName,
Page<CaseEvidence> page) {
if (null == queryDirectory || queryDirectory.getLevel() != 3) {
/*if (null != queryDirectory && CollUtil.isEmpty(queryDirectory.listAllFileId())){
return PageDTO.of(page.getCurrent(), page.getSize(), 0);
}*/
List<String> 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<EvidenceFileDTO> 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<FileOcrProcess> fileOcrProcesses = new ArrayList<>();
for (EvidenceFileDTO evidenceFile : evidenceFiles) {
List<FileOcrProcess> 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<NotePromptExtractAttributesDto> attributes = caseEvidencePropertyService.findExtractAttributes(directory.getCategoryId());
notePrompt.setExtractAttributes(attributes);
log.info("属性提取开始。");
long attrStart = System.currentTimeMillis();
llmExtractDto.setPrompt(notePrompt.getPrompt());
llmExtractDto.setExtractAttributes(notePrompt.getExtractAttributes());
List<LLMExtractDto> llmExtractDtos = llmExtractService.extractAttribute(Collections.singletonList(llmExtractDto));
if (!llmExtractDtos.isEmpty()) {
List<NotePromptExtractAttributesDto> 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<EvidenceCategoryDTO> listCategoryTree(String caseType) {
Assert.notEmpty(caseType, "案件类型不能为空!");
return evidenceCategoryService.listCategoryTree(caseType);
}
@Override
public List<EvidenceDirectoryDTO> listFileTree(String caseId) {
return listFileTree(caseId, null);
}
@Override
public List<EvidenceDirectoryDTO> listFileTree(String caseId, String batchNo) {
Assert.notEmpty(caseId, "案件ID不能为空!");
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
evidenceDirectoryService.appendFile(evidenceDirectoryDTOS, evidenceFileService.queryFileInfoList(caseId, batchNo));
return evidenceDirectoryDTOS;
}
@Override
public List<EvidenceDirectoryDTO> listFileTree(String caseId, String batchNo, String evidenceId, String directoryId) {
Assert.notEmpty(caseId, "案件ID不能为空!");
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
evidenceDirectoryService.appendFile(evidenceDirectoryDTOS,
evidenceFileService.queryFileInfoList(caseId, batchNo, evidenceId, directoryId));
return evidenceDirectoryDTOS;
}
@Override
public List<EvidenceDirectoryDTO> listDirectoryTree(String caseId) {
Assert.notEmpty(caseId, "案件ID不能为空!");
List<EvidenceDirectoryDTO> 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<EvidenceCategoryDTO> evidenceCategoryTree = evidenceCategoryService.listCategoryTree(caseType);
List<EvidenceDirectoryDTO> evidenceDirectoryTree = evidenceDirectoryService.listDirectoryTree(caseId);
initCaseEvidenceDirectory(evidenceCategoryTree, evidenceDirectoryTree, caseId, null);
}
@Override
public void refreshCaseEvidence() {
log.info("开始初始化案件的证据目录。=========>>>>");
List<ModelCase> list = modelCaseService.list();
List<CaseEvidence> allEvidence = super.list();
List<EvidenceFile> allFile = evidenceFileService.list();
Map<String, String> 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<CaseEvidence> allEvidence, Map<String, String> catagroyMap, List<EvidenceFile> allFile) {
String caseType = modelCase.getCaseType();
String id = modelCase.getId();
// 开始初始化
initCaseEvidenceDirectory(id, caseType);
EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(listDirectoryTree(id));
List<CaseEvidence> 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<EvidenceFile> files = allFile.stream().filter(ef -> StrUtil.equals(ef.getEvidenceId(), caseEvidence.getId())).peek(ef -> ef.setDirectoryId(caseEvidence.getDirectoryId())).toList();
Map<String, MinioFile> 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<String> 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<EvidenceDirectoryDTO> evidenceFileDTOS) {
List<CaseEvidenceDetailDTO> oldEvidences = this.queryEvidenceList(caseId);
List<EvidenceDirectoryDTO> oldEvidenceDirectoryDTOS = listFileTree(caseId);
List<CaseEvidenceDetailDTO> newEvidences = toCaseCaseEvidenceDetailDTO(evidenceFileDTOS, oldEvidenceDirectoryDTOS);
newEvidences.forEach(caseEvidenceDetailDTO -> caseEvidenceDetailDTO.setCaseId(caseId));
List<CaseEvidenceDetailDTO> operationalEvidenceList = findChangedEvidence(oldEvidences, newEvidences);
String batchId = updateCaseEvidence(operationalEvidenceList);
// 异步调用
((CaseEvidenceService) AopContext.currentProxy()).syncEvidenceAnalysis(operationalEvidenceList);
return batchId;
}
@Async
public void syncEvidenceAnalysis(List<CaseEvidenceDetailDTO> evidenceList) {
List<EvidenceFileDTO> 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<String, List<EvidenceFileDTO>> evidenceMap = ocrFileDTOList.stream().collect(Collectors.groupingBy(EvidenceFileDTO::getEvidenceId));
for (Map.Entry<String, List<EvidenceFileDTO>> entry : evidenceMap.entrySet()) {
String evidenceId = entry.getKey();
// 首先统一更新为正在处理
CaseEvidence one = this.lambdaQuery().eq(CaseEvidence::getId, evidenceId).one();
updateEvidenceAppendProcessingNewTransaction(evidenceId, one.getProcessStatus(), "1");
}
for (Map.Entry<String, List<EvidenceFileDTO>> entry : evidenceMap.entrySet()) {
String evidenceId = entry.getKey();
List<EvidenceFileDTO> 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<String> 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<CaseEvidenceDetailDTO> 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<EvidenceProcessDTO> listOcrAndExtract(String caseId, String batchNo) {
Assert.notEmpty(caseId, "案件id不能为空");
ModelCase modelCase = modelCaseService.getById(caseId);
Assert.notNull(modelCase, "案件不存在");
List<CaseEvidenceDetailDTO> caseEvidenceDetailDTOS = this.queryEvidenceList(caseId, batchNo);
if (CollUtil.isEmpty(caseEvidenceDetailDTOS)) {
return new ArrayList<>();
}
List<EvidenceProcessDTO> processDTOList = caseEvidenceDetailDTOS.stream()
.filter(evidenceDetail -> CollUtil.isNotEmpty(evidenceDetail.getFileList()))
.map(EvidenceProcessDTO::new).collect(Collectors.toList());
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
List<EvidenceCategory> 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<EvidenceVerifyDTO> evidenceVerifyDTOS, String caseId, String batchNo) {
Assert.notEmpty(caseId, "案件id不能为空");
if (CollUtil.isEmpty(evidenceVerifyDTOS)) {
return;
}
List<CaseEvidenceDetailDTO> caseEvidenceDetailDTOS = queryEvidenceList(caseId, null);
List<EvidenceDirectoryDTO> directoryDTOS = evidenceDirectoryService.listDirectoryTree(caseId);
EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(directoryDTOS);
Map<String, List<EvidenceVerifyDTO>> evidenceMap = evidenceVerifyDTOS.stream().collect(Collectors.groupingBy(EvidenceVerifyDTO::getEvidenceId));
for (Map.Entry<String, List<EvidenceVerifyDTO>> entry : evidenceMap.entrySet()) {
String evidenceId = entry.getKey();
List<EvidenceVerifyDTO> 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<String, List<NotePromptExtractAttributesDto>> 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<EvidenceFileDTO> fileList = evidenceDetail.getFileList();
int initOrder = 0;
if (StrUtil.isNotEmpty(batchNo) && !CollUtil.isNotEmpty(fileList)) {
// 如果批次不为空,则只对当前批次的文件进行排序
initOrder = fileList.size();
}
List<String> 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<EvidenceDirectoryDTO> evidenceDirectoryList = verifyEvidenceReqVO.getEvidenceDirectoryList();
if (CollUtil.isEmpty(evidenceDirectoryList)) {
return;
}
// 重新把外层的信息设置到证据文件对象中
verifyEvidenceReqVO.getEvidenceDirectoryList().forEach(EvidenceDirectoryDTO::replaceEvidence);
List<EvidenceVerifyDTO> 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<EvidenceDirectoryDTO> evidenceDetails(String caseId, String batchNo, String evidenceId) {
List<EvidenceDirectoryDTO> evidenceDirectoryDTOS = listFileTree(caseId, batchNo, evidenceId, null);
List<CaseEvidence> caseEvidenceList = this.lambdaQuery().eq(CaseEvidence::getCaseId, caseId).list();
this.redoExtractAttributes(caseId, caseEvidenceList);
EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryDTOS);
// 强行翻译
rebuildEvidenceProperties(rootDirectory, caseEvidenceList);
List<CategoryPromptDTO> categoryPromptDTOS = evidenceDirectoryService.listCategoryPrompt(caseId);
Map<String, CaseEvidenceDTO> caseEvidenceMap = caseEvidenceList.stream().map(CaseEvidenceDTO::new).peek(e -> e.setDirectoryNamePathValue(rootDirectory)).collect(Collectors.toMap(CaseEvidenceDTO::getId, Function.identity()));
Map<String, CategoryPromptDTO> categoryPromptMap = categoryPromptDTOS.stream().collect(Collectors.toMap(CategoryPromptDTO::getDirectoryId, k -> k, (v1, v2) -> v1));
Iterator<EvidenceDirectoryDTO> iterator = evidenceDirectoryDTOS.iterator();
while (iterator.hasNext()) {
EvidenceDirectoryDTO evidenceDirectoryDTO = iterator.next();
evidenceDirectoryDTO.setFileEvidence(caseEvidenceMap, categoryPromptMap);
evidenceDirectoryDTO.removeEmptyDirectory();
List<EvidenceFileDTO> fileInfoList = evidenceDirectoryDTO.getFileInfoList();
if (CollUtil.isEmpty(evidenceDirectoryDTO.getChild()) && CollUtil.isEmpty(fileInfoList)) {
// 移除自身
iterator.remove();
}
}
return evidenceDirectoryDTOS;
}
public void redoExtractAttributes(String caseId, List<CaseEvidence> caseEvidences) {
EvidenceDirectoryDTO rootDirectory = new EvidenceDirectoryDTO(evidenceDirectoryService.listDirectoryTree(caseId));
Map<String, List<String>> categoryMapEvidence = new HashMap<>();
for (CaseEvidence caseEvidence : caseEvidences) {
EvidenceDirectoryDTO directory = rootDirectory.findDirectory(caseEvidence.getDirectoryId());
if (null != directory && StrUtil.isNotEmpty(directory.getCategoryId())) {
List<String> evidenceIds = categoryMapEvidence.getOrDefault(directory.getCategoryId(), new ArrayList<>());
evidenceIds.add(caseEvidence.getId());
categoryMapEvidence.put(directory.getCategoryId(), evidenceIds);
}
}
Map<String, List<NotePromptExtractAttributesDto>> map = new HashMap<>();
for (Map.Entry<String, List<String>> entry : categoryMapEvidence.entrySet()) {
map.putAll(caseEvidencePropertyService.listEvidenceProperty(entry.getKey(), entry.getValue()));
}
for (CaseEvidence caseEvidence : caseEvidences) {
List<NotePromptExtractAttributesDto> attributesDtos = map.get(caseEvidence.getId());
// 兼容老数据
if (CollUtil.isNotEmpty(attributesDtos)) {
caseEvidence.setProperty(attributesDtos);
}
}
}
@Override
public void downloadEvidence(String evidenceId, HttpServletResponse response) throws IOException, DocumentException {
List<EvidenceFileDTO> evidenceFileDTOList = evidenceFileService.listFileInfo(List.of(evidenceId));
Map<String, InputStream> 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<CaseEvidence> caseEvidenceList) {
Map<String, String> 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<String, List<NotePromptExtractAttributesDto>> 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<NotePromptExtractAttributesDto> 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<NotePromptExtractAttributesDto> mergeExtractAttributes(List<NotePromptExtractAttributesDto> property, List<NotePromptExtractAttributesDto> 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<EvidenceDirectory> 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<EvidenceDirectoryDTO> evidenceDirectoryDTOS = listDirectoryTree(evidenceDirectory.getCaseId());
List<String> 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<CaseEvidenceDetailDTO> caseEvidenceDetailDTOS) {
for (CaseEvidenceDetailDTO caseEvidenceDetailDTO : caseEvidenceDetailDTOS) {
if (StrUtil.equals(caseEvidenceDetailDTO.getId(), evidenceId)) {
return caseEvidenceDetailDTO;
}
}
return null;
}
private List<CaseEvidenceDetailDTO> toCaseCaseEvidenceDetailDTO(List<EvidenceDirectoryDTO> newDirectoryDTOS, List<EvidenceDirectoryDTO> oldEvidenceDirectoryDTOS) {
if (CollUtil.isEmpty(newDirectoryDTOS)) {
return new ArrayList<>();
}
EvidenceDirectoryDTO oldRootDirectory = new EvidenceDirectoryDTO(oldEvidenceDirectoryDTOS);
List<String> fileIdList = newDirectoryDTOS.stream().flatMap(directoryDTO -> directoryDTO.listAllFileId().stream()).toList();
Map<String, MinioFile> fileMap = minioService.listMinioFile(fileIdList).stream()
.collect(Collectors.toMap(MinioFile::getId, Function.identity()));
List<EvidenceDirectoryDTO> floatNewDirectoryDTOS = newDirectoryDTOS.stream().flatMap(directoryDTO -> directoryDTO.listAllDirectory().stream()).toList();
List<CaseEvidenceDetailDTO> 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<EvidenceFileDTO> 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<CaseEvidenceDetailDTO> findChangedEvidence(List<CaseEvidenceDetailDTO> oldEvidenceList,
List<CaseEvidenceDetailDTO> newEvidenceList) {
List<CaseEvidenceDetailDTO> caseEvidence2DTOList = new ArrayList<>();
if (CollUtil.isEmpty(oldEvidenceList) && CollUtil.isNotEmpty(newEvidenceList)) {
// 数据库中不存在数据,则全部新增
for (CaseEvidenceDetailDTO evidenceDetailDTO : newEvidenceList) {
List<String> 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<String, Map<String, EvidenceFileDTO>> 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<String, EvidenceFileDTO> fileCache = evidenceFileCache.get(newEvidence.getId());
if (StrUtil.equals(oldEvidence.getId(), newEvidence.getId())) {
isFind = true;
oldEvidence.setUpdateStatus("-1");
List<String> oldFileIds = oldEvidence.getFileList().stream().map(EvidenceFileDTO::getFileId).toList();
List<String> newFileIds = newEvidence.getFileList().stream().map(EvidenceFileDTO::getFileId).toList();
TupleIdRecord tupleIdRecord = compareFileList(newFileIds, oldFileIds);
List<EvidenceFileDTO> 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<String> 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<String> 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<EvidenceCategoryDTO> evidenceCategoryTree, List<EvidenceDirectoryDTO> evidenceDirectoryTree, String caseId, String parentId) {
if (null == evidenceDirectoryTree) {
evidenceDirectoryTree = new ArrayList<>(1);
}
for (EvidenceCategoryDTO evidenceCategoryDTO : evidenceCategoryTree) {
List<EvidenceDirectoryDTO> 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<String> newFileIdList, List<String> oldFileIdList) {
List<String> addFileList = new ArrayList<>();
List<String> deleteFileList = new ArrayList<>();
List<String> 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<String> addFileList, List<String> updateFileList, List<String> deleteFileList) {
}
}