|
|
package com.supervision.police.service.impl;
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
import cn.hutool.core.lang.Pair;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.druid.sql.ast.SQLStatement;
|
|
|
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.supervision.common.constant.IndexRuleConstants;
|
|
|
import com.supervision.common.constant.NotePromptConstants;
|
|
|
import com.supervision.common.domain.R;
|
|
|
import com.supervision.common.utils.IPages;
|
|
|
import com.supervision.common.utils.StringUtils;
|
|
|
import com.supervision.constant.DataStatus;
|
|
|
import com.supervision.neo4j.dto.WebRelDTO;
|
|
|
import com.supervision.neo4j.service.Neo4jService;
|
|
|
import com.supervision.police.domain.*;
|
|
|
import com.supervision.police.dto.*;
|
|
|
import com.supervision.police.dto.indexRule.IndexRule;
|
|
|
import com.supervision.police.dto.indexRule.RuleCondition;
|
|
|
import com.supervision.police.dto.indexRule.RuleConditionGroup;
|
|
|
import com.supervision.police.dto.neo4j.NodeDTO;
|
|
|
import com.supervision.police.dto.neo4j.PathDTO;
|
|
|
import com.supervision.police.dto.neo4j.RelationshipValueDTO;
|
|
|
import com.supervision.police.mapper.CasePersonMapper;
|
|
|
import com.supervision.police.mapper.ModelAtomicResultMapper;
|
|
|
import com.supervision.police.mapper.ModelIndexMapper;
|
|
|
import com.supervision.police.service.*;
|
|
|
import com.supervision.police.vo.GraphDebugReqVO;
|
|
|
import com.supervision.police.vo.GraphDebugResVO;
|
|
|
import com.supervision.police.vo.ModelIndexReqVO;
|
|
|
import com.supervision.utils.JudgeLogicUtil;
|
|
|
import com.supervision.utils.SqlParserUtil;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.neo4j.driver.Record;
|
|
|
import org.neo4j.driver.internal.InternalNode;
|
|
|
import org.neo4j.driver.internal.InternalRelationship;
|
|
|
import org.neo4j.driver.types.Node;
|
|
|
import org.neo4j.driver.types.Relationship;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 指标表(ModelIndex)表服务实现类
|
|
|
*
|
|
|
* @author qmy
|
|
|
* @since 2024-07-05 09:20:10
|
|
|
*/
|
|
|
@Slf4j
|
|
|
@Service
|
|
|
@RequiredArgsConstructor
|
|
|
public class ModelIndexServiceImpl extends ServiceImpl<ModelIndexMapper, ModelIndex> implements ModelIndexService {
|
|
|
|
|
|
private final ComDictionaryService comDictionaryService;
|
|
|
|
|
|
private final ModelIndexMapper modelIndexMapper;
|
|
|
|
|
|
private final ModelAtomicIndexService modelAtomicIndexService;
|
|
|
|
|
|
private final ModelCaseService modelCaseService;
|
|
|
|
|
|
private final ModelAtomicResultMapper modelAtomicResultMapper;
|
|
|
|
|
|
private final CasePersonMapper casePersonMapper;
|
|
|
|
|
|
private final CaseStatusManageService caseStatusManageService;
|
|
|
|
|
|
private final ModelIndexAtomicRelationService modelIndexAtomicRelationService;
|
|
|
|
|
|
private final NotePromptService notePromptService;
|
|
|
|
|
|
private final EvidenceCategoryService evidenceCategoryService;
|
|
|
|
|
|
@Value("${case.evidence.table}")
|
|
|
private List<String> allowedTables;
|
|
|
|
|
|
private final Neo4jService neo4jService;
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> selectAll(ModelIndexReqVO modelIndex, Integer page, Integer size) {
|
|
|
|
|
|
// 构建查询条件
|
|
|
IPage<ModelIndex> iPage = new Page<>(page, size);
|
|
|
LambdaQueryWrapper<ModelIndex> wrapper = Wrappers.lambdaQuery();
|
|
|
wrapper.like(modelIndex.getName() != null, ModelIndex::getName, modelIndex.getName())
|
|
|
.like(modelIndex.getShortName() != null, ModelIndex::getShortName, modelIndex.getShortName())
|
|
|
.like(modelIndex.getRemark() != null, ModelIndex::getRemark, modelIndex.getRemark())
|
|
|
.eq(StringUtils.isNotEmpty(modelIndex.getIndexType()), ModelIndex::getIndexType, modelIndex.getIndexType())
|
|
|
.eq(StringUtils.isNotEmpty(modelIndex.getCaseType()), ModelIndex::getCaseType, modelIndex.getCaseType())
|
|
|
.eq(ModelIndex::getDataStatus, "1");
|
|
|
|
|
|
|
|
|
if (StrUtil.isNotEmpty(modelIndex.getAtomicIndexName())) {
|
|
|
// 如果查询条件中有原子指标名称,则根据原子指标名称过滤关联的指标id
|
|
|
List<ModelIndexAtomicRelationDTO> modelIndexAtomicDTOS = modelIndexAtomicRelationService.listByAtomicIndexName(modelIndex.getAtomicIndexName());
|
|
|
List<String> indexIdList = modelIndexAtomicDTOS.stream().map(ModelIndexAtomicRelationDTO::getModelIndexId).distinct().toList();
|
|
|
if (CollUtil.isEmpty(indexIdList)) {
|
|
|
return R.ok(IPages.buildDataMap(iPage));
|
|
|
}
|
|
|
wrapper.in(CollUtil.isNotEmpty(indexIdList), ModelIndex::getId, indexIdList);
|
|
|
}
|
|
|
|
|
|
wrapper.orderBy(true, false, ModelIndex::getUpdateTime);
|
|
|
iPage = modelIndexMapper.selectPage(iPage, wrapper);
|
|
|
|
|
|
// 分页查询
|
|
|
List<ModelIndex> records = iPage.getRecords();
|
|
|
List<ComDictionary> dicts = comDictionaryService.list();
|
|
|
|
|
|
// 查询结果拼装
|
|
|
for (ModelIndex index : records) {
|
|
|
index.setIndexTypeName(comDictionaryService.getName(dicts, "index_type", index.getIndexType()));
|
|
|
index.setCaseTypeName(comDictionaryService.getName(dicts, "case_type", index.getCaseType()));
|
|
|
//原子指标
|
|
|
String judgeLogic = index.getJudgeLogic();
|
|
|
Set<String> ids = new HashSet<>();
|
|
|
IndexRule indexRule = index.getIndexRule();
|
|
|
if (indexRule != null) {
|
|
|
List<RuleConditionGroup> ruleConditionGroupList = indexRule.getRuleConditionGroupList();
|
|
|
for (RuleConditionGroup ruleConditionGroup : ruleConditionGroupList) {
|
|
|
List<RuleCondition> ruleConditionList = ruleConditionGroup.getRuleConditionList();
|
|
|
for (RuleCondition ruleCondition : ruleConditionList) {
|
|
|
ids.add(ruleCondition.getAtomicIndexId());
|
|
|
}
|
|
|
}
|
|
|
List<ModelAtomicIndex> atomicIndexList = modelAtomicIndexService.selectBatchIds(ids.stream().toList());
|
|
|
index.setAtomicIndexList(atomicIndexList);
|
|
|
} else if (StringUtils.isNotEmpty(judgeLogic)) {
|
|
|
List<JudgeLogic> logic = JSONUtil.toList(judgeLogic, JudgeLogic.class);
|
|
|
for (JudgeLogic judge : logic) {
|
|
|
List<AtomicData> atomicData = judge.getAtomicData();
|
|
|
for (AtomicData atomic : atomicData) {
|
|
|
ids.add(atomic.getAtomicIndex());
|
|
|
}
|
|
|
}
|
|
|
List<ModelAtomicIndex> atomicIndexList = modelAtomicIndexService.selectBatchIds(ids.stream().toList());
|
|
|
index.setAtomicIndexList(atomicIndexList);
|
|
|
}
|
|
|
index.setAtomicIndexNum(ids.size());
|
|
|
}
|
|
|
iPage.setRecords(records);
|
|
|
return R.ok(IPages.buildDataMap(iPage));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> addOrUpd(ModelIndex modelIndex) {
|
|
|
int i;
|
|
|
if (StringUtils.isEmpty(modelIndex.getId())) {
|
|
|
i = modelIndexMapper.insert(modelIndex);
|
|
|
modelIndexAtomicRelationService.saveByModelIndex(modelIndex);
|
|
|
} else {
|
|
|
ModelIndex dbModelIndex = super.getById(modelIndex.getId());
|
|
|
modelIndex.setJudgeLogic(dbModelIndex.getJudgeLogic());// 保持原来判断逻辑不变
|
|
|
i = modelIndexMapper.updateById(modelIndex);
|
|
|
modelIndexAtomicRelationService.updateByModelIndex(modelIndex);
|
|
|
}
|
|
|
if (i > 0) {
|
|
|
return R.okMsg("保存成功");
|
|
|
} else {
|
|
|
return R.fail("保存失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> del(String id) {
|
|
|
ModelIndex index = modelIndexMapper.selectById(id);
|
|
|
index.setDataStatus(DataStatus.NOT_AVAILABLE.getCode());
|
|
|
int i = modelIndexMapper.updateById(index);
|
|
|
if (i > 0) {
|
|
|
modelIndexAtomicRelationService.deleteByModelIndex(id);
|
|
|
return R.okMsg("删除成功");
|
|
|
} else {
|
|
|
return R.fail("删除失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> selectAllAtomic(ModelAtomicIndex modelAtomicIndex, Integer page, Integer size) {
|
|
|
IPage<ModelAtomicIndex> iPage = new Page<>(page, size);
|
|
|
iPage = modelAtomicIndexService.selectAll(iPage, modelAtomicIndex);
|
|
|
List<ModelAtomicIndex> records = iPage.getRecords();
|
|
|
List<ComDictionary> dicts = comDictionaryService.list();
|
|
|
String caseType = StrUtil.isNotEmpty(modelAtomicIndex.getCaseType()) ? modelAtomicIndex.getCaseType() : NotePromptConstants.CASE_TYPE_ENGINEERING_CONTRACT_FRAUD;
|
|
|
EvidenceCategoryDTO rootCategory = new EvidenceCategoryDTO(evidenceCategoryService.listCategoryTree(caseType));
|
|
|
for (ModelAtomicIndex index : records) {
|
|
|
index.setCaseTypeName(comDictionaryService.getName(dicts, "case_type", index.getCaseType()));
|
|
|
index.setIndexSourceName(comDictionaryService.getName(dicts, "index_source", index.getIndexSource()));
|
|
|
index.setRecordTypeName(comDictionaryService.getName(dicts, "record_type", index.getRecordType()));
|
|
|
index.setCategoryIdPath(rootCategory.listCategoryIdPath(index.getCategoryId()));
|
|
|
}
|
|
|
iPage.setRecords(records);
|
|
|
return R.ok(IPages.buildDataMap(iPage));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> addOrUpdAtomic(ModelAtomicIndex modelAtomicIndex) {
|
|
|
|
|
|
saveAtomicIndexPreDo(modelAtomicIndex);
|
|
|
|
|
|
// 校验是否已经存在了相同名称的原子指标
|
|
|
ModelAtomicIndex existIndex = modelAtomicIndexService.lambdaQuery().eq(ModelAtomicIndex::getName, modelAtomicIndex.getName())
|
|
|
.eq(ModelAtomicIndex::getDataStatus, DataStatus.AVAILABLE.getCode()).last("limit 1").one();
|
|
|
|
|
|
if (ObjectUtil.isNotEmpty(existIndex) && !StringUtils.equals(modelAtomicIndex.getId(), existIndex.getId())) {
|
|
|
throw new IllegalArgumentException("已存在相同名称的原子指标");
|
|
|
}
|
|
|
|
|
|
boolean success = modelAtomicIndexService.saveOrUpdate(modelAtomicIndex);
|
|
|
return success ? R.okMsg("保存成功") : R.fail("保存失败");
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 原子指标保存前置处理
|
|
|
*
|
|
|
* @param modelAtomicIndex
|
|
|
*/
|
|
|
private void saveAtomicIndexPreDo(ModelAtomicIndex modelAtomicIndex) {
|
|
|
if (StringUtils.equals(IndexRuleConstants.OPERAND_TYPE_DB, modelAtomicIndex.getIndexSource())) {
|
|
|
Assert.notEmpty(modelAtomicIndex.getCategoryId(), "分类不能为空");
|
|
|
// 如果查询类型为数据查询,则校验查询语句
|
|
|
Assert.notEmpty(modelAtomicIndex.getQueryLang(), "查询语言不能为空");
|
|
|
Assert.isTrue(checkSql(modelAtomicIndex.getQueryLang()), "查询语句不合法");
|
|
|
} else if (StringUtils.equals(IndexRuleConstants.OPERAND_TYPE_STRUCTURE, modelAtomicIndex.getIndexSource())) {
|
|
|
Assert.notEmpty(modelAtomicIndex.getPromptId(), "promptId不能为空");
|
|
|
NotePrompt notePrompt = notePromptService.getBaseMapper().selectById(modelAtomicIndex.getPromptId());
|
|
|
Assert.notNull(notePrompt, "提示词信息不存在");
|
|
|
Assert.notEmpty(notePrompt.getEvidenceCategoryId(), "提示词分类为空");
|
|
|
modelAtomicIndex.setCategoryId(notePrompt.getEvidenceCategoryId());
|
|
|
}else if (StringUtils.equals(IndexRuleConstants.OPERAND_TYPE_GRAPH, modelAtomicIndex.getIndexSource())) {
|
|
|
Assert.notEmpty(modelAtomicIndex.getQueryLang(), "查询语句不能为空");
|
|
|
// NotePrompt notePrompt = notePromptService.getBaseMapper().selectById(modelAtomicIndex.getPromptId());
|
|
|
// Assert.notNull(notePrompt, "提示词信息不存在");
|
|
|
// String query = promptGenerateGraphQuery(notePrompt, queryTemplate);
|
|
|
// modelAtomicIndex.setQueryLang(query);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public R<?> delAtomic(String id) {
|
|
|
ModelAtomicIndex index = modelAtomicIndexService.getMapper().selectById(id);
|
|
|
index.setDataStatus(DataStatus.NOT_AVAILABLE.getCode());
|
|
|
int i = modelAtomicIndexService.getMapper().updateById(index);
|
|
|
if (i > 0) {
|
|
|
modelAtomicIndexService.whenDeleteAtomicIndex(index.getCaseType(), id);
|
|
|
return R.okMsg("删除成功");
|
|
|
} else {
|
|
|
return R.fail("删除失败");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public List<CaseAtomicIndexDTO> listCaseAtomicIndex(String caseId, String indexSource) {
|
|
|
|
|
|
Assert.notEmpty(caseId, "案件id不能为空");
|
|
|
ModelCase modelCase = modelCaseService.getById(caseId);
|
|
|
Assert.notNull(modelCase, "案件不存在");
|
|
|
String caseType = modelCase.getCaseType();
|
|
|
Assert.notEmpty(caseType, "案件类型不能为空");
|
|
|
List<CasePerson> casePersonList = casePersonMapper.selectList(Wrappers.lambdaQuery(CasePerson.class)
|
|
|
.eq(CasePerson::getCaseId, caseId).eq(CasePerson::getRoleCode, "1"));
|
|
|
Assert.notEmpty(casePersonList, "案件行为人不能为空!");
|
|
|
String actorId = CollUtil.getFirst(casePersonList).getId();
|
|
|
// 获取案件类型对应的指标
|
|
|
List<ModelIndex> modelIndexList = modelIndexMapper.selectList(
|
|
|
Wrappers.lambdaQuery(ModelIndex.class)
|
|
|
.eq(ModelIndex::getCaseType, caseType).eq(ModelIndex::getDataStatus, "1"));
|
|
|
if (CollUtil.isEmpty(modelIndexList)) {
|
|
|
return new ArrayList<>(1);
|
|
|
}
|
|
|
|
|
|
// 从指标中计算出所有原子指标id
|
|
|
List<String> atomicIndexIds = modelIndexList.stream().filter(modelIndex -> StrUtil.isNotEmpty(modelIndex.getJudgeLogic()))
|
|
|
.map(modelIndex -> JudgeLogicUtil.pickAtomicIndexIds(modelIndex.getJudgeLogic()))
|
|
|
.flatMap(Collection::stream).distinct().toList();
|
|
|
|
|
|
if (CollUtil.isEmpty(atomicIndexIds)) {
|
|
|
return new ArrayList<>(1);
|
|
|
}
|
|
|
|
|
|
// 查询原子指标相关信息
|
|
|
List<ModelAtomicIndex> modelAtomicIndexList = modelAtomicIndexService.listCaseAtomicIndex(atomicIndexIds, caseType, indexSource);
|
|
|
if (CollUtil.isEmpty(modelAtomicIndexList)) {
|
|
|
return new ArrayList<>(1);
|
|
|
}
|
|
|
|
|
|
// 查询判定结果数据
|
|
|
List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
|
|
|
Wrappers.lambdaQuery(ModelAtomicResult.class).eq(ModelAtomicResult::getCaseId, caseId)
|
|
|
.eq(ModelAtomicResult::getCasePersonId, actorId)
|
|
|
.in(ModelAtomicResult::getAtomicId, atomicIndexIds));
|
|
|
|
|
|
Map<String, Map<String, List<ModelAtomicResult>>> modelAtomicResultGroup = modelAtomicResults.stream()
|
|
|
.filter(modelAtomicResult -> StrUtil.isNotEmpty(modelAtomicResult.getAtomicId()))
|
|
|
.collect(Collectors.groupingBy(ModelAtomicResult::getIndexId, Collectors.groupingBy(ModelAtomicResult::getAtomicId)));
|
|
|
|
|
|
Map<String, List<ModelIndex>> modelIndexMapAtomic = groupModelIndexByAtomicIndexId(modelIndexList);
|
|
|
|
|
|
// 以原子指标为基准,组装数据
|
|
|
return modelAtomicIndexList.stream().flatMap(atomicIndex ->
|
|
|
modelIndexMapAtomic.get(atomicIndex.getId()).stream().map(modelIndex -> {
|
|
|
Map<String, List<ModelAtomicResult>> map = modelAtomicResultGroup.getOrDefault(modelIndex.getId(), new HashMap<>(1));
|
|
|
return new CaseAtomicIndexDTO(atomicIndex, modelIndex, CollUtil.getFirst(map.get(atomicIndex.getId())));
|
|
|
})
|
|
|
).toList();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
|
|
|
public Boolean saveCaseAtomicResult(CaseAtomicResultWrapper caseAtomicResultWrapper) {
|
|
|
|
|
|
Assert.notEmpty(caseAtomicResultWrapper.getCaseId(), "案件id不能为空!");
|
|
|
ModelCase modelCase = modelCaseService.getById(caseAtomicResultWrapper.getCaseId());
|
|
|
Assert.notNull(modelCase, "案件不存在!");
|
|
|
// 设置行为人id
|
|
|
CasePerson casePerson = casePersonMapper.selectOne(Wrappers.lambdaQuery(CasePerson.class)
|
|
|
.eq(CasePerson::getCaseId, modelCase.getId()).eq(CasePerson::getRoleCode, "1").eq(CasePerson::getCaseActorFlag, 1));
|
|
|
caseAtomicResultWrapper.setActorId(casePerson.getId());
|
|
|
|
|
|
//清空人工评估结果
|
|
|
removeCaseAtomicResult(caseAtomicResultWrapper.getCaseId(), modelCase.getCaseType(),
|
|
|
caseAtomicResultWrapper.getActorId(), "1");
|
|
|
|
|
|
// 保存原子评估结果
|
|
|
caseAtomicResultWrapper.getCaseAtomicIndexList().stream().map(caseAtomicIndexDTO ->
|
|
|
caseAtomicIndexDTO.toModelAtomicResult(
|
|
|
caseAtomicResultWrapper.getCaseId(), caseAtomicResultWrapper.getActorId())).toList()
|
|
|
.forEach(modelAtomicResultMapper::insert);
|
|
|
|
|
|
caseStatusManageService.whenUpdateIndexResult(caseAtomicResultWrapper.getCaseId());
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
@Override
|
|
|
public boolean checkSql(String sql) {
|
|
|
log.info("checkSql:{}", sql);
|
|
|
if (StringUtils.isEmpty(sql)) {
|
|
|
return false;
|
|
|
}
|
|
|
if (CollUtil.isEmpty(this.allowedTables)) {
|
|
|
log.info("checkSql:未配置允许的表");
|
|
|
return false;
|
|
|
}
|
|
|
MySqlStatementParser parser = new MySqlStatementParser(sql);
|
|
|
SQLStatement sqlStatement = SqlParserUtil.parseStatement(parser);
|
|
|
if (Objects.isNull(sqlStatement)) {
|
|
|
log.warn("checkSql sql:{}语句解析失败", sql);
|
|
|
return false;
|
|
|
}
|
|
|
String sqlType = SqlParserUtil.detectSQLType(sqlStatement);
|
|
|
if (!"SELECT".equals(sqlType)) {
|
|
|
log.warn("checkSql:只支持查询类型语句");
|
|
|
return false;
|
|
|
}
|
|
|
List<String> tableList = SqlParserUtil.extractTableNames(sqlStatement);
|
|
|
if (CollUtil.isEmpty(tableList)) {
|
|
|
log.warn("checkSql:未检测到表");
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
long count = tableList.stream().filter(table -> !this.allowedTables.contains(table)).count();
|
|
|
if (count > 0) {
|
|
|
log.warn("checkSql:表{}不在允许的表列表中", tableList);
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Map<String, List<ValueCalculateScopeDTO>> listAtomicIndexAttributeScope(List<String> atomicIndexIds) {
|
|
|
|
|
|
if (CollUtil.isEmpty(atomicIndexIds)) {
|
|
|
return Map.of();
|
|
|
}
|
|
|
Map<String, List<ValueCalculateScopeDTO>> result = atomicIndexIds.stream().collect(Collectors.toMap(i -> i, i -> List.of()));
|
|
|
List<ModelAtomicIndex> atomicIndexList = modelAtomicIndexService.listByIds(atomicIndexIds);
|
|
|
if (CollUtil.isEmpty(atomicIndexList)) {
|
|
|
return result;
|
|
|
}
|
|
|
List<String> promptIds = atomicIndexList.stream().map(ModelAtomicIndex::getPromptId).filter(StrUtil::isNotEmpty).toList();
|
|
|
if (CollUtil.isEmpty(promptIds)) {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
List<NotePrompt> notePrompts = notePromptService.listByIds(promptIds);
|
|
|
Map<String, String> dicMap = comDictionaryService.getDictionaryMap("prompt_attribute_valuetype");
|
|
|
|
|
|
for (Map.Entry<String, List<ValueCalculateScopeDTO>> entry : result.entrySet()) {
|
|
|
List<ValueCalculateScopeDTO> scopeDTOList = makeScopes(entry.getKey(), atomicIndexList, notePrompts, dicMap);
|
|
|
if (scopeDTOList != null) {
|
|
|
entry.setValue(scopeDTOList);
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public GraphDebugResVO graphDebug(GraphDebugReqVO graphDebugDTO) {
|
|
|
|
|
|
GraphDebugResVO graphDebugResVO = new GraphDebugResVO();
|
|
|
if (StrUtil.isEmpty(graphDebugDTO.getCaseId())){
|
|
|
graphDebugResVO.setMessageType("2");
|
|
|
graphDebugResVO.setMessage("请选择案件!");
|
|
|
return graphDebugResVO;
|
|
|
}
|
|
|
|
|
|
CasePerson casePerson = casePersonMapper.selectOne(new LambdaQueryWrapper<>(CasePerson.class)
|
|
|
.eq(CasePerson::getCaseId, graphDebugDTO.getCaseId()).eq(CasePerson::getRoleCode, "1")
|
|
|
.eq(CasePerson::getCaseActorFlag, 1));
|
|
|
Map<String, Object> parameters = new HashMap<>();
|
|
|
parameters.put("caseId", graphDebugDTO.getCaseId());
|
|
|
if (null != casePerson){
|
|
|
parameters.put("lawActor", casePerson.getName());
|
|
|
}
|
|
|
|
|
|
// 执行查询语句
|
|
|
List<Record> records;
|
|
|
try {
|
|
|
records = this.neo4jService.executeCypher(graphDebugDTO.getQueryLang(), parameters);
|
|
|
} catch (Exception e) {
|
|
|
graphDebugResVO.setMessageType("1");
|
|
|
graphDebugResVO.setMessage(e.getMessage());
|
|
|
return graphDebugResVO;
|
|
|
}
|
|
|
|
|
|
if (CollUtil.isNotEmpty(records)){
|
|
|
graphDebugResVO.setRecordTitleList(records.get(0).keys());
|
|
|
}
|
|
|
graphDebugResVO.setRecordList(mapRecords(records));
|
|
|
|
|
|
Pair<List<WebRelDTO>, List<Map<String, String>>> pair = this.neo4jService.mergeRecord(generateNodes(records), generateRelations(records));
|
|
|
graphDebugResVO.setGraphRelList(pair.getKey());
|
|
|
graphDebugResVO.setGraphNodeList(pair.getValue());
|
|
|
|
|
|
// 尝试转换为图形数据
|
|
|
return graphDebugResVO;
|
|
|
}
|
|
|
|
|
|
|
|
|
private List<WebRelDTO> generateRelations(List<Record> records) {
|
|
|
|
|
|
List<WebRelDTO> graphRelList = records.stream().flatMap(record -> record.values().stream())
|
|
|
.filter(value -> value.type().name().equals("RELATIONSHIP"))
|
|
|
.map(value -> {
|
|
|
Relationship relationship = value.asRelationship();
|
|
|
return new WebRelDTO(relationship.id(), relationship.endNodeId(), relationship.type());
|
|
|
})
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
// 拓展关系信息
|
|
|
Set<Long> relationIds = new HashSet<>();
|
|
|
for (Record record : records) {
|
|
|
// relId
|
|
|
org.neo4j.driver.Value relValue = record.get("relId");
|
|
|
if (StrUtil.equalsAny(relValue.type().name(), "INTEGER")){
|
|
|
relationIds.add(relValue.asLong());
|
|
|
}
|
|
|
}
|
|
|
if (CollUtil.isNotEmpty(relationIds)){
|
|
|
List<Record> extendRecord = neo4jService.executeCypher("MATCH ()-[r]-() where id(r) in $relationIds return r", Map.of("relationIds", relationIds));
|
|
|
if (CollUtil.isNotEmpty(extendRecord)){
|
|
|
graphRelList.addAll(extendRecord.stream().flatMap(r -> r.values().stream()).map(r -> {
|
|
|
Relationship relationship = r.asRelationship();
|
|
|
return new WebRelDTO(relationship.startNodeId(), relationship.endNodeId(), relationship.type());
|
|
|
}).toList());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Set<String> relIdSet = new HashSet<>();
|
|
|
return graphRelList.stream().filter(map -> relIdSet.add(StrUtil.join("-", map.getSource(), map.getTarget()))).toList();
|
|
|
}
|
|
|
|
|
|
|
|
|
private List<Map<String, String>> generateNodes(List<Record> records) {
|
|
|
|
|
|
|
|
|
List<Map<String, String>> graphNodeList = records.stream().flatMap(record -> record.values().stream())
|
|
|
.filter(value -> value.type().name().equals("NODE")).map(value ->{
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
Node node = value.asNode();
|
|
|
map.put("id", String.valueOf(node.id()));
|
|
|
map.put("name", node.get("name").asString());
|
|
|
map.put("entityName", node.get("name").asString());
|
|
|
return map;
|
|
|
}
|
|
|
).collect(Collectors.toList());
|
|
|
|
|
|
// 拓展节点信息
|
|
|
Set<Long> nodeIds = new HashSet<>();
|
|
|
for (Record record : records) {
|
|
|
// startId ,endId
|
|
|
org.neo4j.driver.Value startValue = record.get("startId");
|
|
|
org.neo4j.driver.Value endValue = record.get("endId");
|
|
|
|
|
|
if (StrUtil.equalsAny(startValue.type().name(), "INTEGER")){
|
|
|
nodeIds.add(startValue.asLong());
|
|
|
}
|
|
|
if (StrUtil.equalsAny(endValue.type().name(), "INTEGER")){
|
|
|
nodeIds.add(endValue.asLong());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (CollUtil.isNotEmpty(nodeIds)){
|
|
|
List<Record> extendRecord = neo4jService.executeCypher("MATCH (n) where id(n) in $nodeIds return n", Map.of("nodeIds", nodeIds));
|
|
|
if (CollUtil.isNotEmpty(extendRecord)){
|
|
|
graphNodeList.addAll(extendRecord.stream().flatMap(r -> r.values().stream()).map(r -> {
|
|
|
Map<String, String> map = new HashMap<>();
|
|
|
map.put("id", String.valueOf(r.asNode().id()));
|
|
|
map.put("name", r.get("name").asString());
|
|
|
map.put("entityName", r.get("name").asString());
|
|
|
return map;
|
|
|
}).toList());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Set<String> nodeIdSet = new HashSet<>();
|
|
|
return graphNodeList.stream().filter(map -> nodeIdSet.add(map.get("id"))).toList();
|
|
|
}
|
|
|
|
|
|
private List<Map<String, Object>> mapRecords(List<Record> records) {
|
|
|
List<Map<String, Object>> recordList = new ArrayList<>();
|
|
|
for (Record record : records) {
|
|
|
HashMap<String, Object> map = new HashMap<>();
|
|
|
for (String key : record.keys()) {
|
|
|
org.neo4j.driver.Value value = record.get(key);
|
|
|
String typeName = value.type().name();
|
|
|
if (typeName.equals("NULL")){
|
|
|
map.put(key,null);
|
|
|
}
|
|
|
|
|
|
if (StrUtil.equalsAny(typeName, "BOOLEAN","STRING", "NUMBER", "INTEGER", "FLOAT")){
|
|
|
// MATCH (n)-[r]-() where n.caseId= '1' RETURN n.recordId limit 10
|
|
|
map.put(key,value.asObject());
|
|
|
}
|
|
|
|
|
|
if (typeName.equals("PATH")){
|
|
|
// MATCH p=(n)-[*2]-() where n.caseId= '1' RETURN p limit 10
|
|
|
map.put(key,new PathDTO(value.asPath()));
|
|
|
}
|
|
|
|
|
|
if (typeName.equals("RELATIONSHIP")){
|
|
|
// MATCH (n)-[r]-() where n.caseId= '1' RETURN r limit 10
|
|
|
map.put(key,new RelationshipValueDTO((InternalRelationship) value.asRelationship()));
|
|
|
}
|
|
|
if (typeName.equals("LIST OF ANY?")){
|
|
|
|
|
|
List<RelationshipValueDTO> list = value.asList().stream()
|
|
|
.map(i -> new RelationshipValueDTO((InternalRelationship) i)).toList();
|
|
|
map.put(key,list);
|
|
|
}
|
|
|
if (typeName.equals("NODE")){
|
|
|
// MATCH (n)-[r]-() where n.caseId= '1' RETURN r limit 10
|
|
|
map.put(key,new NodeDTO((InternalNode) value.asNode()));
|
|
|
}
|
|
|
recordList.add(map);
|
|
|
}
|
|
|
}
|
|
|
return recordList;
|
|
|
}
|
|
|
|
|
|
private List<ValueCalculateScopeDTO> makeScopes(String atomicIndexId, List<ModelAtomicIndex> atomicIndexList, List<NotePrompt> notePrompts, Map<String, String> dicMap) {
|
|
|
ModelAtomicIndex modelAtomicIndex = atomicIndexList.stream().filter(i -> StrUtil.equals(atomicIndexId, i.getId())).findFirst().orElse(null);
|
|
|
if (null == modelAtomicIndex || StrUtil.isEmpty(modelAtomicIndex.getPromptId())) {
|
|
|
return null;
|
|
|
}
|
|
|
String properties = modelAtomicIndex.getProperties();
|
|
|
if (StrUtil.isEmpty(properties)) {
|
|
|
return null;
|
|
|
}
|
|
|
NotePrompt notePromptDTO = notePrompts.stream().filter(i -> StrUtil.equals(modelAtomicIndex.getPromptId(), i.getId())).findFirst().orElse(null);
|
|
|
if (null == notePromptDTO) {
|
|
|
return null;
|
|
|
}
|
|
|
List<NotePromptExtractAttributesDto> extractAttributes = notePromptDTO.getExtractAttributes();
|
|
|
if (CollUtil.isNotEmpty(extractAttributes)) {
|
|
|
return extractAttributes.stream().map(extractAttribute -> {
|
|
|
ValueCalculateScopeDTO valueCalculateScope = new ValueCalculateScopeDTO();
|
|
|
valueCalculateScope.setValue(extractAttribute.getAttrName());
|
|
|
valueCalculateScope.setValueType(extractAttribute.getAttrValueType());
|
|
|
valueCalculateScope.setValueTypeDesc(dicMap.get(extractAttribute.getAttrValueType()));
|
|
|
valueCalculateScope.setOperatorList(
|
|
|
IndexRuleConstants.VALUE_TYPE_OPERATOR_MAPPING.get(extractAttribute.getAttrValueType()));
|
|
|
Map<String, String> map = IndexRuleConstants.VALUE_TYPE_AGGREGATE_MAPPING.getOrDefault(valueCalculateScope.getValueType(),new HashMap<>());
|
|
|
valueCalculateScope.setAggregateList(map.entrySet().stream().map(entry -> new Pair<>(entry.getKey(), entry.getValue())).toList());
|
|
|
return valueCalculateScope;
|
|
|
}).toList();
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 清空案件下的评估结果
|
|
|
*
|
|
|
* @param caseId 案件id
|
|
|
* @param caseType 案件类型
|
|
|
* @param actorId 行为人id
|
|
|
* @param indexSource 原子指标来源
|
|
|
*/
|
|
|
private void removeCaseAtomicResult(String caseId, String caseType, String actorId, String indexSource) {
|
|
|
List<ModelAtomicIndex> modelAtomicIndexList = modelAtomicIndexService.listCaseAtomicIndex(null, caseType, indexSource);
|
|
|
List<String> atomicIndexIds = modelAtomicIndexList.stream().map(ModelAtomicIndex::getId).distinct().toList();
|
|
|
modelAtomicResultMapper.delete(Wrappers.lambdaQuery(ModelAtomicResult.class)
|
|
|
.eq(ModelAtomicResult::getCaseId, caseId)
|
|
|
.eq(ModelAtomicResult::getCasePersonId, actorId)
|
|
|
.in(CollUtil.isNotEmpty(atomicIndexIds), ModelAtomicResult::getAtomicId, atomicIndexIds));
|
|
|
}
|
|
|
|
|
|
|
|
|
private Map<String, List<ModelIndex>> groupModelIndexByAtomicIndexId(List<ModelIndex> modelIndexList) {
|
|
|
Map<String, List<ModelIndex>> groupMap = new HashMap<>();
|
|
|
if (CollUtil.isEmpty(modelIndexList)) {
|
|
|
return groupMap;
|
|
|
}
|
|
|
for (ModelIndex modelIndex : modelIndexList) {
|
|
|
if (StrUtil.isEmpty(modelIndex.getJudgeLogic())) {
|
|
|
continue;
|
|
|
}
|
|
|
String judgeLogic = modelIndex.getJudgeLogic();
|
|
|
List<JudgeLogic> judgeLogicList = JSONUtil.toList(judgeLogic, JudgeLogic.class);
|
|
|
for (JudgeLogic logic : judgeLogicList) {
|
|
|
List<AtomicData> atomicData = logic.getAtomicData();
|
|
|
if (CollUtil.isEmpty(atomicData)) {
|
|
|
continue;
|
|
|
}
|
|
|
for (AtomicData atomic : atomicData) {
|
|
|
List<ModelIndex> modelIndexs = groupMap.getOrDefault(atomic.getAtomicIndex(), new ArrayList<>());
|
|
|
modelIndexs.add(modelIndex);
|
|
|
groupMap.put(atomic.getAtomicIndex(), modelIndexs);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return groupMap;
|
|
|
}
|
|
|
}
|
|
|
|