Sfoglia il codice sorgente

Merge branch 'feature/eta1.6.5_edb_calculate' into debug

# Conflicts:
#	models/base_from_calculate.go
xyxie 1 anno fa
parent
commit
32cc7d6048

+ 5 - 3
controllers/base_from_calculate.go

@@ -315,6 +315,7 @@ func (this *CalculateController) Edit() {
 	}
 
 	//todo 校验空值类型,max、min空值类型
+	//todo req.EdbInfoIdArr根据tag排序,排成A,B,AB,这种格式
 
 	calculateFormula := req.CalculateFormula
 	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
@@ -385,7 +386,7 @@ func (this *CalculateController) Edit() {
 	}
 	var needCalculate bool
 
-	if edbInfoDetail.CalculateFormula != req.CalculateFormula || edbInfoDetail.EmptyType != req.EmptyType || edbInfoDetail.MaxEmptyType != req.MaxEmptyType {
+	if edbInfoDetail.CalculateFormula != req.CalculateFormula || edbInfoDetail.EmptyType != req.EmptyType || edbInfoDetail.MaxEmptyType != req.MaxEmptyType || edbInfoDetail.Extra != req.Extra {
 		needCalculate = true
 	}
 
@@ -1423,14 +1424,15 @@ func (this *CalculateController) Refresh() {
 		}
 		var formulaStr string
 		edbInfoList := make([]*models.EdbInfo, 0)
-
+		edbInfoTag := make(map[string]int)
 		for _, v := range calculateMap {
+			edbInfoTag[v.FromTag] = v.FromEdbInfoId
 			formulaStr += v.FromTag + ","
 			edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
 			edbInfo, _ := models.GetEdbInfoById(v.FromEdbInfoId)
 			edbInfoList = append(edbInfoList, edbInfo)
 		}
-		err = models.RefreshAllCalculate(edbInfoList, edbInfo.EdbInfoId, source, subSource, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, endDate, edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
+		err = models.RefreshAllCalculate(edbInfoList, edbInfoTag, edbInfo.EdbInfoId, source, subSource, edbInfo.EdbCode, edbInfo.CalculateFormula, startDate, endDate, edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType, edbInfo.Extra)
 		if err != nil && err.Error() != utils.ErrNoRow() {
 			errMsg = "RefreshCalculate Err:" + err.Error()
 			break

+ 7 - 4
models/base_calculate.go

@@ -1374,20 +1374,23 @@ func (obj BaseCalculate) Ljz() (dateDataMap map[time.Time]float64, err error, er
 			itemDate := item.DataTime
 			dayInt := itemDate.Year()*100 + int(itemDate.Month())
 			var currTime time.Time
-			if itemDate.Month() <= 10 {
-				tmpK := fmt.Sprint(dayInt*100, "10")
+			if itemDate.Day() <= 10 {
+				//本月上旬
+				tmpK := fmt.Sprint(dayInt, "10")
 				currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
 				if err != nil {
 					return
 				}
 
-			} else if itemDate.Month() <= 20 {
-				tmpK := fmt.Sprint(dayInt*100, "20")
+			} else if itemDate.Day() <= 20 {
+				// 本月中旬
+				tmpK := fmt.Sprint(dayInt, "20")
 				currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
 				if err != nil {
 					return
 				}
 			} else {
+				// 本月下旬
 				currTime, err = time.ParseInLocation(utils.FormatYearMonthUnSpace, fmt.Sprint(dayInt), time.Local)
 				if err != nil {
 					return

+ 61 - 16
models/base_from_calculate.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"encoding/json"
 	"errors"
 	"eta/eta_index_lib/utils"
 	"fmt"
@@ -24,6 +25,7 @@ type EdbInfoCalculateSaveReq struct {
 	CalculateFormula string `description:"计算公式"`
 	EmptyType        int    `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType     int    `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string `description:"指标额外配置"`
 	EdbInfoIdArr     []EdbInfoFromTag
 }
 
@@ -90,16 +92,19 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
 		ChartImage:       "",
 		EmptyType:        req.EmptyType,
 		MaxEmptyType:     req.MaxEmptyType,
+		Extra:            req.Extra,
 	}
 	lastId, err := to.Insert(edbInfo)
 	if err != nil {
 		return
 	}
 	edbInfo.EdbInfoId = int(lastId)
+	edbInfoTag := make(map[string]int)
 	//关联关系表
 	{
 		//处理关联指标
 		for _, v := range calculateMappingList {
+			edbInfoTag[v.FromTag] = v.FromEdbInfoId
 			v.EdbCode = edbCode
 			v.EdbInfoId = edbInfo.EdbInfoId
 		}
@@ -112,7 +117,7 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
 	}
 
 	//计算数据
-	err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
+	err = refreshAllCalculate(to, edbInfoList, edbInfoTag, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType, edbInfo.Extra)
 	return
 }
 
@@ -142,7 +147,8 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaSli
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.EmptyType = req.EmptyType
 	edbInfo.MaxEmptyType = req.MaxEmptyType
-	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EmptyType", "MaxEmptyType")
+	edbInfo.Extra = req.Extra
+	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EmptyType", "MaxEmptyType", "Extra")
 	if err != nil {
 		return
 	}
@@ -163,7 +169,9 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaSli
 		edbInfoList := make([]*EdbInfo, 0)
 
 		calculateMappingList := make([]*EdbInfoCalculateMapping, 0)
+		edbInfoTag := make(map[string]int)
 		for k, v := range req.EdbInfoIdArr {
+			edbInfoTag[v.FromTag] = v.EdbInfoId
 			fromEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
 			if tmpErr != nil {
 				err = tmpErr
@@ -214,7 +222,7 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaSli
 			}
 		}
 		//计算数据
-		err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType)
+		err = refreshAllCalculate(to, edbInfoList, edbInfoTag, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType, edbInfo.MaxEmptyType, edbInfo.Extra)
 	}
 
 	return
@@ -257,7 +265,7 @@ func DeleteCalculateEdbInfo(edbInfoId int) (err error) {
 }
 
 // RefreshAllCalculate 刷新全部数据
-func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source, subSource int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (err error) {
+func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoTag map[string]int, edbInfoId, source, subSource int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int, extra string) (err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
 	if err != nil {
@@ -274,18 +282,30 @@ func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source, subSource i
 	fmt.Println(startDate, endDate)
 
 	//计算数据
-	err = refreshAllCalculate(to, edbInfoIdArr, edbInfoId, source, subSource, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes, emptyType, maxEmptyType)
+	err = refreshAllCalculate(to, edbInfoIdArr, edbInfoTag, edbInfoId, source, subSource, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes, emptyType, maxEmptyType, extra)
 	return
 }
 
 // refreshAllCalculate 刷新全部数据
-func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, source, subSource int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int) (err error) {
+func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoTag map[string]int, edbInfoId, source, subSource int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType, maxEmptyType int, extra string) (err error) {
 	realSaveDataMap := make(map[string]map[int]float64)
 	saveDataMap := make(map[string]map[int]float64)
 
 	// 最小的结束日期 , 最晚的数据开始日期
 	var minLatestDate, maxStartDate time.Time
-	dateList := make([]string, 0) // 第一个指标的日期数据
+	dateList := make([]string, 0)        // 最终的日期数据
+	dateMap := make(map[string]struct{}) // 最终的日期数据
+
+	dateTagConfig := ""
+	if extra != "" {
+		var dateConfig CalculateEdbExtra
+		err = json.Unmarshal([]byte(extra), &dateConfig)
+		if err != nil {
+			err = fmt.Errorf("refreshAllCalculate,extra解析失败,Err:%s", err.Error())
+			return
+		}
+		dateTagConfig = dateConfig.DateTag
+	}
 
 	for edbInfoIndex, v := range edbInfoIdArr {
 		var condition string
@@ -328,19 +348,40 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
 				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 dateTagConfig == "all" {
+				if _, ok := dateMap[dv.DataTime]; !ok {
+					dateList = append(dateList, dv.DataTime)
+					dateMap[dv.DataTime] = struct{}{}
+				}
+			} else if dateTagConfig == "" { // 默认取第一个指标的时间序列
+				if edbInfoIndex == 0 {
+					if _, ok := dateMap[dv.DataTime]; !ok {
+						dateList = append(dateList, dv.DataTime)
+						dateMap[dv.DataTime] = struct{}{}
+					}
 				}
-				if maxStartDate.IsZero() || tmpDate.Before(maxStartDate) {
-					maxStartDate = tmpDate
+			} else {
+				if eId, ok := edbInfoTag[dateTagConfig]; ok {
+					if v.EdbInfoId == eId {
+						if _, ok1 := dateMap[dv.DataTime]; !ok1 {
+							dateList = append(dateList, dv.DataTime)
+							dateMap[dv.DataTime] = struct{}{}
+						}
+					}
 				}
 			}
 		}
 	}
+	// 处理最大日期和最小日期
+	for _, v := range dateList {
+		tmpDate, _ := time.ParseInLocation(utils.FormatDate, v, time.Local)
+		if minLatestDate.IsZero() || tmpDate.After(minLatestDate) {
+			minLatestDate = tmpDate
+		}
+		if maxStartDate.IsZero() || tmpDate.Before(maxStartDate) {
+			maxStartDate = tmpDate
+		}
+	}
 
 	//数据处理,将日期内不全的数据做补全
 	HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
@@ -511,7 +552,9 @@ func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr, valArrMax map[int]float64,
 		formulaStr = GetMaxMinEdbInfo(formulaStr)
 	}
 	replaceCount := 0
-	for dk, dv := range edbInfoIdArr {
+	for dk := len(edbInfoIdArr) - 1; dk >= 0; dk-- {
+		dv := edbInfoIdArr[dk]
+		//for dk, dv := range edbInfoIdArr {
 		var isReplace bool
 		formulaStr, isReplace = GetFormulaReplace(dk, dv.EdbInfoId, formulaStr, edbInfoIdBytes, formulaMap, valArr, valArrMax, maxDealFlag)
 		if isReplace {
@@ -588,6 +631,7 @@ type EdbInfoCalculateBatchSaveReq struct {
 	MoveFrequency    string                         `description:"移动频度:天/周/月/季/年"`
 	Calendar         string                         `description:"公历/农历"`
 	Data             interface{}                    `description:"数据"`
+	Extra            string                         `description:"指标的额外配置"`
 }
 
 // EdbInfoCalculateEdbInfoIdReq 新增/编辑请求 关联的指标列表
@@ -618,6 +662,7 @@ type EdbInfoCalculateBatchEditReq struct {
 	MoveType      int         `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency string      `description:"移动频度:天/周/月/季/年"`
 	Calendar      string      `description:"公历/农历" orm:"default(公历)"`
+	Extra         string      `description:"指标的额外配置"`
 	Data          interface{} `description:"数据"`
 }
 

+ 134 - 11
models/edb_data_calculate_ljz.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"encoding/json"
 	"errors"
 	"eta/eta_index_lib/utils"
 	"fmt"
@@ -80,6 +81,7 @@ func (obj Ljz) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error,
 		LatestValue:      0,
 		ChartImage:       "",
 		Calendar:         "",
+		Extra:            req.Extra,
 	}
 
 	newEdbInfoId, tmpErr := to.Insert(edbInfo)
@@ -113,7 +115,7 @@ func (obj Ljz) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error,
 	}
 
 	//计算数据
-	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "")
+	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "", edbInfo.Extra)
 
 	return
 }
@@ -152,7 +154,7 @@ func (obj Ljz) Edit(params EditCalculateBatchParams) (err error, errMsg string)
 	tableName := GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
 
 	var isRecalculate bool
-	if edbInfo.Frequency != req.Frequency {
+	if edbInfo.Frequency != req.Frequency || edbInfo.Extra != req.Extra {
 		isRecalculate = true
 	}
 	//修改指标信息
@@ -161,6 +163,7 @@ func (obj Ljz) Edit(params EditCalculateBatchParams) (err error, errMsg string)
 	edbInfo.Frequency = req.Frequency
 	edbInfo.Unit = req.Unit
 	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.Extra = req.Extra
 	edbInfo.ModifyTime = time.Now()
 	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "ModifyTime")
 	if err != nil {
@@ -180,9 +183,9 @@ func (obj Ljz) Edit(params EditCalculateBatchParams) (err error, errMsg string)
 	}
 	if count > 0 { // 指标未被替换,无需删除关联数据
 
-		// 频度被换了,需要重新计算
+		// todo 频度被换了,需要重新计算
 		if isRecalculate {
-			err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "")
+			err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "", req.Extra)
 		}
 
 		return
@@ -228,7 +231,7 @@ func (obj Ljz) Edit(params EditCalculateBatchParams) (err error, errMsg string)
 	}
 
 	//计算数据
-	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "")
+	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo, fromEdbInfo, edbInfo.EdbCode, "", edbInfo.Extra)
 
 	return
 }
@@ -261,7 +264,7 @@ func (obj Ljz) Refresh(params RefreshParams) (err error, errMsg string) {
 	}()
 
 	// 计算数据
-	err = obj.refresh(to, params.EdbInfo.EdbInfoId, params.EdbInfo.Source, params.EdbInfo.SubSource, params.EdbInfo, fromEdbInfo, params.EdbInfo.EdbCode, params.StartDate)
+	err = obj.refresh(to, params.EdbInfo.EdbInfoId, params.EdbInfo.Source, params.EdbInfo.SubSource, params.EdbInfo, fromEdbInfo, params.EdbInfo.EdbCode, params.StartDate, params.EdbInfo.Extra)
 
 	return
 }
@@ -281,7 +284,7 @@ func (obj Ljz) GetEdbType() int {
 	return utils.CALCULATE_EDB_TYPE
 }
 
-func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo, fromEdbInfo *EdbInfo, edbCode, startDate string) (err error) {
+func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo, fromEdbInfo *EdbInfo, edbCode, startDate string, extra string) (err error) {
 	dataTableName := GetEdbDataTableName(source, subSource)
 	edbInfoIdStr := strconv.Itoa(edbInfoId)
 	//计算数据
@@ -313,8 +316,19 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			return
 		}
 	}
+	var lastValType int
+	if extra != "" {
+		var lastValConfig CalculateLjzEdbExtra
+		err = json.Unmarshal([]byte(extra), &lastValConfig)
+		if err != nil {
+			err = fmt.Errorf("refreshAllCalculate,extra解析失败,Err:%s", err.Error())
+			return
+		}
+		lastValType = lastValConfig.LastValType
+	}
 
 	//日度转周度:日期选周五,计算上周六到本周五的日度值的加总,最新日期为最新值对应的周五。
+	//日度转旬度:日期选每个旬的最后一天,计算当旬所有日度值的加总,最新日期为最新值对应当旬的最后一天。
 	//日度转月度:日期选每个月最后一天,计算当月所有日度值的加总,最新日期为最新值对应当月最后一天。
 	//日度转季度、年度:方法类似转月度。
 	//周度转月度/季度/年度:将周度值转成日度,空值用插值法插值,计算当月/当季/当年所有值的加总,然后除以7。
@@ -326,6 +340,7 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 	case "年度":
 		yearMap := make(map[int]float64)
 		yearList := make([]int, 0)
+		var lastNewDate time.Time
 		for _, item := range dataList {
 			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, item.DataTime, time.Local)
 			if tmpErr != nil {
@@ -345,10 +360,37 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			currTime := time.Date(v, 12, 31, 0, 0, 0, 0, time.Local)
 			dateList = append(dateList, currTime)
 			valueMap[currTime] = yearMap[v]
+			lastNewDate = currTime
+		}
+
+		// 根据配置处理最新值, 1 表示均值填充
+		if lastValType == 1 {
+			lastItem := dataList[len(dataList)-1]
+			// 最后一天的累计值
+			initVal := valueMap[lastNewDate]
+			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastItem.DataTime, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+
+			//获取当季的总天数, 当季最后一天减去当季第一天
+			// 获取当年的总天数
+			startDateT := time.Date(itemDate.Year(), 1, 1, 0, 0, 0, 0, time.Local)
+			allDays := int(lastNewDate.Sub(startDateT).Hours() / 24)
+			//获取距离当年第一天的天数
+			days := int(itemDate.Sub(startDateT).Hours() / 24)
+
+			daysT := decimal.NewFromInt(int64(days))
+			initValAndMonthT := decimal.NewFromFloat(initVal * float64(allDays))
+			val, _ := initValAndMonthT.Div(daysT).RoundCeil(4).Float64()
+			fmt.Printf("最新值 计算公式:%d*%f/(%d) = %f\n", allDays, initVal, days, val)
+			valueMap[lastNewDate] = val
 		}
 	case "半年度":
 		yearMonthMap := make(map[string]float64)
 		yearMonthList := make([]string, 0)
+		var lastNewDate time.Time
 		for _, item := range dataList {
 			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, item.DataTime, time.Local)
 			if tmpErr != nil {
@@ -380,10 +422,37 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			currTime = currTime.AddDate(0, 1, -1)
 			dateList = append(dateList, currTime)
 			valueMap[currTime] = yearMonthMap[v]
+			lastNewDate = currTime
+		}
+
+		// 根据配置处理最新值, 1 表示均值填充
+		if lastValType == 1 {
+			lastItem := dataList[len(dataList)-1]
+			// 最后一天的累计值
+			initVal := valueMap[lastNewDate]
+			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastItem.DataTime, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+
+			//获取上半年或者下半年的总天数, 半年度最后一天减去半年度第一天
+			startDateT := lastNewDate.AddDate(0, -6, 0)
+			allDays := int(lastNewDate.Sub(startDateT).Hours() / 24)
+
+			//获取距离半年度第一天的天数
+			days := int(itemDate.Sub(startDateT).Hours() / 24)
+
+			daysT := decimal.NewFromInt(int64(days))
+			initValAndMonthT := decimal.NewFromFloat(initVal * float64(allDays))
+			val, _ := initValAndMonthT.Div(daysT).RoundCeil(4).Float64()
+			fmt.Printf("最新值 计算公式:%d*%f/(%d) = %f\n", allDays, initVal, days, val)
+			valueMap[lastNewDate] = val
 		}
 	case "季度":
 		yearMonthMap := make(map[string]float64)
 		yearMonthList := make([]string, 0)
+		var lastNewDate time.Time
 		for _, item := range dataList {
 			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, item.DataTime, time.Local)
 			if tmpErr != nil {
@@ -419,10 +488,37 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			currTime = currTime.AddDate(0, 1, -1)
 			dateList = append(dateList, currTime)
 			valueMap[currTime] = yearMonthMap[v]
+			lastNewDate = currTime
+		}
+
+		// 根据配置处理最新值, 1 表示均值填充
+		if lastValType == 1 {
+			lastItem := dataList[len(dataList)-1]
+			// 最后一天的累计值
+			initVal := valueMap[lastNewDate]
+			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastItem.DataTime, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+
+			//获取当季的总天数, 当季最后一天减去当季第一天
+			startDateT := lastNewDate.AddDate(0, -3, 0)
+			allDays := int(lastNewDate.Sub(startDateT).Hours() / 24)
+			//获取距离当季第一天的天数
+			days := int(itemDate.Sub(startDateT).Hours() / 24)
+
+			daysT := decimal.NewFromInt(int64(days))
+			initValAndMonthT := decimal.NewFromFloat(initVal * float64(allDays))
+			val, _ := initValAndMonthT.Div(daysT).RoundCeil(4).Float64()
+			fmt.Printf("最新值 计算公式:%d*%f/(%d) = %f\n", allDays, initVal, days, val)
+
+			valueMap[lastNewDate] = val
 		}
 	case "月度":
 		yearMonthMap := make(map[string]float64)
 		yearMonthList := make([]string, 0)
+		var lastNewDate time.Time
 		for _, item := range dataList {
 			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, item.DataTime, time.Local)
 			if tmpErr != nil {
@@ -450,6 +546,30 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			currTime = currTime.AddDate(0, 1, -1)
 			dateList = append(dateList, currTime)
 			valueMap[currTime] = yearMonthMap[v]
+			lastNewDate = currTime
+		}
+
+		// 根据配置处理最新值, 1 表示均值填充
+		if lastValType == 1 {
+			lastItem := dataList[len(dataList)-1]
+			// 最后一天的累计值
+			initVal := valueMap[lastNewDate]
+			itemDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastItem.DataTime, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+
+			//获取当月的天数
+			monthDays := lastNewDate.Day()
+			//获取自然日的天数
+			days := itemDate.Day()
+
+			daysT := decimal.NewFromInt(int64(days))
+			initValAndMonthT := decimal.NewFromFloat(initVal * float64(monthDays))
+			val, _ := initValAndMonthT.Div(daysT).RoundCeil(4).Float64()
+			fmt.Printf("最新值 计算公式:%d*%f/(%d) = %f\n", monthDays, initVal, days, val)
+			valueMap[lastNewDate] = val
 		}
 	case "旬度":
 		tmpDateDataMap := make(map[time.Time]float64)
@@ -462,20 +582,23 @@ func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfo
 			}
 			dayInt := itemDate.Year()*100 + int(itemDate.Month())
 			var currTime time.Time
-			if itemDate.Month() <= 10 {
-				tmpK := fmt.Sprint(dayInt*100, "10")
+			if itemDate.Day() <= 10 {
+				//本月上旬
+				tmpK := fmt.Sprint(dayInt, "10")
 				currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
 				if err != nil {
 					return
 				}
 
-			} else if itemDate.Month() <= 20 {
-				tmpK := fmt.Sprint(dayInt*100, "20")
+			} else if itemDate.Day() <= 20 {
+				// 本月中旬
+				tmpK := fmt.Sprint(dayInt, "20")
 				currTime, err = time.ParseInLocation(utils.FormatDateUnSpace, tmpK, time.Local)
 				if err != nil {
 					return
 				}
 			} else {
+				// 本月下旬
 				currTime, err = time.ParseInLocation(utils.FormatYearMonthUnSpace, fmt.Sprint(dayInt), time.Local)
 				if err != nil {
 					return

+ 11 - 0
models/edb_info.go

@@ -58,6 +58,7 @@ type EdbInfo struct {
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
 	StockCode        string  `description:"证券代码"`
+	Extra            string  `description:"指标的额外配置"`
 }
 
 func (e *EdbInfo) Add() (err error) {
@@ -1263,3 +1264,13 @@ func GetEdbAndClassifyMaxSort(parentId int, classifyType uint8) (maxSort int, er
 	}
 	return
 }
+
+// CalculateEdbExtra 指标运算额外配置
+type CalculateEdbExtra struct {
+	DateTag string `description:"时间序列的生成方式,all 表示所选指标的时间序列并集"`
+}
+
+// CalculateLjzEdbExtra 累计值额外配置
+type CalculateLjzEdbExtra struct {
+	LastValType int `description:"最新值处理:0默认、均值填充"`
+}

+ 8 - 1
utils/base_from_calculate.go

@@ -23,7 +23,14 @@ func CheckFormula(formula string) map[string]string {
 	for i := 0; i < len(str); i++ {
 		byteInt := str[i]
 		if byteInt >= 65 && byteInt <= 90 {
-			byteStr := string(byteInt)
+			byteStr := string(byteInt) //获取计算公式中的占位符A,B, AA,AB
+			if i+1 < len(str) {
+				next := str[i+1]
+				if next >= 65 && next <= 90 {
+					byteStr += string(next)
+					i++
+				}
+			}
 			if _, ok := byteMap[byteStr]; !ok {
 				byteMap[byteStr] = byteStr
 			}