Ver Fonte

添加指标运算时,增加空值处理类型

xyxie há 1 ano atrás
pai
commit
4d138e0fd3

+ 39 - 18
controllers/base_from_calculate.go

@@ -139,11 +139,18 @@ func (this *CalculateController) Add() {
 		formulaStr += v.FromTag + ","
 		edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
 	}
-	formulaMap := utils.CheckFormula(req.CalculateFormula)
-	for _, v := range formulaMap {
-		if !strings.Contains(formulaStr, v) {
-			br.Msg = "公式错误,请重新填写"
-			return
+	formulaSlice, err := utils.CheckFormulaJson(req.CalculateFormula)
+	if err != nil {
+		br.Msg = "公式格式错误,请重新填写"
+		return
+	}
+	for _, formula := range formulaSlice {
+		formulaMap := utils.CheckFormula(formula)
+		for _, v := range formulaMap {
+			if !strings.Contains(formulaStr, v) {
+				br.Msg = "公式错误,请重新填写"
+				return
+			}
 		}
 	}
 
@@ -188,10 +195,15 @@ func (this *CalculateController) Add() {
 			calculateMappingList = append(calculateMappingList, calculateMappingItem)
 		}
 	}
-	ok, _ := models.CheckFormula2(edbInfoList, formulaMap, calculateFormula, edbInfoIdBytes)
-	if !ok {
-		br.Msg = "生成计算指标失败,请使用正确的计算公式"
-		return
+
+	for _, v := range formulaSlice {
+		formulaMap := utils.CheckFormula(v)
+		//预先计算,判断公式是否正常
+		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
+		if !ok {
+			br.Msg = "生成计算指标失败,请使用正确的计算公式"
+			return
+		}
 	}
 
 	randStr := utils.GetRandDigit(4)
@@ -298,10 +310,12 @@ func (this *CalculateController) Edit() {
 	}
 
 	if req.CalculateFormula == "" {
-		br.Msg = "请填写指标"
+		br.Msg = "请填写指标公式"
 		return
 	}
 
+	//todo 校验空值类型,max、min空值类型
+
 	calculateFormula := req.CalculateFormula
 	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
 	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
@@ -371,7 +385,7 @@ func (this *CalculateController) Edit() {
 	}
 	var needCalculate bool
 
-	if edbInfoDetail.CalculateFormula != req.CalculateFormula {
+	if edbInfoDetail.CalculateFormula != req.CalculateFormula || edbInfoDetail.EmptyType != req.EmptyType || edbInfoDetail.MaxEmptyType != req.MaxEmptyType {
 		needCalculate = true
 	}
 
@@ -403,16 +417,23 @@ func (this *CalculateController) Edit() {
 		}
 	}
 
-	formulaMap := utils.CheckFormula(req.CalculateFormula)
-	for _, v := range formulaMap {
-		if !strings.Contains(formulaStr, v) {
-			br.Msg = "公式错误,请重新填写"
-			return
+	formulaSlice, err := utils.CheckFormulaJson(req.CalculateFormula)
+	if err != nil {
+		br.Msg = "公式格式错误,请重新填写"
+		return
+	}
+	for _, formula := range formulaSlice {
+		formulaMap := utils.CheckFormula(formula)
+		for _, v := range formulaMap {
+			if !strings.Contains(formulaStr, v) {
+				br.Msg = "公式错误,请重新填写"
+				return
+			}
 		}
 	}
 
 	//重新计算
-	err, errMsg := models.EditCalculateInfo(edbInfoDetail, req, formulaMap, edbInfoIdBytes, needCalculate)
+	err, errMsg := models.EditCalculateInfo(edbInfoDetail, req, formulaSlice, edbInfoIdBytes, needCalculate)
 	if err != nil {
 		br.Msg = "生成计算指标失败"
 		if errMsg != `` {
@@ -1405,7 +1426,7 @@ func (this *CalculateController) Refresh() {
 			edbInfo, _ := models.GetEdbInfoById(v.FromEdbInfoId)
 			edbInfoList = append(edbInfoList, edbInfo)
 		}
-		err = models.RefreshAllCalculate(edbInfoList, edbInfo.EdbInfoId, source, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, endDate, edbInfoIdBytes, edbInfo.EmptyType)
+		err = models.RefreshAllCalculate(edbInfoList, edbInfo.EdbInfoId, source, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, endDate, edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
 		if err != nil && err.Error() != utils.ErrNoRow() {
 			errMsg = "RefreshCalculate Err:" + err.Error()
 			break

+ 1 - 1
controllers/base_from_predict_calculate.go

@@ -953,7 +953,7 @@ func (this *PredictCalculateController) Refresh() {
 			edbInfo, _ := models.GetEdbInfoById(v.FromEdbInfoId)
 			edbInfoList = append(edbInfoList, edbInfo)
 		}
-		latestDateStr, latestValue, err = models.RefreshAllPredictCalculate(edbInfoList, edbInfo.EdbInfoId, source, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, edbInfoIdBytes, edbInfo.EmptyType)
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculate(edbInfoList, edbInfo.EdbInfoId, source, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
 		if err != nil && err.Error() != utils.ErrNoRow() {
 			errMsg = "RefreshCalculate Err:" + err.Error()
 			break

+ 85 - 122
models/base_from_calculate.go

@@ -24,6 +24,7 @@ type EdbInfoCalculateSaveReq struct {
 	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
 }
 
@@ -39,92 +40,6 @@ type CalculateItems struct {
 	DataMap   map[string]float64
 }
 
-// AddCalculate 新增计算(运算)指标
-func AddCalculate(edbInfoIdArr []*EdbInfo, edbInfoId int, edbCode, formulaStr string, edbInfoIdBytes []string) (err error) {
-	o := orm.NewOrm()
-	defer func() {
-		if err != nil {
-			utils.FileLog.Info(fmt.Sprintf("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 := GetEdbDataListAll(condition, pars, v.Source, 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 := utils.CheckFormula(formulaStr)
-	addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,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.ParseInLocation(utils.FormatDate, sk, time.Local)
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				addSql += "("
-				addSql += strconv.Itoa(edbInfoId) + "," + "'" + edbCode + "'" + "," + "'" + sk + "'" + "," + utils.SubFloatToString(calVal, 4) + "," + "'" + nowStr + "'" +
-					"," + "'" + nowStr + "'" + "," + "'" + timeStr + "'"
-				addSql += "),"
-				isAdd = true
-			}
-		} else {
-			fmt.Println("formulaFormStr is empty")
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = o.Raw(addSql).Exec()
-		if err != nil {
-			fmt.Println("AddEdbDataCalculate Err:" + err.Error())
-			//errMsg = " tx.Exec Err :" + err.Error()
-			return
-		}
-	}
-	return
-}
-
 // AddCalculateInfo 新增计算(运算)指标
 func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbInfoCalculateMapping, edbInfoList []*EdbInfo, edbCode, uniqueCode string, edbInfoIdBytes []string) (edbInfo *EdbInfo, err error) {
 
@@ -175,6 +90,7 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
 		LatestValue:      0,
 		ChartImage:       "",
 		EmptyType:        req.EmptyType,
+		MaxEmptyType:     req.MaxEmptyType,
 	}
 	lastId, err := to.Insert(edbInfo)
 	if err != nil {
@@ -197,13 +113,13 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
 	}
 
 	//计算数据
-	err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType)
+	err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
 
 	return
 }
 
 // EditCalculateInfo 编辑计算(运算)指标
-func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap map[string]string, edbInfoIdBytes []string, needCalculate bool) (err error, errMsg string) {
+func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaSlice []string, edbInfoIdBytes []string, needCalculate bool) (err error, errMsg string) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
 	if err != nil {
@@ -227,7 +143,8 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap
 	edbInfo.CalculateFormula = req.CalculateFormula
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.EmptyType = req.EmptyType
-	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EmptyType")
+	edbInfo.MaxEmptyType = req.MaxEmptyType
+	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EmptyType", "MaxEmptyType")
 	if err != nil {
 		return
 	}
@@ -278,12 +195,15 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap
 			}
 		}
 
-		//预先计算,判断公式是否正常
-		ok, _ := CheckFormula2(edbInfoList, formulaMap, req.CalculateFormula, edbInfoIdBytes)
-		if !ok {
-			errMsg = "生成计算指标失败,请使用正确的计算公式"
-			err = errors.New(errMsg)
-			return
+		for _, v := range formulaSlice {
+			formulaMap := utils.CheckFormula(v)
+			//预先计算,判断公式是否正常
+			ok, _ := CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
+			if !ok {
+				errMsg = "生成计算指标失败,请使用正确的计算公式"
+				err = errors.New(errMsg)
+				return
+			}
 		}
 
 		//关联关系表
@@ -297,7 +217,7 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap
 		}
 
 		//计算数据
-		err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType)
+		err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
 
 	}
 
@@ -341,7 +261,7 @@ func DeleteCalculateEdbInfo(edbInfoId int) (err error) {
 }
 
 // RefreshAllCalculate 刷新全部数据
-func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType int) (err error) {
+func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
 	if err != nil {
@@ -358,13 +278,13 @@ func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode
 	fmt.Println(startDate, endDate)
 
 	//计算数据
-	err = refreshAllCalculate(to, edbInfoIdArr, edbInfoId, source, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes, emptyType)
+	err = refreshAllCalculate(to, edbInfoIdArr, edbInfoId, source, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes, emptyType, maxEmptyType)
 
 	return
 }
 
 // refreshAllCalculate 刷新全部数据
-func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType int) (err error) {
+func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (err error) {
 	realSaveDataMap := make(map[string]map[int]float64)
 	saveDataMap := make(map[string]map[int]float64)
 
@@ -437,7 +357,7 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 	//数据处理,将日期内不全的数据做补全
 	handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
 
-	formulaDateSlice, formulaDateMap, err := utils.CheckFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
+	formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
 	if err != nil {
 		return
 	}
@@ -462,6 +382,12 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 	}
 	edbInfoIdStr := strconv.Itoa(edbInfoId)
 	existDataMap := make(map[string]string)
+
+	// 判断是否特殊处理max和min函数
+	maxDealFlag := false
+	if emptyType == 4 && maxEmptyType == 2 {
+		maxDealFlag = true
+	}
 	for sk, sv := range saveDataMap {
 		// 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值
 		if emptyType == 1 {
@@ -485,8 +411,15 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 		if formulaStr == "" {
 			continue
 		}
+		svMax := make(map[int]float64)
+		if maxDealFlag {
+			// 特殊处理max和min函数,如果原本的值为空,则选择空值参与运算
+			if svMaxData, ok := realSaveDataMap[sk]; ok {
+				svMax = svMaxData
+			}
+		}
 		formulaStr = strings.ToUpper(formulaStr)
-		formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
+		formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, svMax, formulaMap, formulaStr, edbInfoIdBytes, maxDealFlag)
 		//计算公式异常,那么就移除该指标
 		if formulaFormStr == `` {
 			//removeDateList = append(removeDateList, sk)
@@ -579,7 +512,12 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 }
 
 // ReplaceFormula 替换计算方式
-func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) string {
+func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr, valArrMax map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string, maxDealFlag bool) string {
+	// todo 先处理max和min函数的特殊情况
+	//if strings.Contains(formulaStr, "MAX") || strings.Contains(formulaStr, "MIN") {
+	if maxDealFlag {
+		formulaStr = GetMaxMinEdbInfo(formulaStr)
+	}
 	funMap := GetFormulaMap()
 	for k, v := range funMap {
 		formulaStr = strings.Replace(formulaStr, k, v, -1)
@@ -587,7 +525,7 @@ func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr map[int]float64, formulaMap
 	replaceCount := 0
 	for dk, dv := range edbInfoIdArr {
 		var isReplace bool
-		formulaStr, isReplace = GetFormulaReplace(dk, dv.EdbInfoId, formulaStr, edbInfoIdBytes, formulaMap, valArr)
+		formulaStr, isReplace = GetFormulaReplace(dk, dv.EdbInfoId, formulaStr, edbInfoIdBytes, formulaMap, valArr, valArrMax, maxDealFlag)
 		if isReplace {
 			replaceCount++
 		}
@@ -595,6 +533,9 @@ func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr map[int]float64, formulaMap
 	for k, v := range funMap {
 		formulaStr = strings.Replace(formulaStr, v, k, -1)
 	}
+	if strings.Contains(formulaStr, "MAX()") || strings.Contains(formulaStr, "MIN()") {
+		return ""
+	}
 	if replaceCount == len(formulaMap) {
 		return formulaStr
 	} else {
@@ -602,18 +543,23 @@ func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr map[int]float64, formulaMap
 	}
 }
 
-func GetFormulaReplace(index, edbInfoId int, formulaStr string, edbInfoIdBytes []string, formulaMap map[string]string, valArr map[int]float64) (formulaResult string, isReplace bool) {
-	// todo 获取原本的值
-	valArrMax := make(map[int]float64)
-
+func GetFormulaReplace(index, edbInfoId int, formulaStr string, edbInfoIdBytes []string, formulaMap map[string]string, valArr, valArrMax map[int]float64, maxDealFlag bool) (formulaResult string, isReplace bool) {
 	formulaResult = formulaStr
 	dKey := edbInfoIdBytes[index]
 	if _, ok := formulaMap[dKey]; ok { //公式中存在
-		// todo 判断公式中存在max、min,如果存在,则值从valArrMax中获取,其余的值从valArr中获取
 		if val, valOk := valArr[edbInfoId]; valOk { //值存在
 			dvStr := fmt.Sprintf("%v", val)
-			formulaResult = strings.Replace(formulaStr, dKey, dvStr, -1)
+			formulaResult = strings.Replace(formulaResult, dKey, dvStr, -1)
 			isReplace = true
+			if maxDealFlag {
+				if valM, valMOk := valArrMax[edbInfoId]; valMOk { //值存在
+					dvMStr := fmt.Sprintf("%v", valM)
+					formulaResult = strings.Replace(formulaResult, strings.ToLower(dKey), dvMStr, -1)
+				} else {
+					formulaResult = strings.Replace(formulaResult, strings.ToLower(dKey)+",", "", -1)
+					formulaResult = strings.Replace(formulaResult, ","+strings.ToLower(dKey), "", -1)
+				}
+			}
 		}
 	}
 	return
@@ -690,8 +636,11 @@ func CheckFormula2(edbInfoArr []*EdbInfo, formulaMap map[string]string, formulaS
 	for _, v := range edbInfoArr {
 		valArr[v.EdbInfoId] = 100
 	}
+
 	formulaStr = strings.ToUpper(formulaStr)
-	formulaFormStr := ReplaceFormula(edbInfoArr, valArr, formulaMap, formulaStr, edbInfoIdBytes)
+	// 预设里的max和min无需特殊处理
+	valArrMax := make(map[int]float64)
+	formulaFormStr := ReplaceFormula(edbInfoArr, valArr, valArrMax, formulaMap, formulaStr, edbInfoIdBytes, false)
 	if formulaFormStr == "" {
 		return
 	}
@@ -899,22 +848,36 @@ func handleDateDataMapZero(saveDataMap map[string]map[int]float64, date string,
 	return
 }
 
-func GetMaxMinEdbInfo(formula string, formulaMap map[string]string) (edbInfoIdBytes []string) {
+func GetFormulaMaxMinReplace(index, edbInfoId int, formulaStr string, edbInfoIdBytes []string, formulaMap map[string]string, valArr map[int]float64) (formulaResult string, isReplace bool) {
+	formulaStr = GetMaxMinEdbInfo(formulaStr)
+	formulaResult = formulaStr
+	dKey := edbInfoIdBytes[index]
+	if _, ok := formulaMap[dKey]; ok { //公式中存在
+		// todo 判断公式中存在max、min,如果存在,则值从valArrMax中获取,其余的值从valArr中获取
+		if val, valOk := valArr[edbInfoId]; valOk { //值存在
+			dvStr := fmt.Sprintf("%v", val)
+			formulaResult = strings.Replace(formulaStr, dKey, dvStr, -1)
+			isReplace = true
+		}
+	}
+	return
+}
+
+func GetMaxMinEdbInfo(formula string) string {
 	//formula := "A+min(A,B,max(A,C))"
-	// 定义正则表达式匹配max和min函数及其参数
-	regex := regexp.MustCompile(`MIN\((.*?)\)|MAX\((.*?)\)`)
+	// todo 无法处理max里嵌套max或者min的情况
+	// 使用正则表达式匹配MAX和MIN函数及其参数
+	regex := regexp.MustCompile(`(?i)(MAX|MIN)\((.*?)\)`)
 	matches := regex.FindAllStringSubmatch(formula, -1)
-
-	// 遍历匹配结果,输出max和min函数及其参数
+	// 遍历匹配结果,输出MAX和MIN函数及其参数
 	for _, match := range matches {
 		if len(match) == 3 {
-			function := match[1] // min或max函数
-			parameter := match[2]
-			// todo 将max和min函数里的入参替换成小写
-			//lowercaseParameter := parameter                                                                         // 参数保持不变
-			//lowercaseFormula = strings.ReplaceAll(lowercaseFormula, match[0], lowercaseFunction+lowercaseParameter) // 替换公式中的MAX/MIN函数及其参数为小写形式
-			fmt.Printf("Function: %s, Parameter: %s\n", function, parameter)
+			parameter := strings.ToLower(match[0]) // 参数
+			formula = strings.ReplaceAll(formula, match[0], parameter)
+			fmt.Printf("formula: %s\n", formula)
 		}
 	}
-	return
+	formula = strings.ReplaceAll(formula, "max", "MAX")
+	formula = strings.ReplaceAll(formula, "min", "MIN")
+	return formula
 }

+ 43 - 6
models/base_predict_from_calculate.go

@@ -238,12 +238,12 @@ func AddPredictCalculateData(edbInfoIdList []*EdbInfo, edbInfo *EdbInfo, edbCode
 		}
 	}()
 
-	latestDateStr, latestValue, err = refreshAllPredictCalculate(to, edbInfoIdList, edbInfo.EdbInfoId, edbInfo.Source, edbCode, formulaStr, "", edbInfoIdBytes, edbInfo.EmptyType)
+	latestDateStr, latestValue, err = refreshAllPredictCalculate(to, edbInfoIdList, edbInfo.EdbInfoId, edbInfo.Source, edbCode, formulaStr, "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
 	return
 }
 
 // RefreshAllPredictCalculate 刷新预测计算指标的全部数据
-func RefreshAllPredictCalculate(edbInfoIdList []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate string, edbInfoIdBytes []string, emptyType int) (latestDateStr string, latestValue float64, err error) {
+func RefreshAllPredictCalculate(edbInfoIdList []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (latestDateStr string, latestValue float64, err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
 	if err != nil {
@@ -258,13 +258,13 @@ func RefreshAllPredictCalculate(edbInfoIdList []*EdbInfo, edbInfoId, source int,
 		}
 	}()
 
-	latestDateStr, latestValue, err = refreshAllPredictCalculate(to, edbInfoIdList, edbInfoId, source, edbCode, formulaStr, startDate, edbInfoIdBytes, emptyType)
+	latestDateStr, latestValue, err = refreshAllPredictCalculate(to, edbInfoIdList, edbInfoId, source, edbCode, formulaStr, startDate, edbInfoIdBytes, emptyType, maxEmptyType)
 
 	return
 }
 
 // refreshAllPredictCalculate 刷新预测计算指标的全部数据
-func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate string, edbInfoIdBytes []string, emptyType int) (latestDateStr string, latestValue float64, err error) {
+func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (latestDateStr string, latestValue float64, err error) {
 	fmt.Println("startDate:", startDate)
 
 	// 最小的结束日期 , 最晚的数据开始日期
@@ -330,7 +330,10 @@ func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInf
 	//数据处理,将日期内不全的数据做填补
 	handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdList, emptyType)
 
-	formulaMap := utils.CheckFormula(formulaStr)
+	formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
+	if err != nil {
+		return
+	}
 	addSql := ` INSERT INTO edb_data_predict_calculate (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
 	var isAdd bool
 	if !minLatestDate.IsZero() {
@@ -354,10 +357,44 @@ func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInf
 	existDataMap := make(map[string]string)
 
 	removeDateList := make([]string, 0) //需要移除的日期
+	// 判断是否特殊处理max和min函数
+	maxDealFlag := false
+	if emptyType == 4 && maxEmptyType == 2 {
+		maxDealFlag = true
+	}
+
 	for sk, sv := range saveDataMap {
+		// 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值
+		if emptyType == 1 {
+			if len(sv) != len(edbInfoIdList) {
+				continue
+			}
+		}
 		//fmt.Println(sk, sv)
+		// 根据时间范围,选择对应的公式
+		formulaMap := make(map[string]string)
+		formulaStr = ""
+		for _, fv := range formulaDateSlice {
+			if sk >= 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[sk]; ok {
+				svMax = svMaxData
+			}
+		}
 		formulaStr = strings.ToUpper(formulaStr)
-		formulaFormStr := ReplaceFormula(edbInfoIdList, sv, formulaMap, formulaStr, edbInfoIdBytes)
+		formulaFormStr := ReplaceFormula(edbInfoIdList, sv, svMax, formulaMap, formulaStr, edbInfoIdBytes, maxDealFlag)
 		if formulaFormStr != "" {
 			//utils.FileLog.Info(fmt.Sprintf("formulaFormStr:%s", formulaFormStr))
 			expression := formula.NewExpression(formulaFormStr)

+ 41 - 3
models/predict_edb.go

@@ -24,6 +24,7 @@ type CalculateRule struct {
 	EndDate                    string           `description:"截止日期"`
 	EdbInfoIdArr               []EdbInfoFromTag `description:"指标信息"`
 	EmptyType                  int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType               int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 }
 
 // RefreshCalculateByRuleBy9 刷新计算
@@ -114,8 +115,10 @@ func CalculateByRuleBy9(to orm.TxOrmer, rule CalculateRule) (resultDataList []*E
 	addDataList := make([]*PredictEdbRuleData, 0)
 
 	// 计算规则
-	formulaMap := utils.CheckFormula(formulaStr)
-
+	formulaDateSlice, formulaDateMap, err := utils.HandleFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
+	if err != nil {
+		return
+	}
 	//获取指标所有数据
 	dataList := make([]*PredictEdbRuleData, 0)
 	sql := `SELECT * FROM predict_edb_rule_data WHERE config_id = ?`
@@ -130,9 +133,44 @@ func CalculateByRuleBy9(to orm.TxOrmer, rule CalculateRule) (resultDataList []*E
 	existDataMap := make(map[string]string)
 
 	removeDateList := make([]string, 0) //需要移除的日期
+	// 判断是否特殊处理max和min函数
+	maxDealFlag := false
+	if rule.EmptyType == 4 && rule.MaxEmptyType == 2 {
+		maxDealFlag = true
+	}
 	for sk, sv := range saveDataMap {
+		// 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值
+		if rule.EmptyType == 1 {
+			if len(sv) != len(rule.EdbInfoList) {
+				continue
+			}
+		}
+		//fmt.Println(sk, sv)
+		// 根据时间范围,选择对应的公式
+		formulaMap := make(map[string]string)
+		formulaStr = ""
+		for _, fv := range formulaDateSlice {
+			if sk >= 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[sk]; ok {
+				svMax = svMaxData
+			}
+		}
+		formulaStr = strings.ToUpper(formulaStr)
 		//fmt.Println(sk, sv)
-		formulaFormStr := ReplaceFormula(rule.EdbInfoList, sv, formulaMap, formulaStr, rule.EdbInfoIdBytes)
+		formulaFormStr := ReplaceFormula(rule.EdbInfoList, sv, svMax, formulaMap, formulaStr, rule.EdbInfoIdBytes, maxDealFlag)
 		//计算公式异常,那么就移除该指标
 		if formulaFormStr == "" {
 			removeDateList = append(removeDateList, sk)

+ 18 - 2
utils/base_from_calculate.go

@@ -36,8 +36,8 @@ type FormulaListItem struct {
 	Date    string `json:"d"`
 }
 
-// CheckFormulaJson 检测计算公式json串是否异常
-func CheckFormulaJson(formula string, startDate string) (dateSlice []string, formulaMap map[string]string, err error) {
+// HandleFormulaJson 处理计算公式json串是否异常
+func HandleFormulaJson(formula string, startDate string) (dateSlice []string, formulaMap map[string]string, err error) {
 	list := make([]FormulaListItem, 0)
 	err = json.Unmarshal([]byte(formula), &list)
 	if err != nil {
@@ -60,3 +60,19 @@ func CheckFormulaJson(formula string, startDate string) (dateSlice []string, for
 
 	return
 }
+
+// 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
+	}
+	formulaSlice = make([]string, 0)
+	// 日期排序
+	for _, v := range list {
+		formulaSlice = append(formulaSlice, v.Formula)
+	}
+	return
+}