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/ModelIndexServiceImpl.java

454 lines
22 KiB
Java

10 months ago
package com.supervision.police.service.impl;
10 months ago
import cn.hutool.core.collection.CollUtil;
10 months ago
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ObjectUtil;
10 months ago
import cn.hutool.core.util.StrUtil;
10 months ago
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
10 months ago
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;
10 months ago
import com.supervision.common.domain.R;
import com.supervision.common.utils.IPages;
import com.supervision.common.utils.StringUtils;
10 months ago
import com.supervision.constant.DataStatus;
10 months ago
import com.supervision.police.domain.*;
import com.supervision.police.dto.*;
10 months ago
import com.supervision.police.mapper.CasePersonMapper;
10 months ago
import com.supervision.police.mapper.ModelAtomicResultMapper;
10 months ago
import com.supervision.police.mapper.ModelIndexMapper;
import com.supervision.police.service.*;
import com.supervision.police.vo.ModelIndexReqVO;
import com.supervision.utils.JudgeLogicUtil;
import com.supervision.utils.SqlParserUtil;
10 months ago
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
10 months ago
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
10 months ago
import java.util.*;
10 months ago
import java.util.stream.Collectors;
10 months ago
/**
* (ModelIndex)
*
* @author qmy
* @since 2024-07-05 09:20:10
*/
10 months ago
@Slf4j
10 months ago
@Service
10 months ago
@RequiredArgsConstructor
10 months ago
public class ModelIndexServiceImpl extends ServiceImpl<ModelIndexMapper, ModelIndex> implements ModelIndexService {
10 months ago
private final ComDictionaryService comDictionaryService;
10 months ago
10 months ago
private final ModelIndexMapper modelIndexMapper;
10 months ago
10 months ago
private final ModelAtomicIndexService modelAtomicIndexService;
10 months ago
10 months ago
private final ModelCaseService modelCaseService;
private final ModelAtomicResultMapper modelAtomicResultMapper;
10 months ago
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;
10 months ago
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
public R<?> selectAll(ModelIndexReqVO modelIndex, Integer page, Integer size) {
// 构建查询条件
10 months ago
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);
}
9 months ago
wrapper.orderBy(true, false, ModelIndex::getUpdateTime);
iPage = modelIndexMapper.selectPage(iPage, wrapper);
// 分页查询
10 months ago
List<ModelIndex> records = iPage.getRecords();
List<ComDictionary> dicts = comDictionaryService.list();
// 查询结果拼装
10 months ago
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();
List<String> ids = new ArrayList<>();
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());
}
}
10 months ago
List<ModelAtomicIndex> atomicIndexList = modelAtomicIndexService.selectBatchIds(ids);
10 months ago
index.setAtomicIndexList(atomicIndexList);
}
index.setAtomicIndexNum(ids.size());
}
iPage.setRecords(records);
return R.ok(IPages.buildDataMap(iPage));
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
public R<?> addOrUpd(ModelIndex modelIndex) {
int i = 0;
if (StringUtils.isEmpty(modelIndex.getId())) {
i = modelIndexMapper.insert(modelIndex);
modelIndexAtomicRelationService.saveByModelIndex(modelIndex);
10 months ago
} else {
i = modelIndexMapper.updateById(modelIndex);
modelIndexAtomicRelationService.updateByModelIndex(modelIndex);
10 months ago
}
if (i > 0) {
return R.okMsg("保存成功");
} else {
return R.fail("保存失败");
}
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
public R<?> del(String id) {
ModelIndex index = modelIndexMapper.selectById(id);
10 months ago
index.setDataStatus(DataStatus.NOT_AVAILABLE.getCode());
10 months ago
int i = modelIndexMapper.updateById(index);
if (i > 0) {
modelIndexAtomicRelationService.deleteByModelIndex(id);
10 months ago
return R.okMsg("删除成功");
} else {
return R.fail("删除失败");
}
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
public R<?> selectAllAtomic(ModelAtomicIndex modelAtomicIndex, Integer page, Integer size) {
IPage<ModelAtomicIndex> iPage = new Page<>(page, size);
iPage = modelAtomicIndexService.selectAll(iPage, modelAtomicIndex);
10 months ago
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));
10 months ago
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()));
10 months ago
}
iPage.setRecords(records);
return R.ok(IPages.buildDataMap(iPage));
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
public R<?> addOrUpdAtomic(ModelAtomicIndex modelAtomicIndex) {
saveAtomicIndexPreDo(modelAtomicIndex);
// 校验是否已经存在了相同名称的原子指标
10 months ago
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 RuntimeException("已存在相同名称的原子指标");
}
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_LLM, 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());
10 months ago
}
}
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
public R<?> delAtomic(String id) {
10 months ago
ModelAtomicIndex index = modelAtomicIndexService.getMapper().selectById(id);
10 months ago
index.setDataStatus(DataStatus.NOT_AVAILABLE.getCode());
10 months ago
int i = modelAtomicIndexService.getMapper().updateById(index);
10 months ago
if (i > 0) {
10 months ago
modelAtomicIndexService.whenDeleteAtomicIndex(index.getCaseType(), id);
10 months ago
return R.okMsg("删除成功");
} else {
return R.fail("删除失败");
}
}
10 months ago
@Override
@Transactional(transactionManager = "dataSourceTransactionManager", rollbackFor = Exception.class)
10 months ago
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, "案件类型不能为空");
10 months ago
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();
10 months ago
// 获取案件类型对应的指标
List<ModelIndex> modelIndexList = modelIndexMapper.selectList(
Wrappers.lambdaQuery(ModelIndex.class)
10 months ago
.eq(ModelIndex::getCaseType, caseType).eq(ModelIndex::getDataStatus, "1"));
if (CollUtil.isEmpty(modelIndexList)) {
10 months ago
return new ArrayList<>(1);
}
// 从指标中计算出所有原子指标id
9 months ago
List<String> atomicIndexIds = modelIndexList.stream().filter(modelIndex -> StrUtil.isNotEmpty(modelIndex.getJudgeLogic()))
.map(modelIndex -> JudgeLogicUtil.pickAtomicIndexIds(modelIndex.getJudgeLogic()))
10 months ago
.flatMap(Collection::stream).distinct().toList();
9 months ago
if (CollUtil.isEmpty(atomicIndexIds)) {
10 months ago
return new ArrayList<>(1);
}
// 查询原子指标相关信息
9 months ago
List<ModelAtomicIndex> modelAtomicIndexList = modelAtomicIndexService.listCaseAtomicIndex(atomicIndexIds, caseType, indexSource);
if (CollUtil.isEmpty(modelAtomicIndexList)) {
10 months ago
return new ArrayList<>(1);
}
// 查询判定结果数据
List<ModelAtomicResult> modelAtomicResults = modelAtomicResultMapper.selectList(
Wrappers.lambdaQuery(ModelAtomicResult.class).eq(ModelAtomicResult::getCaseId, caseId)
10 months ago
.eq(ModelAtomicResult::getCasePersonId, actorId)
9 months ago
.in(ModelAtomicResult::getAtomicId, atomicIndexIds));
10 months ago
9 months ago
Map<String, Map<String, List<ModelAtomicResult>>> modelAtomicResultGroup = modelAtomicResults.stream()
.filter(modelAtomicResult -> StrUtil.isNotEmpty(modelAtomicResult.getAtomicId()))
.collect(Collectors.groupingBy(ModelAtomicResult::getIndexId, Collectors.groupingBy(ModelAtomicResult::getAtomicId)));
10 months ago
Map<String, List<ModelIndex>> modelIndexMapAtomic = groupModelIndexByAtomicIndexId(modelIndexList);
// 以原子指标为基准,组装数据
return modelAtomicIndexList.stream().flatMap(atomicIndex ->
9 months ago
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())));
})
10 months ago
).toList();
10 months ago
}
@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, "案件不存在!");
10 months ago
// 设置行为人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");
// 保存原子评估结果
10 months ago
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) {
10 months ago
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.getDictionaryMapReverse("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;
}
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(dicMap.get(extractAttribute.getAttrValueType()));
valueCalculateScope.setValueTypeDesc(extractAttribute.getAttrValueType());
valueCalculateScope.setOperatorList(
IndexRuleConstants.VALUE_TYPE_OPERATOR_MAPPING.get(valueCalculateScope.getValueType()));
Map<String, String> map = IndexRuleConstants.VALUE_TYPE_AGGREGATE_MAPPING.get(valueCalculateScope.getValueType());
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));
}
10 months ago
private Map<String, List<ModelIndex>> groupModelIndexByAtomicIndexId(List<ModelIndex> modelIndexList) {
Map<String, List<ModelIndex>> groupMap = new HashMap<>();
if (CollUtil.isEmpty(modelIndexList)) {
10 months ago
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<>());
10 months ago
modelIndexs.add(modelIndex);
groupMap.put(atomic.getAtomicIndex(), modelIndexs);
}
}
}
return groupMap;
}
10 months ago
}