package com.sundata.internalevaluation.calc.calcUnit; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import com.sundata.common.exception.BusinessException; import com.sundata.internalevaluation.calc.model.CalcException; import com.sundata.internalevaluation.calc.model.CalcResult; import com.sundata.internalevaluation.calc.model.CalcUnit; import com.sundata.internalevaluation.calc.model.finals.CalcType; import com.sundata.internalevaluation.calc.util.CalciteUtil; import com.sundata.internalevaluation.configuration.model.DataSetModel; import com.sundata.internalevaluation.configuration.model.IndexModel; import com.sundata.internalevaluation.configuration.model.IndexSourceModel; import com.sundata.internalevaluation.configuration.service.DataSetService; import com.sundata.internalevaluation.configuration.service.IndexConfigService; import com.sundata.internalevaluation.script.ScriptUtil; import com.sundata.internalevaluation.script.TemplateUtil; import org.apache.calcite.schema.impl.AbstractSchema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class IndexCalcUnit extends CalcUnit { private final IndexModel indexConfigModel; private static final Logger log = LoggerFactory.getLogger(IndexCalcUnit.class); // 接收表集 private Set tableSet = null; /** * 创建数据单元的绝对对象,对象必须包含如下参数 * * @param calcCode 计算对象编号 * @param calcName 计算对象名称 * @param initContext 计算单元初始化参数 */ public IndexCalcUnit(String calcCode, String calcName, Map initContext, IndexModel indexConfigModel) { super(calcCode, calcName, CalcType.INDEX, initContext); this.indexConfigModel = indexConfigModel; } /** * 判断是否已经计算过数据了 * * @param calculateInstanceNumber 计算流水号 * @return 是否计算过 true 计算过 false 没有计算过 */ @Override public boolean isCalcFinished(String calculateInstanceNumber) { // TODO 计算是否已经计算 return false; // return DataImages.indexCalcUnitHashMap.containsKey(calculateInstanceNumber) && DataImages.indexCalcUnitHashMap.get(calculateInstanceNumber).stream().anyMatch(a -> a.getCalcCode().equals(this.getCalcCode())); } /** * 初始化计算结果的方法,如果已经计算过,在实现过程中,应当在此方法中根据计算流水号重新初始化 resultContext 结果对象,为其他依赖对象做准备 * 若明明计算过本单元但再次计算时没有初始化该对象,则计算依赖出现问题无法定位与处理 * * @param calculateInstanceNumber 计算流水号 */ @Override public void initResultContext(String calculateInstanceNumber) { // TODO 初始化 // List indexCalcUnits = new ArrayList<>(); //// List indexCalcUnits = DataImages.indexCalcUnitHashMap.get(calculateInstanceNumber); // // 筛选并查找对象,如果找不到则报错 // if (indexCalcUnits.stream().noneMatch(a -> a.getCalcCode().equals(this.getCalcCode()))) { // throw new CalcException(calculateInstanceNumber, StrUtil.format("无法找到已计算完成的结果,计算单元编号:{},计算流水号为:{}。", this.getCalcCode(), calculateInstanceNumber)); // } // this.setResultContext(indexCalcUnits.stream().filter(a -> a.getCalcCode().equals(this.getCalcCode())).findFirst().get().getResultContext()); } /** * 根据节点配置获取源节点; * * @return 所有源头节点 */ @Override public List getSourceCalcUnits() { // TODO 获取源头节点 DataSetService dataSetService = SpringUtil.getBean(DataSetService.class); IndexConfigService indexConfigService = SpringUtil.getBean(IndexConfigService.class); List selectList = indexConfigService.getIndexSourceList(this.indexConfigModel); // 定义存放数据集和其他指标的集合 List indexList = new ArrayList<>(); List dataSetList = new ArrayList<>(); // 查询个指标编号和数据集对应的数据 for ( IndexSourceModel m : selectList) { if ("DATASET".equals(m.getDataSourceType())) { DataSetModel conditionModel = new DataSetModel(); conditionModel.setDataSetNo(m.getDataSetNo()); DataSetModel datasetModel = dataSetService.selectDetailData(conditionModel); dataSetList.add(datasetModel); } else if ("INDEX".equals(m.getDataSourceType())) { IndexModel conditionModel = new IndexModel(); conditionModel.setIndexNo(m.getOtherIndexNo()); IndexModel indexConfigModel = indexConfigService.selectDetailData(conditionModel); indexList.add(indexConfigModel); } } List indexCalcList = null; List dataSetCalcList = null; List resultCalcMap = new ArrayList<>(); // 数据源头节点生成 if (!indexList.isEmpty()) { indexCalcList = indexList.stream().map(indexConfigModel -> new IndexCalcUnit (indexConfigModel.getIndexNo(),indexConfigModel.getIndexName(),Map.of(),indexConfigModel)).collect(Collectors.toList()); } if (!dataSetList.isEmpty()) { dataSetCalcList = dataSetList.stream().map(dataSetModel -> new DataSetCalcUnit (dataSetModel.getDataSetNo(),dataSetModel.getDataSetName(),Map.of(),dataSetModel)).collect(Collectors.toList()); } // 结果封装 if (null != indexCalcList) { resultCalcMap.addAll(indexCalcList); } if (null != dataSetCalcList) { resultCalcMap.addAll(dataSetCalcList); } // 返回所有源头节点 return resultCalcMap; } /** * 计算之后的方法,可实现为空 * * @param context 计算参数过程数据 */ @Override public void afterCalc(Map context) { log.debug("计算之后的参数结构:{}",context); } /** * 计算之前,可实现空 * * @param context 计算参数过程数据 */ @Override public void beforeCalc(Map context) { log.debug("计算之前的参数结构:{}",context); } /** * 必须实现的主体计算内容 * * @param context 节点计算参数清单 * @param sourceResults 整个计算过程中的节点结果 */ @Override public void calc(final CalcResult thisResult, String calculateInstanceNumber, Map context, Map> sourceResults) { // log.info("当前计算节点为:[{}-{}-{}],计算流水号为:{}", this.getCalcType(), this.getCalcCode(), this.getCalcName(), calculateInstanceNumber); // TODO 实际的计算过程 // 记录数据集出现次数 AtomicInteger dataSetNumber = new AtomicInteger(); // 记录其他指标出现次数 AtomicInteger indexNumber = new AtomicInteger(); // 声明只存放指标源头节点变量 Map indexResult = new HashMap<>(); // 声明只存放所有数据集源头节点变量 Map dataSetResult = new HashMap<>(); // 遍历结果集 sourceResults.forEach((calcUnit,result) -> { // 数据集 if ( calcUnit instanceof DataSetCalcUnit dataSetCalcUnit){ if(dataSetCalcUnit.getCalcType() == CalcType.DATASET){ // 记录记过集次数 dataSetNumber.getAndIncrement(); // 将源头节点的返回值取出 // dataSetResult.putAll(result); String calcCode = calcUnit.getCalcCode(); Object schemeObj = result.get(calcCode); if (schemeObj instanceof AbstractSchema schema) { dataSetResult.put(calcCode,schema); } else { String errorMsg = StrUtil.format("数据集-[{}({})]-返回的计算结果不是AbstractSchema类型",calcUnit.getCalcName(),calcCode); log.error(errorMsg); throw new CalcException(errorMsg); } } } // 其他指标 if( calcUnit instanceof IndexCalcUnit indexCalcUnit){ if(indexCalcUnit.getCalcType() == CalcType.INDEX){ // 记录指标出现次数 indexNumber.getAndIncrement(); // 记录指标节点的返回值 indexResult.putAll(result); } } }); // 定义指标结果变量 Object indexCalcResult = null; // 获取指标计算逻辑 String calcLogic = indexConfigModel.getIndexLogic(); if (dataSetNumber.get() > 0 && indexNumber.get() == 0){ // 如果数据集的数量大于0(只依赖数据集) indexCalcResult = doExecuteSql(dataSetResult,calcLogic); } else if(dataSetNumber.get() == 0 && indexNumber.get() > 0){ // 如果指标的数量大于0(只依赖其他指标) // 执行公式,结果放入结果集 indexCalcResult = ScriptUtil.executeScript(indexConfigModel.getIndexNo(),calcLogic,indexResult); } else if (dataSetNumber.get() > 0 && indexNumber.get() >0) { // 同时具有指标和数据集 // 先将sql中指标公式替换掉,再将得到的sql执行 String editSql = TemplateUtil.execute(indexConfigModel.getIndexNo(),calcLogic,indexResult); // 执行拿结果 indexCalcResult = doExecuteSql(dataSetResult,editSql); } else { // 既不依赖其他指标,也不依赖数据集 // 执行公式,结果放入结果集 indexCalcResult = ScriptUtil.executeScript(indexConfigModel.getIndexNo(),calcLogic,indexResult); } // *********************** 处理指标结果为null的情况 if (null != indexCalcResult) { thisResult.put(this.getCalcCode(),indexCalcResult); } else { String defaultValueType = this.indexConfigModel.getDefaultValueType(); String defaultValue = this.indexConfigModel.getDefaultValue(); indexCalcResult = getDefaultValue(defaultValue,defaultValueType); thisResult.put(this.getCalcCode(),indexCalcResult); } } /** * 执行sql获取结果 * @param dataSetResult 数据集 * @param logic 指标计算逻辑 * @return 计算结果 */ private Object doExecuteSql(Map dataSetResult,String logic) { // 执行sql的工具类实例 CalciteUtil finalInstance; try { // 创建示例 CalciteUtil instance = CalciteUtil.getInstance(); // 添加域 dataSetResult.forEach(instance::addSchema); finalInstance = instance; } catch (SQLException e) { log.error(e.getMessage()); throw new BusinessException(e.getMessage(),e); } try { // 执行sql返回姐果 return finalInstance.doExecute(logic); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 获取默认值 * @param defaultValue 默认值 * @param defaultValueType 默认值类型 * @return 转化后值 */ private Object getDefaultValue(String defaultValue, String defaultValueType) { Object castValue = null; if (StrUtil.isNotBlank(defaultValue) && StrUtil.isNotBlank(defaultValueType)) { try { switch (defaultValueType) { case "INT": castValue = Convert.toInt(defaultValue); break; case "STRING": castValue = defaultValue; break; case "BOOLEAN": castValue = Convert.toBool(defaultValue); break; case "BIGDECIMAL": castValue = Convert.toBigDecimal(defaultValue); break; } if (null ==castValue) { String error = StrUtil.format("指标-[{}({})]-默认值转换失败,期望类型为[{}],待转换的值为[{}]。", getCalcName(),getCalcCode(),defaultValueType,defaultValue); log.error(error); throw new ClassCastException(error); } } catch (ClassCastException e) { throw new BusinessException(e.getMessage()); } } else { String error = StrUtil.format("指标-[{}({})]-计算结果为null,且未设置默认值类型或默认值。", getCalcName(),getCalcCode()); log.error(error); throw new BusinessException(error); } return castValue; } }