|
@@ -1,20 +1,22 @@
|
|
|
package com.syjy.calculate.service;
|
|
|
|
|
|
-import com.alibaba.fastjson.JSONArray;
|
|
|
-import com.alibaba.fastjson.JSONObject;
|
|
|
import com.googlecode.aviator.AviatorEvaluator;
|
|
|
-import com.syjy.calculate.entity.CalculationFormula;
|
|
|
-import com.syjy.calculate.repository.CalculationFormulaRepository;
|
|
|
+import com.googlecode.aviator.Expression;
|
|
|
+import com.syjy.calculate.entity.CalculateResult;
|
|
|
+import com.syjy.calculate.entity.CalculationInfo;
|
|
|
+import com.syjy.calculate.entity.CalculateRequest;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
+import java.io.File;
|
|
|
+import java.io.IOException;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
|
/**
|
|
|
- * 计算准确率
|
|
|
+ * 计算准确率、合格率
|
|
|
*
|
|
|
* @author zcl
|
|
|
* @version 1.0
|
|
@@ -23,125 +25,57 @@ import java.util.Map;
|
|
|
@Service
|
|
|
@Slf4j
|
|
|
public class AccuracyPassRateCalculateService {
|
|
|
- BigDecimal ZERO = new BigDecimal("0");
|
|
|
- BigDecimal HUNDRED = new BigDecimal("100");
|
|
|
- String PASS = "PASS";
|
|
|
- @Autowired
|
|
|
- private CalculationFormulaRepository calculationFormulaRepository;
|
|
|
|
|
|
/**
|
|
|
- * @param powerData 功率相关数据 Map中必要字段:sj(实际功率)、yc(预测功率)
|
|
|
- * @param rl 容量
|
|
|
- * @param provinceEnum 省调
|
|
|
- * @param type 短期、超短期
|
|
|
- * @param compare 通过率对比系数
|
|
|
- * @return 返回Json result: true/false value: 99% msg:失败及原因
|
|
|
+ * 计算准确率、合格率
|
|
|
+ *
|
|
|
+ * @param calculateRequest
|
|
|
+ * @return
|
|
|
*/
|
|
|
- public JSONObject calculate(JSONArray powerData, BigDecimal rl, String provinceEnum, String type, BigDecimal compare) {
|
|
|
- JSONObject jsonResult = new JSONObject();
|
|
|
- jsonResult.put("result", false);
|
|
|
+ public CalculateResult calculate(CalculateRequest calculateRequest) {
|
|
|
// 对细则进行校验
|
|
|
- JSONObject checkedJson = checkDataRules(powerData, rl, provinceEnum, type);
|
|
|
+ CalculateResult checkedDataResult = checkDataRules(calculateRequest);
|
|
|
// 如果细则校验失败,返回细则结果
|
|
|
- if ("fail".equals(checkedJson.getString("result"))) {
|
|
|
- jsonResult.put("msg",checkedJson.getString("msg"));
|
|
|
- return jsonResult;
|
|
|
+ if (!String.valueOf(checkedDataResult.get(CalculateResult.CODE_TAG)).equals(CalculateResult.Type.SUCCESS.value())) {
|
|
|
+ return checkedDataResult;
|
|
|
}
|
|
|
// 获取细则校验过的数据
|
|
|
- JSONArray checkedPowerData = checkedJson.getJSONArray("powerData");
|
|
|
- // 根据类型从数据库中查出公式列表
|
|
|
- List<CalculationFormula> calculationFormulaList = calculationFormulaRepository.findByTypeAndProvince(type, provinceEnum, null);
|
|
|
- if (calculationFormulaList == null || calculationFormulaList.size() == 0) {
|
|
|
- jsonResult.put("msg", "计算失败,未匹配到公式");
|
|
|
- return jsonResult;
|
|
|
+ List<Map<String, Object>> checkedData = (List<Map<String, Object>>) checkedDataResult.get(CalculateResult.DATA_TAG);
|
|
|
+ // 获取jar包所在路径
|
|
|
+ String classPath = System.getProperty(CalculateResult.USER_DIR);
|
|
|
+ // 获取文件路径
|
|
|
+ String fileUrl = classPath + CalculateResult.SLASH + CalculateResult.EXAMPLES + CalculateResult.SLASH + calculateRequest.getProvince() + CalculateResult.UNDERLINE + calculateRequest.getFormulaType() + CalculateResult.UNDERLINE + calculateRequest.getElectricType() + CalculateResult.UNDERLINE + CalculateResult.FORMULA + CalculateResult.AV;
|
|
|
+ // 初始化公式并缓存公式
|
|
|
+
|
|
|
+ File file = new File(fileUrl);
|
|
|
+ // 判断公式文件是否存在
|
|
|
+ if (!file.exists()) {
|
|
|
+ // 未匹配到公式文件
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_NO_FORMULA + fileUrl);
|
|
|
}
|
|
|
- // 获取功率个数
|
|
|
- BigDecimal count = BigDecimal.valueOf(checkedPowerData.size());
|
|
|
- // 存放每步计算结果
|
|
|
- Map<String, Object> resultMap = new HashMap<>();
|
|
|
- // 公式
|
|
|
- String formula;
|
|
|
- // 循环公式,依次执行公式
|
|
|
- for (CalculationFormula calculationFormula : calculationFormulaList) {
|
|
|
- BigDecimal formulaResult = ZERO;
|
|
|
- // 获取公式
|
|
|
- formula = calculationFormula.getFormula();
|
|
|
- // 如果包含求和,则进行循环求和计算
|
|
|
- if (formula.contains("sum")) {
|
|
|
- // 获取sum后面的公式
|
|
|
- formula = formula.split(":")[1];
|
|
|
- // 循环执行sum后的公式
|
|
|
- for (int i = 0; i < checkedPowerData.size(); i++) {
|
|
|
- JSONObject dataJson = checkedPowerData.getJSONObject(i);
|
|
|
- // 将执行过的公式结果放入dataMap
|
|
|
- dataJson.putAll(resultMap);
|
|
|
- dataJson.put("rl", rl);
|
|
|
- dataJson.put("count", count);
|
|
|
- try {
|
|
|
- BigDecimal thisResult = new BigDecimal(String.valueOf(AviatorEvaluator.execute(formula, dataJson)));
|
|
|
- // 如果是通过率计算
|
|
|
- if (this.PASS.equals(type)) {
|
|
|
- // 如果对比系数是0,返回计算失败
|
|
|
- if (compare.compareTo(this.ZERO) == 0) {
|
|
|
- jsonResult.put("msg", "计算失败,通过率计算,对比系数不可为0");
|
|
|
- return jsonResult;
|
|
|
- }
|
|
|
- // 计算结果>=对比系数,则为100,否则为0
|
|
|
- if (thisResult.compareTo(compare) > -1) {
|
|
|
- thisResult = this.HUNDRED;
|
|
|
- } else {
|
|
|
- thisResult = this.ZERO;
|
|
|
- }
|
|
|
- }
|
|
|
- // 求和计算 AviatorEvaluator.execute(公式,公式中的参数及值(以Map形式存放))
|
|
|
- formulaResult = formulaResult.add(thisResult);
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- log.error("计算公式:" + formula + "错误:" + e.toString());
|
|
|
- jsonResult.put("msg", "计算失败" + "错误:" + e.toString());
|
|
|
- return jsonResult;
|
|
|
- }
|
|
|
- }
|
|
|
- // 非求和计算
|
|
|
- } else {
|
|
|
- if (checkedPowerData.size() > 0) {
|
|
|
- // 获取数据测试
|
|
|
- JSONObject dataJson = checkedPowerData.getJSONObject(0);
|
|
|
- // 将执行过的公式结果放入dataMap
|
|
|
- dataJson.putAll(resultMap);
|
|
|
- dataJson.put("rl", rl);
|
|
|
- dataJson.put("count", count);
|
|
|
- try {
|
|
|
- // 根据公式进行计算
|
|
|
- formulaResult = new BigDecimal(String.valueOf(AviatorEvaluator.execute(formula, dataJson)));
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("计算公式:" + formula + "错误:" + e.toString());
|
|
|
- e.printStackTrace();
|
|
|
- jsonResult.put("msg", "计算失败" + "错误:" + e.toString());
|
|
|
- return jsonResult;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- // 记录本次公式的计算结果
|
|
|
- resultMap.put("result" + calculationFormula.getOrderNo(), formulaResult);
|
|
|
- log.info("result" + calculationFormula.getOrderNo() + ":" + formulaResult);
|
|
|
+ Expression exp = null;
|
|
|
+ // 初始化公式文件
|
|
|
+ try {
|
|
|
+ exp = AviatorEvaluator.getInstance().compileScript(fileUrl, true);
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
}
|
|
|
- // 获取最后一个公式计算的结果
|
|
|
- String lastResult = String.valueOf(resultMap.get("result" + calculationFormulaList.size()));
|
|
|
- if (lastResult == null) {
|
|
|
- jsonResult.put("msg", "计算失败,结果为空");
|
|
|
- return jsonResult;
|
|
|
+ // 上下文
|
|
|
+ Map<String, Object> env = new HashMap<>();
|
|
|
+ // 将需要计算的list数据放入上下文
|
|
|
+ env.put(CalculateResult.LIST, checkedData);
|
|
|
+ env.put(CalculateResult.RL, calculateRequest.getCap());
|
|
|
+ // 执行计算并得出结果
|
|
|
+ try {
|
|
|
+ // 获取计算结果
|
|
|
+ BigDecimal executeResult = new BigDecimal(String.valueOf(exp.execute(env)));
|
|
|
+ // 过滤计算结果
|
|
|
+ String result = filterResult(executeResult);
|
|
|
+ return CalculateResult.success(CalculateResult.MSG_CALCULATE_SUCCESS, result);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_CALCULATE_FAIL + e.toString());
|
|
|
}
|
|
|
- log.info("最后一个公式计算的结果:" + lastResult);
|
|
|
- BigDecimal bResult = new BigDecimal(lastResult);
|
|
|
- bResult = bResult.setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
- // 过滤准确率
|
|
|
- bResult = filterResult(bResult);
|
|
|
- lastResult = bResult + "%";
|
|
|
- jsonResult.put("result", true);
|
|
|
- jsonResult.put("value", lastResult);
|
|
|
- log.info("准确率:" + lastResult);
|
|
|
- return jsonResult;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -150,71 +84,126 @@ public class AccuracyPassRateCalculateService {
|
|
|
* @param result 过滤前的结果
|
|
|
* @return 过滤后的结果
|
|
|
*/
|
|
|
- public BigDecimal filterResult(BigDecimal result) {
|
|
|
+ private String filterResult(BigDecimal result) {
|
|
|
//当结果为负数时,说明偏差过大,准确率为0
|
|
|
if (result.compareTo(BigDecimal.ZERO) == -1 || result.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
result = BigDecimal.ZERO;
|
|
|
}
|
|
|
// 如果结果大于1,则准确率设为100
|
|
|
- if (result.compareTo(this.HUNDRED) == 1) {
|
|
|
- result = this.HUNDRED;
|
|
|
+ if (result.compareTo(BigDecimal.ONE) == 1) {
|
|
|
+ result = BigDecimal.ONE;
|
|
|
}
|
|
|
- return result;
|
|
|
+ // 对数据*100
|
|
|
+ result = result.multiply(new BigDecimal(CalculateResult.ONE_HUNDRED));
|
|
|
+ // 对数据进行四舍五入
|
|
|
+ result = result.setScale(2, BigDecimal.ROUND_HALF_UP);
|
|
|
+ // 数据加上百分号
|
|
|
+ return result + CalculateResult.PERCENT;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 根据细则过滤数据
|
|
|
*
|
|
|
- * @param powerData
|
|
|
- * @param rl
|
|
|
- * @param provinceEnum
|
|
|
- * @param type
|
|
|
+ * @param calculateRequest
|
|
|
* @return
|
|
|
*/
|
|
|
- public JSONObject checkDataRules(JSONArray powerData, BigDecimal rl, String provinceEnum, String type) {
|
|
|
- JSONObject result = new JSONObject();
|
|
|
- result.put("result", "fail");
|
|
|
- // 获取细则公式
|
|
|
- List<CalculationFormula> rulesCalculationFormulaList = calculationFormulaRepository.findByTypeAndProvince(type, provinceEnum, null);
|
|
|
- // 如果没有细则公式,则不进行细则校验
|
|
|
- if (rulesCalculationFormulaList == null || rulesCalculationFormulaList.size() == 0) {
|
|
|
- result.put("result", "success");
|
|
|
- result.put("powerData", powerData);
|
|
|
- return result;
|
|
|
+ private CalculateResult checkDataRules(CalculateRequest calculateRequest) {
|
|
|
+ // 对入参进行校验
|
|
|
+ if (calculateRequest == null) {
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_REQUEST_NULL);
|
|
|
+ }
|
|
|
+ // 公式类型
|
|
|
+ String formulaType = calculateRequest.getFormulaType();
|
|
|
+ if ("".equals(formulaType) || formulaType == null) {
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_FORMULA_TYPE_NULL);
|
|
|
+ }
|
|
|
+ // 省调
|
|
|
+ String province = calculateRequest.getProvince();
|
|
|
+ if ("".equals(province) || province == null) {
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_PROVINCE_NULL);
|
|
|
+ }
|
|
|
+ // 场站类型
|
|
|
+ String electricType = calculateRequest.getElectricType();
|
|
|
+ if ("".equals(electricType) || electricType == null) {
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_ELECTRIC_TYPE_NULL);
|
|
|
+ }
|
|
|
+ // 获取被校验数据
|
|
|
+ List<CalculationInfo> calculationInfoList = calculateRequest.getCalculationInfoList();
|
|
|
+ // 计算数据为空
|
|
|
+ if (calculationInfoList == null || calculationInfoList.size() == 0) {
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_CALCULATE_DATA_NULL);
|
|
|
+ }
|
|
|
+ // 获取jar包所在路径
|
|
|
+ String classPath = System.getProperty(CalculateResult.USER_DIR);
|
|
|
+ // 获取文件路径
|
|
|
+ String fileUrl = classPath + CalculateResult.SLASH + CalculateResult.EXAMPLES + CalculateResult.SLASH + calculateRequest.getProvince() + CalculateResult.UNDERLINE + calculateRequest.getFormulaType() + CalculateResult.UNDERLINE + calculateRequest.getElectricType() + CalculateResult.UNDERLINE + CalculateResult.RULES + CalculateResult.AV;
|
|
|
+ // 获取文件
|
|
|
+ File file = new File(fileUrl);
|
|
|
+ // 将数据转为List Map 格式
|
|
|
+ List<Map<String, Object>> calculationInfoListMap = getCalculationInfoList(calculationInfoList);
|
|
|
+ // 判断公式文件是否存在
|
|
|
+ if (!file.exists()) {
|
|
|
+ // 未匹配到细则文件,则不进行细则校验,返回数据
|
|
|
+ return CalculateResult.success(calculationInfoListMap);
|
|
|
}
|
|
|
- JSONArray checkedArray = new JSONArray();
|
|
|
- JSONObject data = new JSONObject();
|
|
|
- String checkResult = "";
|
|
|
- // 循环功率信息
|
|
|
- for (int i = 0; i < powerData.size(); i++) {
|
|
|
- String checkFlag = "success";
|
|
|
- data = powerData.getJSONObject(i);
|
|
|
+ List<Map<String, Object>> passList = new ArrayList<>();
|
|
|
+ // 初始化细则校验文件
|
|
|
+ Expression exp = null;
|
|
|
+ try {
|
|
|
+ exp = AviatorEvaluator.getInstance().compileScript(fileUrl, true);
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ // 循环数据,对数据进行校验
|
|
|
+ for (Map<String, Object> calculationMap : calculationInfoListMap) {
|
|
|
// 循环公式,对每条功率信息进行细则处理
|
|
|
- for (CalculationFormula formula : rulesCalculationFormulaList) {
|
|
|
- try {
|
|
|
- checkResult = String.valueOf(AviatorEvaluator.execute(formula.getFormula(), data));
|
|
|
- if (!"pass".equals(checkResult)) {
|
|
|
- checkFlag = "fail";
|
|
|
+ try {
|
|
|
+ Map<String,Object> checkResult = (HashMap<String, Object>) exp.execute(calculationMap);
|
|
|
+ switch (String.valueOf(checkResult.get(CalculateResult.CODE_TAG))){
|
|
|
+ case CalculateResult.IGNORE :
|
|
|
break;
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
- log.error("计算公式:" + formula + "错误:" + e.toString());
|
|
|
- return result;
|
|
|
+ case CalculateResult.ERROR :
|
|
|
+ String resultValue = String.valueOf(checkResult.get(CalculateResult.MSG_TAG));
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_DATA_CHECK_ERROR,resultValue);
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (String.valueOf(checkResult.get(CalculateResult.CODE_TAG)).equals(CalculateResult.Type.SUCCESS.value())) {
|
|
|
+ break;
|
|
|
}
|
|
|
+ // 校验成功,将通过的数据放入passList
|
|
|
+ passList.add(calculationMap);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error(CalculateResult.MSG_DATA_CHECK_ERROR + e.toString());
|
|
|
+ return CalculateResult.error(CalculateResult.MSG_DATA_CHECK_ERROR);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 校验成功,返回待计算的数据
|
|
|
+ return CalculateResult.success(passList);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 格式化被校验数据
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<Map<String, Object>> getCalculationInfoList(List<CalculationInfo> calculationInfoList) {
|
|
|
+ List<Map<String, Object>> resultList = new ArrayList<>();
|
|
|
+ for (CalculationInfo calculationInfo : calculationInfoList) {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ map.put(CalculateResult.SJ, calculationInfo.getSj());
|
|
|
+ map.put(CalculateResult.YC, calculationInfo.getYc());
|
|
|
+ // 如果容量不为空,放入容量字段
|
|
|
+ if (calculationInfo.getRl() != null) {
|
|
|
+ map.put(CalculateResult.RL, calculationInfo.getRl());
|
|
|
}
|
|
|
- // 如果循环所有规则后还是success,则此条数据校验通过,放入list中
|
|
|
- if ("success".equals(checkFlag)) {
|
|
|
- checkedArray.add(data);
|
|
|
- // 如果没通过,且为单点数据,则返回细则结果
|
|
|
- } else if (powerData.size() == 1) {
|
|
|
- result.put("msg", checkResult);
|
|
|
- return result;
|
|
|
+ // 如果时间不为空,放入时间字段
|
|
|
+ if (calculationInfo.getTime() != 0) {
|
|
|
+ map.put(CalculateResult.TIME, calculationInfo.getTime());
|
|
|
}
|
|
|
+ resultList.add(map);
|
|
|
}
|
|
|
- result.put("result", "success");
|
|
|
- result.put("powerData", checkedArray);
|
|
|
- return result;
|
|
|
+ return resultList;
|
|
|
}
|
|
|
|
|
|
}
|