|
@@ -0,0 +1,234 @@
|
|
|
|
+package services
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "errors"
|
|
|
|
+ "eta/eta_index_lib/models"
|
|
|
|
+ "eta/eta_index_lib/utils"
|
|
|
|
+ "fmt"
|
|
|
|
+ "github.com/shopspring/decimal"
|
|
|
|
+ "github.com/yidane/formula"
|
|
|
|
+ "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 := utils.CheckFormula(f)
|
|
|
|
+ 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 := utils.CheckFormula(v)
|
|
|
|
+ //预先计算,判断公式是否正常
|
|
|
|
+ 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)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ 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, maxStartDate.Format(utils.FormatDate))
|
|
|
|
+ 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 = utils.CheckFormula(formulaStr)
|
|
|
|
+ }
|
|
|
|
+ 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, 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
|
|
|
|
+}
|