Forráskód Böngészése

动态环差演算

xyxie 1 éve
szülő
commit
6b1f994b1d

+ 72 - 0
controllers/base_from_predict.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_index_lib/logic"
 	"eta/eta_index_lib/models"
+	"eta/eta_index_lib/services"
 	"eta/eta_index_lib/utils"
 	"fmt"
 	"strconv"
@@ -183,3 +184,74 @@ func (this *PredictController) Refresh() {
 	br.Success = true
 	br.Msg = "获取成功"
 }
+
+// CalculateByNinePreview
+// @Title 动态环差演算
+// @Description 指标运算演算
+// @Param request body models.RuleConfig true "type json string"
+// @Success Ret=200 返回指标id
+// @router /calculate_by_nine/preview [post]
+func (this *PredictController) CalculateByNinePreview() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.RuleConfig
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	var errMsg string
+	// 获取计算参数
+	formula, edbInfoList, edbInfoIdBytes, err, errMsg := services.GetCalculateByRuleByNineParams(req)
+	if err != nil {
+		br.Msg = "计算失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.Msg = err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	// 获取计算数据
+	dataList, err := services.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes, req.EmptyType, req.MaxEmptyType)
+	if err != nil {
+		br.Msg = "数据计算失败"
+		br.ErrMsg = "数据计算失败:Err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+
+	latestDate := time.Now()
+	for _, v := range edbInfoList {
+		tmpLatestDate, err := time.ParseInLocation(utils.FormatDate, v.LatestDate, time.Local)
+		if err != nil {
+			continue
+		}
+		if tmpLatestDate.Before(latestDate) {
+			latestDate = tmpLatestDate
+		}
+	}
+
+	newDataList := make([]*models.EdbDataList, 0)
+	lenData := len(dataList)
+	if lenData > 0 {
+		for i := lenData - 1; i >= 0; i-- {
+			newDataList = append(newDataList, dataList[i])
+		}
+	}
+	resp := models.PredictRuleCalculateByNineResp{
+		LatestDate: latestDate.Format(utils.FormatDate),
+		DataList:   newDataList,
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 10 - 2
models/base_from_calculate.go

@@ -355,7 +355,7 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 	}
 
 	//数据处理,将日期内不全的数据做补全
-	handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
+	HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
 
 	formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
 	if err != nil {
@@ -654,7 +654,7 @@ func CheckFormula2(edbInfoArr []*EdbInfo, formulaMap map[string]string, formulaS
 }
 
 // 处理整个数据
-func handleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.Time, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*EdbInfo, emptyType int) {
+func HandleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.Time, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*EdbInfo, emptyType int) {
 	var startDate, endDate string
 	var startDateT, endDateT time.Time
 	if emptyType == 2 || emptyType == 3 {
@@ -737,6 +737,7 @@ func handleDateDataMap(realSaveDataMap, saveDataMap map[string]map[int]float64,
 			}
 			if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
 				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
 					saveDataMap[date][edbInfoId] = val
 					return
 				}
@@ -750,6 +751,7 @@ func handleDateDataMap(realSaveDataMap, saveDataMap map[string]map[int]float64,
 			}
 			if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
 				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
 					saveDataMap[date][edbInfoId] = val
 					return
 				}
@@ -866,3 +868,9 @@ func GetMaxMinEdbInfo(formula string) string {
 	formula = strings.ReplaceAll(formula, "min", "MIN")
 	return formula
 }
+
+// PredictRuleCalculateByNineResp 获取预测指标规则9的绘图数据返回
+type PredictRuleCalculateByNineResp struct {
+	LatestDate string
+	DataList   interface{}
+}

+ 1 - 1
models/base_predict_from_calculate.go

@@ -328,7 +328,7 @@ func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInf
 	}
 
 	//数据处理,将日期内不全的数据做填补
-	handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdList, emptyType)
+	HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdList, emptyType)
 
 	formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
 	if err != nil {

+ 1 - 1
models/predict_edb.go

@@ -109,7 +109,7 @@ func CalculateByRuleBy9(to orm.TxOrmer, rule CalculateRule) (resultDataList []*E
 	}
 
 	// todo 数据处理,将日期内不全的数据做填补
-	handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, rule.EdbInfoList, rule.EmptyType)
+	HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, rule.EdbInfoList, rule.EmptyType)
 
 	// 添加数据
 	addDataList := make([]*PredictEdbRuleData, 0)

+ 9 - 0
routers/commentsRouter.go

@@ -754,6 +754,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_index_lib/controllers:PredictController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:PredictController"],
+        beego.ControllerComments{
+            Method: "CalculateByNinePreview",
+            Router: `/calculate_by_nine/preview`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_index_lib/controllers:PredictController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:PredictController"],
         beego.ControllerComments{
             Method: "Refresh",

+ 234 - 0
services/base_from_predict.go

@@ -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
+}