package services import ( "errors" "eta/eta_index_lib/models" "eta/eta_index_lib/utils" "fmt" "github.com/dengsgo/math-engine/engine" "github.com/shopspring/decimal" "strconv" "strings" "time" ) // GetCalculateByRuleByNineParams 获取预测规则9的计算参数 func GetCalculateByRuleByNineParams(req models.RuleConfig) (formula string, edbInfoList []*models.EdbInfo, edbInfoIdBytes []string, err error, errMsg string) { formula = req.Value formula = strings.Replace(formula, "(", "(", -1) formula = strings.Replace(formula, ")", ")", -1) formula = strings.Replace(formula, ",", ",", -1) formula = strings.Replace(formula, "。", ".", -1) formula = strings.Replace(formula, "%", "*0.01", -1) //检验公式 var checkFormulaStr string for _, tmpEdbInfoId := range req.EdbInfoIdArr { checkFormulaStr += tmpEdbInfoId.FromTag + "," edbInfoIdBytes = append(edbInfoIdBytes, tmpEdbInfoId.FromTag) } formulaSlice, err := utils.CheckFormulaJson(formula) if err != nil { errMsg = "公式格式错误,请重新填写" err = errors.New(errMsg) return } for _, f := range formulaSlice { formulaMap, e := utils.CheckFormula(f) if e != nil { err = fmt.Errorf("公式错误,请重新填写") return } for _, v := range formulaMap { if !strings.Contains(checkFormulaStr, v) { errMsg = "公式错误,请重新填写" err = errors.New(errMsg) return } } } //关联的指标信息 edbInfoList = make([]*models.EdbInfo, 0) for _, tmpEdbInfoId := range req.EdbInfoIdArr { fromEdbInfo, tmpErr := models.GetEdbInfoById(tmpEdbInfoId.EdbInfoId) if tmpErr != nil { if tmpErr.Error() == utils.ErrNoRow() { err = errors.New("指标 " + strconv.Itoa(tmpEdbInfoId.EdbInfoId) + " 不存在") } else { err = errors.New("获取指标失败:Err:" + tmpErr.Error()) } errMsg = "数据计算失败" return } edbInfoList = append(edbInfoList, fromEdbInfo) } for _, v := range formulaSlice { formulaMap, e := utils.CheckFormula(v) if e != nil { err = fmt.Errorf("公式错误,请重新填写") return } //预先计算,判断公式是否正常 ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes) if !ok { errMsg = "生成计算指标失败,请使用正确的计算公式" err = errors.New(errMsg) return } } return } // CalculateByRuleByNine 动态环差规则计算入库 func CalculateByRuleByNine(formulaStr string, edbInfoList []*models.EdbInfo, edbInfoIdBytes []string, emptyType, maxEmptyType int) (dataList []*models.EdbDataList, err error) { realSaveDataMap := make(map[string]map[int]float64) saveDataMap := make(map[string]map[int]float64) dateList := make([]string, 0) //日期 // 最小的结束日期 , 最晚的数据开始日期 var minLatestDate, maxStartDate time.Time formulaStr = strings.ToUpper(formulaStr) // 获取关联指标数据 for edbInfoIndex, v := range edbInfoList { // todo eta_api和eta_index_lib两个函数的逻辑不一致 sourceDataList, tmpErr := models.GetPredictEdbDataListAll(v, 1) if tmpErr != nil { err = tmpErr return } dataMap := make(map[string]float64) //lenData := len(sourceDataList) for _, dv := range sourceDataList { // 实际数据 if val, ok := realSaveDataMap[dv.DataTime]; ok { if _, ok1 := val[v.EdbInfoId]; !ok1 { val[v.EdbInfoId] = dv.Value } } else { temp := make(map[int]float64) temp[v.EdbInfoId] = dv.Value realSaveDataMap[dv.DataTime] = temp } // saveDataMap 待计算的数据 if val, ok := saveDataMap[dv.DataTime]; ok { if _, ok1 := val[v.EdbInfoId]; !ok1 { val[v.EdbInfoId] = dv.Value } } else { temp2 := make(map[int]float64) temp2[v.EdbInfoId] = dv.Value saveDataMap[dv.DataTime] = temp2 } // 以第一个指标的日期作为基准日期 if edbInfoIndex == 0 { dateList = append(dateList, dv.DataTime) tmpDate, _ := time.ParseInLocation(utils.FormatDate, dv.DataTime, time.Local) if minLatestDate.IsZero() || tmpDate.After(minLatestDate) { minLatestDate = tmpDate } if maxStartDate.IsZero() || tmpDate.Before(maxStartDate) { maxStartDate = tmpDate } } /* if lenData > 0 { tmpLatestDate, _ := time.ParseInLocation(utils.FormatDate, sourceDataList[lenData-1].DataTime, time.Local) if minLatestDate.IsZero() || minLatestDate.After(tmpLatestDate) { minLatestDate = tmpLatestDate } tmpStartDate, _ := time.ParseInLocation(utils.FormatDate, sourceDataList[0].DataTime, time.Local) if maxStartDate.IsZero() || maxStartDate.Before(tmpStartDate) { maxStartDate = tmpStartDate } }*/ } item := new(models.CalculateItems) item.EdbInfoId = v.EdbInfoId item.DataMap = dataMap } models.HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoList, emptyType) // 添加数据 dataList = make([]*models.EdbDataList, 0) // 计算规则 formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, minLatestDate) if err != nil { return } existDataMap := make(map[string]string) // 判断是否特殊处理max和min函数 maxDealFlag := false if emptyType == 4 && maxEmptyType == 2 { maxDealFlag = true } for k, date := range dateList { sv := saveDataMap[date] // 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值 if emptyType == 1 { if len(sv) != len(edbInfoList) { continue } } //fmt.Println(sk, sv) // 根据时间范围,选择对应的公式 formulaMap := make(map[string]string) formulaStr = "" for _, fv := range formulaDateSlice { if date < fv { if f, ok := formulaDateMap[fv]; ok { formulaStr = f formulaMap, err = utils.CheckFormula(formulaStr) if err != nil { err = fmt.Errorf("公式错误,请重新填写") return } } break } } if formulaStr == "" { continue } svMax := make(map[int]float64) if maxDealFlag { // 特殊处理max和min函数,如果原本的值为空,则选择空值参与运算 if svMaxData, ok := realSaveDataMap[date]; ok { svMax = svMaxData } } //fmt.Println(date, sv) formulaFormStr := models.ReplaceFormula(edbInfoList, sv, svMax, formulaMap, formulaStr, edbInfoIdBytes, maxDealFlag) if formulaFormStr == `` { //计算公式异常,那么就移除该指标 continue } //fmt.Println(fmt.Sprintf("formulaFormStr:%s", formulaFormStr)) fmt.Println(fmt.Sprintf("%s:formulaFormStr:%s", date, formulaFormStr)) //expression := formula.NewExpression(formulaFormStr) //calResult, tmpErr := expression.Evaluate() //if tmpErr != nil { // // 分母为0的报错 // if strings.Contains(tmpErr.Error(), "divide by zero") { // continue // } // err = errors.New("计算失败:Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr) // return //} calVal, err := engine.ParseAndExec(formulaFormStr) //calVal, err := calResult.Float64() if err != nil { err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr) fmt.Println(err) return nil, err } //nanCheck := fmt.Sprintf("%0.f", calVal) //calVal, tmpErr := calResult.Float64() //if tmpErr != nil { // err = errors.New("计算失败:获取计算值失败 Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr) // fmt.Println(err) // return //} saveValue, _ := decimal.NewFromFloat(calVal).RoundCeil(4).Float64() //utils.SubFloatToString(calVal, 4) dataTime, _ := time.Parse(utils.FormatDate, date) timestamp := dataTime.UnixNano() / 1e6 if _, existOk := existDataMap[date]; !existOk { tmpPredictEdbRuleData := &models.EdbDataList{ EdbDataId: k, EdbInfoId: 0, DataTime: date, DataTimestamp: timestamp, Value: saveValue, } dataList = append(dataList, tmpPredictEdbRuleData) } existDataMap[date] = date } return }