Browse Source

Merge branch 'feature/eta1.2.0_edb_calculate' of eta_server/eta_api into master

xyxie 1 year ago
parent
commit
b72c0dc6ab

+ 17 - 5
controllers/data_manage/edb_info_calculate.go

@@ -134,11 +134,19 @@ func (this *ChartInfoController) CalculateSave() {
 		formulaStr += v.FromTag + ","
 		edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
 	}
-	formulaMap := data.CheckFormula(req.CalculateFormula)
-	for _, v := range formulaMap {
-		if !strings.Contains(formulaStr, v) {
-			br.Msg = "公式错误,请重新填写"
-			return
+
+	formulaSlice, err := data.CheckFormulaJson(req.CalculateFormula)
+	if err != nil {
+		br.Msg = "公式格式错误,请重新填写"
+		return
+	}
+	for _, formula := range formulaSlice {
+		formulaMap := data.CheckFormula(formula)
+		for _, v := range formulaMap {
+			if !strings.Contains(formulaStr, v) {
+				br.Msg = "公式错误,请重新填写"
+				return
+			}
 		}
 	}
 
@@ -153,6 +161,8 @@ func (this *ChartInfoController) CalculateSave() {
 		ClassifyId:       req.ClassifyId,
 		CalculateFormula: req.CalculateFormula,
 		EdbInfoIdArr:     req.EdbInfoIdArr,
+		EmptyType:        req.EmptyType,
+		MaxEmptyType:     req.MaxEmptyType,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {
@@ -422,6 +432,8 @@ func (this *ChartInfoController) CalculateEdit() {
 		ClassifyId:       req.ClassifyId,
 		CalculateFormula: req.CalculateFormula,
 		EdbInfoIdArr:     req.EdbInfoIdArr,
+		EmptyType:        req.EmptyType,
+		MaxEmptyType:     req.MaxEmptyType,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {

+ 33 - 37
controllers/data_manage/predict_edb_info.go

@@ -913,6 +913,8 @@ func (this *PredictEdbInfoController) Detail() {
 				RuleType:         v.RuleType,
 				FixedValue:       v.FixedValue,
 				Value:            v.Value,
+				EmptyType:        v.EmptyType,
+				MaxEmptyType:     v.MaxEmptyType,
 				EndDate:          v.EndDate,
 				ModifyTime:       v.ModifyTime,
 				CreateTime:       v.CreateTime,
@@ -1485,7 +1487,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 		switch v.RuleType {
 		case 9:
 			// 获取计算参数
-			formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(v)
+			/*formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(v)
 			if err != nil {
 				br.Msg = "计算失败"
 				if errMsg != "" {
@@ -1496,13 +1498,26 @@ func (this *PredictEdbInfoController) ChartDataList() {
 				return
 			}
 			// 获取计算数据
-			tmpDataList, err = data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes)
+			tmpDataList, err = data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes, v.EmptyType, v.MaxEmptyType)
 			if err != nil {
 				br.Msg = "计算失败"
 				br.ErrMsg = err.Error()
 				br.IsSendEmail = false
 				return
+			}*/
+			reqJson, err := json.Marshal(v)
+			respItem, err := data.PredictCalculateByNinePreview(string(reqJson))
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取失败,Err:" + err.Error()
+				return
+			}
+			if respItem.Ret != 200 {
+				br.Msg = respItem.Msg
+				br.ErrMsg = respItem.ErrMsg
+				return
 			}
+			tmpDataList = respItem.Data.DataList
 		}
 		tmpPredictEdbConfAndData := data_manage.PredictEdbConfAndData{
 			ConfigId:         0,
@@ -1641,7 +1656,6 @@ func (this *PredictEdbInfoController) PredictRuleCalculateByNine() {
 		this.ServeJSON()
 	}()
 	sysUser := this.SysUser
-	time.Now().AddDate(0, -1, -1).Format(utils.FormatDate)
 	if sysUser == nil {
 		br.Msg = "请登录"
 		br.ErrMsg = "请登录,SysUser Is Empty"
@@ -1650,49 +1664,31 @@ func (this *PredictEdbInfoController) PredictRuleCalculateByNine() {
 	}
 	var req request.RuleConfig
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
-
-	// 获取计算参数
-	formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(req)
 	if err != nil {
-		br.Msg = "计算失败"
-		if errMsg != "" {
-			br.Msg = errMsg
-		}
-		br.Msg = err.Error()
-		br.IsSendEmail = false
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
-	// 获取计算数据
-	dataList, err := data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes)
+	// 添加计算指标
+	reqJson, err := json.Marshal(req)
 	if err != nil {
-		br.Msg = "数据计算失败"
-		br.ErrMsg = "数据计算失败:Err:" + err.Error()
-		br.IsSendEmail = false
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		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([]*data_manage.EdbDataList, 0)
-	lenData := len(dataList)
-	if lenData > 0 {
-		for i := lenData - 1; i >= 0; i-- {
-			newDataList = append(newDataList, dataList[i])
-		}
+	respItem, err := data.PredictCalculateByNinePreview(string(reqJson))
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
 	}
-	resp := response.PredictRuleCalculateByNineResp{
-		LatestDate: latestDate.Format(utils.FormatDate),
-		DataList:   newDataList,
+	if respItem.Ret != 200 {
+		br.Msg = respItem.Msg
+		br.ErrMsg = respItem.ErrMsg
+		return
 	}
+	resp := respItem.Data
 
 	br.Ret = 200
 	br.Success = true

+ 4 - 0
models/data_manage/edb_info.go

@@ -47,6 +47,8 @@ type EdbInfo struct {
 	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
 	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
 	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
+	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	TerminalCode     string  `description:"终端编码,用于配置在机器上"`
 	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
 	ErDataUpdateDate string  `description:"本次更新,数据发生变化的最早日期"`
@@ -313,6 +315,8 @@ type EdbInfoList struct {
 	IsEnEdb          bool                    `description:"是否展示英文标识"`
 	DataInsertConfig EdbDataInsertConfigItem `description:"指标数据插入配置"`
 	DataDateType     string                  `description:"数据日期类型,枚举值:交易日、自然日"`
+	EmptyType        int                     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	SubSource        int                     `description:"子数据来源:0:经济数据库,1:日期序列"`
 	SubSourceName    string                  `description:"子数据来源名称"`
 	IndicatorCode    string                  `description:"指标代码"`

+ 6 - 0
models/data_manage/edb_info_calculate.go

@@ -18,6 +18,8 @@ type EdbInfoCalculateSaveReq struct {
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
 	Calendar         string           `description:"公历/农历"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -107,6 +109,8 @@ type EdbInfoCalculateEditReq struct {
 	Unit             string           `description:"单位"`
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -200,6 +204,8 @@ type EdbInfoCalculateBatchSaveReqByEdbLib struct {
 	MoveFrequency    string           `description:"移动频度:天/周/月/季/年"`
 	Calendar         string           `description:"公历/农历"`
 	Data             interface{}      `description:"数据列"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 }
 
 // EdbInfoCalculateBatchEditReqByEdbLib 编辑计算指标的请求参数

+ 4 - 0
models/data_manage/predict_edb_conf.go

@@ -14,6 +14,8 @@ type PredictEdbConf struct {
 	RuleType         int       `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	FixedValue       float64   `description:"固定值"`
 	Value            string    `description:"配置的值"`
+	EmptyType        int       `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int       `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate          time.Time `description:"截止日期"`
 	ModifyTime       time.Time `description:"修改时间"`
 	CreateTime       time.Time `description:"添加时间"`
@@ -27,6 +29,8 @@ type PredictEdbConfDetail struct {
 	RuleType         int                                     `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	FixedValue       float64                                 `description:"固定值"`
 	Value            string                                  `description:"配置的值"`
+	EmptyType        int                                     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                                     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate          time.Time                               `description:"截止日期"`
 	ModifyTime       time.Time                               `description:"修改时间"`
 	CreateTime       time.Time                               `description:"添加时间"`

+ 2 - 0
models/data_manage/predict_edb_info_calculate.go

@@ -10,6 +10,8 @@ type PredictEdbInfoCalculateSaveReq struct {
 	Unit             string           `description:"单位"`
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 

+ 2 - 0
models/data_manage/request/predict_edb_info.go

@@ -42,6 +42,8 @@ type AddPredictEdbInfoReq struct {
 type RuleConfig struct {
 	RuleType     int                          `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	Value        string                       `description:"值"`
+	EmptyType    int                          `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType int                          `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate      string                       `description:"截止日期"`
 	EdbInfoIdArr []data_manage.EdbInfoFromTag `description:"指标信息"`
 }

+ 1 - 1
models/data_manage/response/predit_edb_info.go

@@ -46,5 +46,5 @@ type PredictEdbInfoChartDataResp struct {
 // PredictRuleCalculateByNineResp 获取预测指标规则9的绘图数据返回
 type PredictRuleCalculateByNineResp struct {
 	LatestDate string
-	DataList   interface{}
+	DataList   []*data_manage.EdbDataList
 }

+ 22 - 0
services/data/base_edb_lib.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/response"
 	"eta/eta_api/utils"
 	"fmt"
 	"io/ioutil"
@@ -131,6 +132,27 @@ func SaveBasePredictEdbData(edbInfoCalculateBatchSaveReqStr string) (resp *AddPr
 	return
 }
 
+type PredictRuleCalculateByNineRespResponse struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        response.PredictRuleCalculateByNineResp
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
+// PredictCalculateByNinePreview 预测指标动态环差演算
+func PredictCalculateByNinePreview(RuleConfigReqStr string) (resp *PredictRuleCalculateByNineRespResponse, err error) {
+	_, resultByte, err := postAddEdbData(RuleConfigReqStr, "predict/calculate_by_nine/preview")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
 // SavePredictEdbData 新增/编辑预测指标运算
 func SavePredictEdbData(edbInfoCalculateBatchSaveReqStr string) (resp *AddPredictEdbDataResponse, err error) {
 	_, resultByte, err := postAddEdbData(edbInfoCalculateBatchSaveReqStr, "predict_calculate/save")

+ 153 - 102
services/data/edb_info_calculate.go

@@ -9,13 +9,14 @@ import (
 	"github.com/shopspring/decimal"
 	"github.com/yidane/formula"
 	"math"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
 )
 
 func CheckFormula(formula string) map[string]string {
-	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}
+	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN", "EXP"}
 
 	str := strings.ToUpper(formula)
 	for _, v := range mathFormula {
@@ -37,22 +38,23 @@ func CheckFormula(formula string) map[string]string {
 	return byteMap
 }
 
-// CheckFormula2 校验公式是否正常(比如说除法的分母不能为0之类的,实际上就是用预设的字段数据做一次计算)
-func CheckFormula2(edbInfoArr []*data_manage.EdbInfo, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) (ok bool, err error) {
-	valArr := make(map[int]float64)
-	for _, v := range edbInfoArr {
-		valArr[v.EdbInfoId] = 100
-	}
-	formulaStr = strings.ToUpper(formulaStr)
-	formulaFormStr := ReplaceFormula(edbInfoArr, valArr, formulaMap, formulaStr, edbInfoIdBytes)
-	if formulaFormStr == "" {
+type FormulaListItem struct {
+	Formula string `json:"f"`
+	Date    string `json:"d"`
+}
+
+// CheckFormulaJson 检测计算公式json串是否异常
+func CheckFormulaJson(formula string) (formulaSlice []string, err error) {
+	list := make([]FormulaListItem, 0)
+	err = json.Unmarshal([]byte(formula), &list)
+	if err != nil {
+		err = fmt.Errorf("公式串解析失败: json.Unmarshal Err: %v", err)
 		return
 	}
-	expression := formula.NewExpression(formulaFormStr)
-	_, err = expression.Evaluate()
-	if err != nil {
-	} else {
-		ok = true
+	formulaSlice = make([]string, 0)
+	// 日期排序
+	for _, v := range list {
+		formulaSlice = append(formulaSlice, v.Formula)
 	}
 	return
 }
@@ -62,91 +64,8 @@ type CalculateItems struct {
 	DataMap   map[string]float64
 }
 
-func Calculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCode, formulaStr string, edbInfoIdBytes []string) (err error) {
-	defer func() {
-		if err != nil {
-			utils.FileLog.Info("Calculate Err:%s" + err.Error())
-		}
-	}()
-	saveDataMap := make(map[string]map[int]float64)
-	for _, v := range edbInfoIdArr {
-		var condition string
-		var pars []interface{}
-		condition += " AND edb_info_id=? "
-		pars = append(pars, v.EdbInfoId)
-		dataList, err := data_manage.GetEdbDataListAll(condition, pars, v.Source, v.SubSource, 1)
-		if err != nil {
-			return err
-		}
-		dataMap := make(map[string]float64)
-		for _, dv := range dataList {
-			if val, ok := saveDataMap[dv.DataTime]; ok {
-				if _, ok := val[v.EdbInfoId]; !ok {
-					val[v.EdbInfoId] = dv.Value
-				}
-			} else {
-				temp := make(map[int]float64)
-				temp[v.EdbInfoId] = dv.Value
-				saveDataMap[dv.DataTime] = temp
-			}
-		}
-		item := new(CalculateItems)
-		item.EdbInfoId = v.EdbInfoId
-		item.DataMap = dataMap
-	}
-	formulaMap := CheckFormula(formulaStr)
-	addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	nowStr := time.Now().Format(utils.FormatDateTime)
-	var isAdd bool
-	for sk, sv := range saveDataMap {
-		formulaStr = strings.ToUpper(formulaStr)
-		formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
-		if formulaStr == "" {
-			return
-		}
-		if formulaFormStr != "" {
-			expression := formula.NewExpression(formulaFormStr)
-			calResult, err := expression.Evaluate()
-			if err != nil {
-				err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
-				fmt.Println(err)
-				return err
-			}
-			calVal, err := calResult.Float64()
-			if err != nil {
-				err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
-				fmt.Println(err)
-				return err
-			}
-
-			//需要存入的数据
-			{
-				dataTime, _ := time.Parse(utils.FormatDate, sk)
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				addSql += "("
-				addSql += strconv.Itoa(edbInfoId) + "," + "'" + edbCode + "'" + "," + "'" + sk + "'" + "," + utils.SubFloatToString(calVal, 4) + "," + "'" + nowStr + "'" +
-					"," + "'" + nowStr + "'" + "," + "1"
-				addSql += "," + "'" + timeStr + "'"
-				addSql += "),"
-				isAdd = true
-			}
-		} else {
-			fmt.Println("formulaFormStr is empty")
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		data_manage.AddEdbDataCalculateBySql(addSql)
-		if err != nil {
-			fmt.Println("AddEdbDataCalculate Err:" + err.Error())
-			return err
-		}
-	}
-	return
-}
-
 func ReplaceFormula(edbInfoIdArr []*data_manage.EdbInfo, valArr map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) string {
+	// todo 处理min和max
 	funMap := GetFormulaMap()
 	for k, v := range funMap {
 		formulaStr = strings.Replace(formulaStr, k, v, -1)
@@ -548,7 +467,22 @@ func RefreshCalculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCod
 }
 
 // 处理整个数据
-func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo) {
+func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo, emptyType int) {
+	var startDate, endDate string
+	var startDateT, endDateT time.Time
+	if emptyType == 2 || emptyType == 3 {
+		for k, _ := range realSaveDataMap {
+			if k > endDate {
+				endDate = k
+			}
+			if k < startDate || startDate == "" {
+				startDate = k
+			}
+		}
+
+		startDateT, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		endDateT, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+	}
 	for _, date := range dateList {
 		tmpDataMap := realSaveDataMap[date]
 		for _, edbInfo := range edbInfoIdArr {
@@ -569,8 +503,16 @@ func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[s
 				//	day = 365
 				//}
 				// 需求池 255 指标运算文案修改,补数据遍历区间修改(2023-3-7 09:37:23修改)
-				day := 35
-				handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, day)
+				switch emptyType {
+				case 0:
+					handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, 35)
+				case 2:
+					handleDateDataMapBefore(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
+				case 3:
+					handleDateDataMapAfter(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
+				case 4:
+					handleDateDataMapZero(saveDataMap, date, tmpEdbInfoId)
+				}
 			}
 		}
 	}
@@ -711,3 +653,112 @@ func CallCalculateComputeCorrelation(data *data_manage.EdbInfoCalculateBatchSave
 
 	return
 }
+
+// handleDateDataMapBefore 前值填充:空值优先以最近的前值填充,没有前值时,用后值填充
+func handleDateDataMapBefore(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
+	currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
+
+	// 后一天
+	nextDateDay := currDate
+
+	// 前一天
+	preDateDay := currDate
+
+	for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
+		// 上个日期的数据
+		{
+			preDateDay = currDate.AddDate(0, 0, -i)
+			preDateDayStr := preDateDay.Format(utils.FormatDate)
+			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
+				}
+			}
+		}
+	}
+
+	for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
+		// 下个日期的数据
+		{
+			nextDateDay = currDate.AddDate(0, 0, i)
+			nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+			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
+				}
+			}
+		}
+	}
+	return
+}
+
+// handleDateDataMapAfter 后值填充:空值优先以最近的后值填充,没有后值时,用前值填充
+func handleDateDataMapAfter(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
+	currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
+
+	// 后一天
+	nextDateDay := currDate
+
+	// 前一天
+	preDateDay := currDate
+
+	for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
+		// 下个日期的数据
+		{
+			nextDateDay = currDate.AddDate(0, 0, i)
+			nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+			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
+				}
+			}
+		}
+	}
+
+	for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
+		// 上个日期的数据
+		{
+			preDateDay = currDate.AddDate(0, 0, -i)
+			preDateDayStr := preDateDay.Format(utils.FormatDate)
+			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
+				}
+			}
+		}
+	}
+	return
+}
+
+// handleDateDataMapZero 等于0
+func handleDateDataMapZero(saveDataMap map[string]map[int]float64, date string, edbInfoId int) {
+	saveDataMap[date][edbInfoId] = 0
+	return
+}
+
+func GetMaxMinEdbInfo(formula string) string {
+	//formula := "A+min(A,B,max(A,C))"
+	// todo 无法处理max里嵌套max或者min的情况
+	// 使用正则表达式匹配MAX和MIN函数及其参数
+	regex := regexp.MustCompile(`(?i)(MAX|MIN)\((.*?)\)`)
+	matches := regex.FindAllStringSubmatch(formula, -1)
+	// 遍历匹配结果,输出MAX和MIN函数及其参数
+	for _, match := range matches {
+		if len(match) == 3 {
+			parameter := strings.ToLower(match[0]) // 参数
+			formula = strings.ReplaceAll(formula, match[0], parameter)
+			fmt.Printf("formula: %s\n", formula)
+		}
+	}
+	formula = strings.ReplaceAll(formula, "max", "MAX")
+	formula = strings.ReplaceAll(formula, "min", "MIN")
+	return formula
+}

+ 0 - 154
services/data/predict_edb_info.go

@@ -9,7 +9,6 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/shopspring/decimal"
-	"github.com/yidane/formula"
 	"strconv"
 	"strings"
 	"time"
@@ -1127,159 +1126,6 @@ func GetPredictCalculateDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, s
 	return
 }
 
-// GetCalculateByRuleByNineParams 获取预测规则9的计算参数
-func GetCalculateByRuleByNineParams(req request.RuleConfig) (formula string, edbInfoList []*data_manage.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)
-	}
-	formulaMap := CheckFormula(formula)
-	for _, tmpFormula := range formulaMap {
-		if !strings.Contains(checkFormulaStr, tmpFormula) {
-			errMsg = "公式错误,请重新填写"
-			return
-		}
-	}
-
-	//关联的指标信息
-	edbInfoList = make([]*data_manage.EdbInfo, 0)
-
-	for _, tmpEdbInfoId := range req.EdbInfoIdArr {
-		fromEdbInfo, tmpErr := data_manage.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)
-	}
-	ok, _ := CheckFormula2(edbInfoList, formulaMap, formula, edbInfoIdBytes)
-	if !ok {
-		errMsg = "生成计算指标失败,请使用正确的计算公式"
-		err = errors.New(errMsg)
-	}
-	return
-}
-
-// CalculateByRuleByNine 动态环差规则计算入库
-func CalculateByRuleByNine(formulaStr string, edbInfoList []*data_manage.EdbInfo, edbInfoIdBytes []string) (dataList []*data_manage.EdbDataList, err error) {
-	realSaveDataMap := make(map[string]map[int]float64)
-	saveDataMap := make(map[string]map[int]float64)
-	dateList := make([]string, 0) //日期
-
-	formulaStr = strings.ToUpper(formulaStr)
-	// 获取关联指标数据
-	for edbInfoIndex, v := range edbInfoList {
-		sourceDataList, _, _, tmpErr, _ := GetPredictDataListByPredictEdbInfo(v, "", "", false)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		dataMap := make(map[string]float64)
-		for _, dv := range sourceDataList {
-			// 实际数据
-			if val, ok := realSaveDataMap[dv.DataTime]; ok {
-				if _, ok := val[v.EdbInfoId]; !ok {
-					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 _, ok := val[v.EdbInfoId]; !ok {
-					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)
-			}
-		}
-		item := new(CalculateItems)
-		item.EdbInfoId = v.EdbInfoId
-		item.DataMap = dataMap
-	}
-
-	//数据处理,将日期内不全的数据做补全
-	handleDateSaveDataMap(dateList, realSaveDataMap, saveDataMap, edbInfoList)
-
-	// 添加数据
-	dataList = make([]*data_manage.EdbDataList, 0)
-
-	// 计算规则
-	formulaMap := CheckFormula(formulaStr)
-
-	existDataMap := make(map[string]string)
-
-	for k, date := range dateList {
-		sv := saveDataMap[date]
-		//fmt.Println(date, sv)
-
-		formulaFormStr := ReplaceFormula(edbInfoList, sv, formulaMap, formulaStr, edbInfoIdBytes)
-		if formulaFormStr == `` {
-			//计算公式异常,那么就移除该指标
-			continue
-		}
-
-		//fmt.Println(fmt.Sprintf("formulaFormStr:%s", 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 := &data_manage.EdbDataList{
-				EdbDataId:     k,
-				EdbInfoId:     0,
-				DataTime:      date,
-				DataTimestamp: timestamp,
-				Value:         saveValue,
-			}
-			dataList = append(dataList, tmpPredictEdbRuleData)
-		}
-		existDataMap[date] = date
-	}
-	return
-}
-
 // ModifyPredictEdbBaseInfoBySourceEdb  根据来源ETA指标修改预测指标的基础信息
 func ModifyPredictEdbBaseInfoBySourceEdb(sourceEDdbInfo *data_manage.EdbInfo) {
 	list, err := data_manage.GetGroupPredictEdbBySourceEdbInfoId(sourceEDdbInfo.EdbInfoId)