Browse Source

Merge branch 'feature/eta1.9.7_interval_anaylsis' of eta_server/eta_index_lib into master

xyxie 7 tháng trước cách đây
mục cha
commit
93de6939f0

+ 9 - 2
controllers/factor_edb_series/factor_edb_series.go

@@ -198,7 +198,7 @@ func (this *FactorEdbSeriesController) ChartRecalculate() {
 	if utils.Rc.IsExist(cacheKey) {
 		br.Ret = 501
 		br.Success = true
-		br.Msg = fmt.Sprintf("系统处理中, 请稍后重试, 图表ID: %s", req.ChartInfoId)
+		br.Msg = fmt.Sprintf("系统处理中, 请稍后重试, 图表ID: %d", req.ChartInfoId)
 		return
 	}
 	utils.Rc.SetNX(cacheKey, 1, 10*time.Minute)
@@ -269,9 +269,10 @@ func (this *FactorEdbSeriesController) ChartRecalculate() {
 	calculateDataOb := new(models.FactorEdbSeriesCalculateData)
 	for _, v := range mappings {
 		edbItem := edbIdItem[v.EdbInfoId]
-		if edbItem == nil {
+		if edbItem == nil && v.CalculateType == models.FactorEdbSeriesChartCalculateTypeCorrelation {
 			continue
 		}
+
 		seriesItem := seriesIdItem[v.FactorEdbSeriesId]
 		if seriesItem == nil {
 			continue
@@ -405,6 +406,12 @@ func (this *FactorEdbSeriesController) ChartRecalculate() {
 					utils.FileLog.Info(fmt.Sprintf("相关性-更新矩阵数据失败, err: %v", e))
 					return
 				}
+			} else if chartMapping.CalculateType == models.FactorEdbSeriesChartCalculateTypeRange {
+				err, errMsg := services.RangeAnalysisChartCalculate(seriesItem.FactorEdbSeriesId, req.ChartInfoId, chartMapping)
+				if err != nil {
+					utils.FileLog.Info(fmt.Sprintf("区间分析图表数据更新失败, err: %v,errMsg %s", err, errMsg))
+					return
+				}
 			}
 		}(v, edbItem, seriesItem)
 	}

+ 4 - 0
models/common.go

@@ -58,6 +58,8 @@ func GetBaseEdbInfoModel(source int) (baseEdbInfoModel BaseEdbInfoInterface) {
 		baseEdbInfoModel = CalculateSum{}
 	case utils.DATA_SOURCE_CALCULATE_AVG:
 		baseEdbInfoModel = CalculateAvg{}
+	case utils.DATA_SOURCE_CALCULATE_RANGEANLYSIS:
+		baseEdbInfoModel = CalculateRangeAnalysis{}
 	default:
 
 	}
@@ -101,6 +103,8 @@ func GetBasePredictEdbInfoModel(source int) (baseEdbInfoModel BasePredictEdbInfo
 		baseEdbInfoModel = PredictPercentile{}
 	case utils.DATA_SOURCE_PREDICT_CALCULATE_ZSXY:
 		baseEdbInfoModel = PredictExponentialSmoothing{}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_RANGEANLYSIS:
+		baseEdbInfoModel = PredictCalculateRangeAnalysis{}
 	default:
 
 	}

+ 5 - 4
models/db.go

@@ -210,10 +210,11 @@ func initBusinessEdb() {
 // initFactorEdbSeries 因子指标系列数据表
 func initFactorEdbSeries() {
 	orm.RegisterModel(
-		new(FactorEdbSeries),              // 因子指标系列
-		new(FactorEdbSeriesChartMapping),  // 因子指标系列-图表关联
-		new(FactorEdbSeriesMapping),       // 因子指标系列-指标计算数据
-		new(FactorEdbSeriesCalculateData), // 因子指标系列-指标关联
+		new(FactorEdbSeries),                  // 因子指标系列
+		new(FactorEdbSeriesChartMapping),      // 因子指标系列-图表关联
+		new(FactorEdbSeriesMapping),           // 因子指标系列-指标计算数据
+		new(FactorEdbSeriesCalculateData),     // 因子指标系列-指标关联
+		new(FactorEdbSeriesCalculateDataQjjs), // 因子指标系列-区间计算
 	)
 }
 

+ 971 - 0
models/edb_data_calculate_qjjs.go

@@ -0,0 +1,971 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type CalculateRangeAnalysis struct {
+}
+
+type RangeAnalysisCalculateFormula struct {
+	DateRangeType        int                                `description:"区间划分类型 0:智能划分,1:手工划分,2:跨年划分"`
+	AutoDateConf         ChartRangeAnalysisAutoDateConf     `description:"智能划分时间区间配置"`
+	ManualDateConf       []ChartRangeAnalysisManualDateConf `description:"手工划分时间区间配置"`
+	YearDateConf         ChartRangeAnalysisYearDateConf     `description:"跨年划分时间区间配置"`
+	CalculateType        int                                `description:"计算类型 0: 区间均值,1: 区间累计值,2:区间涨幅,3:区间年化增长率,4:区间最大值,5:区间最小值"`
+	UnNormalDataDealType int                                `description:"异常值处理配置 0:不处理,1:剔除,2替换"`
+	UnNormalDataConf     ChartRangeAnalysisDeleteDataConf
+	DataConvertType      int                               `description:"数据转换类型 0不转, 1乘 2除 3对数"`
+	DataConvertConf      ChartRangeAnalysisDataConvertConf `description:"数据转换详情"`
+}
+
+type ChartRangeAnalysisAutoDateConf struct { //智能划分
+	IsAutoStartDate int                                  `description:"起始日期是否是动态设置:0固定,1动态"`
+	StartDate       string                               `description:"起始日期"` //固定模式下,截止日期为指标的最新日期
+	EndDate         string                               `description:"固定模式下的截止日期"`
+	IsAutoEndDate   int                                  `description:"截止日期是否是动态设置:0固定,1动态"`
+	StartDateConf   ChartRangeAnalysisAutoDateChangeConf `description:"动态起始日期配置"`
+	EndDateConf     ChartRangeAnalysisAutoDateChangeConf `description:"动态截止日期配置"`
+}
+
+type ChartRangeAnalysisAutoDateChangeConf struct {
+	BaseDateType int `description:"基准日期类型:0指标日期,1系统日期,2固定日期"`
+	MoveForward  int `description:"前移的期数"`
+	DateChange   []*EdbDataDateChangeConf
+}
+
+type EdbDataDateChangeConf struct {
+	Year         int
+	Month        int
+	Day          int
+	Frequency    string `description:"频度变换"`
+	FrequencyDay string `description:"频度的固定日期"`
+	ChangeType   int    `description:"日期变换类型1日期位移,2指定频率"`
+}
+
+type ChartRangeAnalysisManualDateConf struct { //手工划分
+	StartDate string `description:"开始日期"`
+	EndDate   string `description:"结束日期"`
+}
+
+type ChartRangeAnalysisYearDateConf struct {
+	StartDay string `description:"开始日"`
+	EndDay   string `description:"结束日"`
+}
+
+type ChartRangeAnalysisDeleteDataConf struct {
+	Formula      string
+	Value        float64
+	ReplaceValue float64 `description:"替换的值"`
+}
+
+type ChartRangeAnalysisDataConvertConf struct {
+	Value  float64 `description:"数据转换值"`
+	Unit   string  `description:"数据转换单位"`
+	EnUnit string  `description:"数据转换单位"`
+}
+
+type ChartRangeAnalysisDateDataItem struct {
+	StartDate time.Time
+	EndDate   time.Time
+	DataList  []*EdbInfoSearchData
+}
+
+func (obj CalculateRangeAnalysis) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error, errMsg string) {
+	req := params.Req
+	edbCode := params.EdbCode
+	uniqueCode := params.UniqueCode
+	sysUserId := params.SysUserId
+	sysUserRealName := params.SysUserRealName
+	//req *EdbInfoCalculateBatchSaveReq, edbCode, uniqueCode string, sysUserId int, sysUserRealName string
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId > 0 {
+		err = errors.New("无法新增")
+		return
+	}
+
+	edbInfo = new(EdbInfo)
+	edbInfo.Source = obj.GetSource()
+	edbInfo.SourceName = obj.GetSourceName()
+	edbInfo.EdbCode = edbCode
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.SysUserId = sysUserId
+	edbInfo.SysUserRealName = sysUserRealName
+	edbInfo.CreateTime = time.Now()
+	edbInfo.ModifyTime = time.Now()
+	edbInfo.UniqueCode = uniqueCode
+	edbInfo.CalculateFormula = req.CalculateFormula
+	edbInfo.EdbNameEn = req.EdbName
+	edbInfo.UnitEn = req.Unit
+	edbInfo.EdbType = obj.GetEdbType()
+	newEdbInfoId, tmpErr := to.Insert(edbInfo)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	edbInfo.EdbInfoId = int(newEdbInfoId)
+
+	//关联关系
+	fromEdbInfo, e := GetEdbInfoById(req.FromEdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取来源指标失败,Err:%s", e.Error())
+		return
+	}
+
+	calculateMappingItem := new(EdbInfoCalculateMapping)
+	calculateMappingItem.CreateTime = time.Now()
+	calculateMappingItem.ModifyTime = time.Now()
+	calculateMappingItem.Sort = 1
+	calculateMappingItem.EdbCode = edbCode
+	calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+	calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+	calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+	calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+	calculateMappingItem.FromSource = fromEdbInfo.Source
+	calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+	calculateMappingItem.FromTag = ""
+	calculateMappingItem.Source = edbInfo.Source
+	calculateMappingItem.SourceName = edbInfo.SourceName
+	calculateMappingItem.FromSubSource = edbInfo.SubSource
+
+	_, err = to.Insert(calculateMappingItem)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj CalculateRangeAnalysis) Edit(params EditCalculateBatchParams) (err error, errMsg string) {
+	edbInfo := params.EdbInfo
+	req := params.Req
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//修改指标信息
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.CalculateFormula = req.CalculateFormula
+	edbInfo.EdbNameEn = req.EdbNameEn
+	edbInfo.UnitEn = req.UnitEn
+	edbInfo.ModifyTime = time.Now()
+	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EdbNameEn", "UnitEn")
+	if err != nil {
+		return
+	}
+
+	//删除,计算指标关联的,基础指标的关联关系
+	sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+		return
+	}
+	//清空原有数据
+	tableName := GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
+	sql = ` DELETE FROM ` + tableName + ` WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		return
+	}
+
+	fromEdbInfo, e := GetEdbInfoById(req.FromEdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取来源指标失败,Err:%s", e.Error())
+		return
+	}
+
+	calculateMappingItem := new(EdbInfoCalculateMapping)
+	calculateMappingItem.CreateTime = time.Now()
+	calculateMappingItem.ModifyTime = time.Now()
+	calculateMappingItem.Sort = 1
+	calculateMappingItem.EdbCode = edbInfo.EdbCode
+	calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+	calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+	calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+	calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+	calculateMappingItem.FromSource = fromEdbInfo.Source
+	calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+	calculateMappingItem.FromTag = ""
+	calculateMappingItem.Source = edbInfo.Source
+	calculateMappingItem.SourceName = edbInfo.SourceName
+	calculateMappingItem.FromSubSource = edbInfo.SubSource
+
+	_, err = to.Insert(calculateMappingItem)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj CalculateRangeAnalysis) Refresh(params RefreshParams) (err error, errMsg string) {
+	edbInfo := params.EdbInfo
+	edbInfoCalculateDetailList, err := GetEdbInfoCalculateDetailList(edbInfo.EdbInfoId)
+	if err != nil {
+		return
+	}
+	var fromEdbInfo *EdbInfo
+	for _, v := range edbInfoCalculateDetailList {
+		fromEdbInfo, _ = GetEdbInfoById(v.FromEdbInfoId)
+		break
+	}
+
+	if fromEdbInfo == nil {
+		errMsg = "指标异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj CalculateRangeAnalysis) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, fromEdbInfo *EdbInfo, edbCode, calculateFormula string) (err error, errMsg string) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(obj.GetSource(), utils.DATA_SUB_SOURCE_EDB)
+
+	//获取扩散指数指标所有数据
+	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source, subSource)
+	if err != nil {
+		return
+	}
+	//计算指标的map
+	existDataMap := make(map[string]*EdbData, 0)
+	removeDateMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v
+		removeDateMap[v.DataTime] = ``
+	}
+	var rangeAnalysisConf RangeAnalysisCalculateFormula
+	//fmt.Println("calculateFormula:", calculateFormula)
+	err = json.Unmarshal([]byte(calculateFormula), &rangeAnalysisConf)
+	if err != nil {
+		err = fmt.Errorf("解析区间计算公式失败 %s", err.Error())
+		return
+	}
+
+	rangeAnalysisChartData, err := GetRangeAnalysisChartDataByEdbInfo(fromEdbInfo, rangeAnalysisConf)
+	if err != nil {
+		err = fmt.Errorf("获取区间计算数据失败 %s", err.Error())
+		return
+	}
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	for _, item := range rangeAnalysisChartData {
+		currDateStr := item.DataTime
+		currVal := item.Value
+		// 判断扩散指数指标是否存在数据
+		if existData, ok := existDataMap[currDateStr]; ok {
+			// 处理扩散指数数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Round(4).Float64()
+			// 判断扩散指数数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, subSource, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := item.DataTimestamp
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, currDateStr, timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+
+		delete(removeDateMap, currDateStr)
+	}
+
+	// 数据入库
+	{
+
+		if isAdd {
+			addSql = strings.TrimRight(addSql, ",")
+			_, err = to.Raw(addSql).Exec()
+		}
+
+		// 移除不存在的日期数据
+		if len(removeDateMap) > 0 {
+			removeDateList := make([]string, 0) //需要移除的日期
+			for k := range removeDateMap {
+				removeDateList = append(removeDateList, k)
+			}
+			removeDateStr := strings.Join(removeDateList, `","`)
+			removeDateStr = `"` + removeDateStr + `"`
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+			_, err = to.Raw(sql, edbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除扩散指数指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	return
+}
+
+// GetAutoCalculateDateDataList 获取当前时间相关的区间作为计算依据
+func GetAutoCalculateDateDataList(currentDate string, dataList []*EdbInfoSearchData, req RangeAnalysisCalculateFormula) (newDataList []*EdbInfoSearchData, err error) {
+	currentDateTime, _ := time.ParseInLocation(utils.FormatDate, currentDate, time.Local)
+	switch req.DateRangeType {
+	case 0:
+		// 智能划分得到一个开始日期,和结束日期
+		var startDateTime time.Time
+		if req.AutoDateConf.IsAutoStartDate == 0 { //固定设置
+			startDate := req.AutoDateConf.StartDate
+			if startDate == "" {
+				startDate = "2020-01-01"
+			}
+			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		} else {
+			startConf := req.AutoDateConf.StartDateConf
+			startDate := ""
+			if startConf.BaseDateType == 0 { //
+				startDate = currentDate
+			} else if startConf.BaseDateType == 1 {
+				startDate = time.Now().Format(utils.FormatDate)
+			}
+			if startConf.MoveForward > 0 {
+				startDate = GetEdbDateByMoveForward(startDate, startConf.MoveForward, dataList)
+			}
+			if len(startConf.DateChange) > 0 {
+				startDate, err = HandleEdbDateChange(startDate, startConf.DateChange)
+				if err != nil {
+					err = fmt.Errorf("智能划分开始日期处理失败:%s", err.Error())
+					return
+				}
+			}
+			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		}
+		var calStartTime, calEndTime time.Time
+		if currentDateTime.Before(startDateTime) {
+			calStartTime = currentDateTime
+			calEndTime = startDateTime
+		} else {
+			calStartTime = startDateTime
+			calEndTime = currentDateTime
+		}
+		// 根据日期,获取数据
+		for _, vv := range dataList {
+			dataTimeT, _ := time.ParseInLocation(utils.FormatDate, vv.DataTime, time.Local)
+			if dataTimeT.After(calStartTime) && dataTimeT.Before(calEndTime) ||
+				dataTimeT.Equal(calStartTime) ||
+				dataTimeT.Equal(calEndTime) {
+				newDataList = append(newDataList, vv)
+			}
+		}
+	}
+	return
+}
+
+// HandleDataByCalculateType 根据计算公式处理数据
+func HandleRangeAnalysisDataByCalculateType(originList []*ChartRangeAnalysisDateDataItem, originDataList []*EdbInfoSearchData, req RangeAnalysisCalculateFormula) (newList []*EdbInfoSearchData, err error) {
+	if len(originList) == 0 {
+		return
+	}
+	calculateType := req.CalculateType
+	switch calculateType {
+	case 0: //均值
+		var sum float64
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				for _, v := range item.DataList {
+					sum = 0
+					//计算的数据返回需要重新确定
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					for _, vv := range calDataList {
+						sum += vv.Value
+					}
+					val := sum / float64(len(calDataList))
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				sum = 0
+				for k, v := range item.DataList {
+					sum += v.Value
+					val := sum / float64(k+1)
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		}
+
+	case 1: //累计值
+		var sum float64
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				sum = 0
+				for _, v := range item.DataList {
+					sum = 0
+					//计算的数据返回需要重新确定
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					for _, vv := range calDataList {
+						sum += vv.Value
+					}
+					val := sum
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				sum = 0
+				for _, v := range item.DataList {
+					sum += v.Value
+					val := sum
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		}
+
+	case 2: //涨幅
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				for _, v := range item.DataList {
+					var baseVal float64
+					//计算的数据返回需要重新确定
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					if len(calDataList) == 0 {
+						continue
+					}
+					baseVal = calDataList[0].Value
+					baseDate := calDataList[0].DataTime
+					if baseVal == 0 {
+						continue
+					}
+					if v.DataTime == baseDate {
+						continue
+					}
+
+					val := (v.Value - baseVal) / baseVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				if len(item.DataList) == 0 {
+					break
+				}
+				baseVal := item.DataList[0].Value
+				baseDate := item.DataList[0].DataTime
+				if baseVal == 0 {
+					break
+				}
+				for _, v := range item.DataList {
+					if v.DataTime == baseDate {
+						continue
+					}
+					val := (v.Value - baseVal) / baseVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		}
+	case 3: //复合增长率
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				for _, v := range item.DataList {
+					var baseVal float64
+					var baseDate string
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					if len(calDataList) == 0 {
+						continue
+					}
+					baseVal = calDataList[0].Value
+					baseDate = calDataList[0].DataTime
+					if v.DataTime == baseDate {
+						continue
+					}
+					if baseVal == 0 {
+						continue
+					}
+
+					baseDateT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
+					if e != nil {
+						err = fmt.Errorf("time.ParseInLocation err: %v", e)
+						return
+					}
+					tmpT, e := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+					if e != nil {
+						err = fmt.Errorf("time.ParseInLocation err: %v", e)
+						return
+					}
+					// 计算两个日期相差的天数
+					diff := tmpT.Sub(baseDateT).Hours() / 24 / 365
+					val := v.Value / baseVal
+					val = math.Pow(val, 1/diff) - 1
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				if len(item.DataList) == 0 {
+					break
+				}
+				baseVal := item.DataList[0].Value
+				baseDate := item.DataList[0].DataTime
+				if baseVal == 0 {
+					break
+				}
+				for _, v := range item.DataList {
+					if v.DataTime == baseDate {
+						continue
+					}
+					baseDateT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
+					if e != nil {
+						err = fmt.Errorf("time.ParseInLocation err: %v", e)
+						return
+					}
+					tmpT, e := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+					if e != nil {
+						err = fmt.Errorf("time.ParseInLocation err: %v", e)
+						return
+					}
+					// 计算两个日期相差的天数
+					diff := tmpT.Sub(baseDateT).Hours() / 24 / 365
+					val := v.Value / baseVal
+					val = math.Pow(val, 1/diff) - 1
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		}
+	case 4: //最大值
+		var maxVal float64
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				for _, v := range item.DataList {
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					for kk, vv := range calDataList {
+						if kk == 0 {
+							maxVal = vv.Value
+						}
+						if vv.Value > maxVal {
+							maxVal = vv.Value
+						}
+					}
+
+					val := maxVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				for k, v := range item.DataList {
+					if k == 0 {
+						maxVal = v.Value
+					}
+					if v.Value > maxVal {
+						maxVal = v.Value
+					}
+					val := maxVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		}
+	case 5: //最小值
+		var minVal float64
+		if req.DateRangeType == 0 && req.AutoDateConf.IsAutoStartDate > 0 {
+			for _, item := range originList {
+				for _, v := range item.DataList {
+					calDataList, e := GetAutoCalculateDateDataList(v.DataTime, originDataList, req)
+					if e != nil {
+						err = fmt.Errorf("获取区间数据失败:%s", e.Error())
+						return
+					}
+					for kk, vv := range calDataList {
+						if kk == 0 {
+							minVal = vv.Value
+						}
+						if vv.Value < minVal {
+							minVal = vv.Value
+						}
+					}
+					val := minVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		} else {
+			for _, item := range originList {
+				for k, v := range item.DataList {
+					if k == 0 {
+						minVal = v.Value
+					}
+					if v.Value < minVal {
+						minVal = v.Value
+					}
+					val := minVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// GetRangeAnalysisChartDataByEdbInfo 区间计算
+func GetRangeAnalysisChartDataByEdbInfo(fromEdbInfo *EdbInfo, calculateFormula RangeAnalysisCalculateFormula) (newDataList []*EdbInfoSearchData, err error) {
+	// 指标的开始日期和结束日期
+	edbStartDateTime, _ := time.ParseInLocation(utils.FormatDate, fromEdbInfo.StartDate, time.Local)
+	//edbStartDate := edbStartDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)
+	edbEndDateTime, _ := time.ParseInLocation(utils.FormatDate, fromEdbInfo.EndDate, time.Local)
+	edbEndDate := edbEndDateTime.Format(utils.FormatDate)
+
+	// 获取时间基准指标在时间区间内的值
+	dataList := make([]*EdbInfoSearchData, 0)
+	switch fromEdbInfo.EdbInfoType {
+	case 0:
+		//获取来源指标的数据
+		dataList, err = GetEdbDataListAll(fromEdbInfo.Source, fromEdbInfo.SubSource,
+			FindEdbDataListAllCond{
+				EdbInfoId: fromEdbInfo.EdbInfoId,
+			}, 1)
+	case 1:
+		dataList, err = GetPredictEdbDataListAllByStartDate(fromEdbInfo, 1, "")
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标base类型异常", fromEdbInfo.EdbInfoType))
+		return
+	}
+
+	if err != nil {
+		err = fmt.Errorf("获取时间基准指标在时间区间内的值失败,Err:" + err.Error())
+		return
+	}
+
+	dateList := make([]*ChartRangeAnalysisDateDataItem, 0)
+	switch calculateFormula.DateRangeType {
+	case 0:
+		// 智能划分得到一个开始日期,和结束日期
+		var startDateTime, endDateTime time.Time
+		startDateTime = edbStartDateTime
+		if calculateFormula.AutoDateConf.IsAutoStartDate == 0 { //固定设置
+			startDate := calculateFormula.AutoDateConf.StartDate
+			if startDate == "" {
+				startDate = "2020-01-01"
+			}
+			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		}
+		if calculateFormula.AutoDateConf.IsAutoEndDate == 0 { //固定设置
+			endDate := calculateFormula.AutoDateConf.EndDate
+			if endDate == "" {
+				err = fmt.Errorf("智能划分截止日期处理失败:请输入截止日期")
+				return
+			}
+			// todo 如果截止日期比指标日期还要大,则用指标的最新日期
+			endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+		} else {
+			endConf := calculateFormula.AutoDateConf.EndDateConf
+			endDate := edbEndDate
+			if endConf.MoveForward > 0 {
+				endDate = GetEdbDateByMoveForward(endDate, endConf.MoveForward, dataList)
+			}
+			if len(endConf.DateChange) > 0 {
+				endDate, err = HandleEdbDateChange(endDate, endConf.DateChange)
+				if err != nil {
+					err = fmt.Errorf("智能划分结束日期处理失败:%s", err.Error())
+					return
+				}
+			}
+			endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+		}
+
+		dateList = append(dateList, &ChartRangeAnalysisDateDataItem{
+			StartDate: startDateTime,
+			EndDate:   endDateTime})
+	case 1:
+		// 手工划分得到多个开始日期和结束日期(已排序)
+		for _, v := range calculateFormula.ManualDateConf {
+			startDateT, _ := time.ParseInLocation(utils.FormatDate, v.StartDate, time.Local)
+			endDateT, _ := time.ParseInLocation(utils.FormatDate, v.EndDate, time.Local)
+			tmp := &ChartRangeAnalysisDateDataItem{
+				StartDate: startDateT,
+				EndDate:   endDateT,
+			}
+			dateList = append(dateList, tmp)
+		}
+	case 2:
+		// 跨年划分得到多个开始日期和结束日期
+		startYear := edbStartDateTime.Year()
+		endYear := edbEndDateTime.Year()
+		startDay := calculateFormula.YearDateConf.StartDay
+		endDay := calculateFormula.YearDateConf.EndDay
+		for year := startYear; year <= endYear; year++ {
+			startDate := fmt.Sprintf("%d-%s", year, startDay)
+			endDate := fmt.Sprintf("%d-%s", year+1, endDay)
+			startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+			endDateTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+			if startDateTime.Before(edbStartDateTime) {
+				break
+			}
+
+			tmp := &ChartRangeAnalysisDateDataItem{
+				StartDate: startDateTime,
+				EndDate:   endDateTime,
+			}
+			dateList = append(dateList, tmp)
+		}
+	}
+	// 根据日期,获取数据
+	for _, v := range dateList {
+		for _, vv := range dataList {
+			dataTimeT, _ := time.ParseInLocation(utils.FormatDate, vv.DataTime, time.Local)
+			if dataTimeT.After(v.StartDate) && dataTimeT.Before(v.EndDate) ||
+				dataTimeT.Equal(v.StartDate) ||
+				dataTimeT.Equal(v.EndDate) {
+				v.DataList = append(v.DataList, vv)
+			}
+		}
+	}
+	// 根据时间区间类型来获取数据的计算窗口,然后再拼接成整段数据
+	newDataList, err = HandleRangeAnalysisDataByCalculateType(dateList, dataList, calculateFormula)
+	if err != nil {
+		return
+	}
+	if calculateFormula.UnNormalDataDealType > 0 {
+		switch calculateFormula.UnNormalDataDealType { //0:不处理,1:剔除,2替换
+		case 1:
+			dealDataList := make([]*EdbInfoSearchData, 0)
+			for _, v := range newDataList {
+				if !utils.CompareFloatByOpStrings(calculateFormula.UnNormalDataConf.Formula, v.Value, calculateFormula.UnNormalDataConf.Value) {
+					dealDataList = append(dealDataList, v)
+				}
+			}
+		case 2:
+			for i, v := range newDataList {
+				if utils.CompareFloatByOpStrings(calculateFormula.UnNormalDataConf.Formula, v.Value, calculateFormula.UnNormalDataConf.Value) {
+					newDataList[i].Value = calculateFormula.UnNormalDataConf.ReplaceValue
+				}
+			}
+		}
+	}
+
+	if calculateFormula.DataConvertType > 0 {
+		// 数据转换类型 0不转, 1乘 2除 3对数
+		switch calculateFormula.DataConvertType {
+		case 1:
+			for i, v := range newDataList {
+				val := v.Value * calculateFormula.DataConvertConf.Value
+				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+				newDataList[i].Value = val
+			}
+			//item.MaxData = item.MaxData * v.ConvertValue
+			//item.MinData = item.MinData * v.ConvertValue
+		case 2:
+			for i, v := range newDataList {
+				val := v.Value / calculateFormula.DataConvertConf.Value
+				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+				newDataList[i].Value = val
+			}
+			//item.MaxData = item.MaxData / v.ConvertValue
+			//item.MinData = item.MinData / v.ConvertValue
+		case 3:
+			for i, v := range newDataList {
+				if v.Value <= 0 {
+					err = errors.New("数据中含有负数或0,无法对数运算")
+					return
+				}
+				val := math.Log(v.Value) / math.Log(calculateFormula.DataConvertConf.Value)
+				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+				newDataList[i].Value = val
+			}
+			//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+			//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+		}
+	}
+
+	return
+}
+
+func GetEdbDateByMoveForward(startDate string, moveForward int, edbDataList []*EdbInfoSearchData) (date string) {
+	// 根据日期进行排序
+	index := 0
+	length := len(edbDataList)
+	for i := length - 1; i >= 0; i-- {
+		item := edbDataList[i]
+		if item.DataTime == startDate {
+			index += 1
+			continue
+		}
+		if index >= moveForward {
+			date = item.DataTime
+			break
+		}
+		if index > 0 {
+			index += 1
+			date = item.DataTime
+		}
+	}
+	return
+}
+
+// HandleEdbDateChange 处理日期变换
+func HandleEdbDateChange(date string, dateChange []*EdbDataDateChangeConf) (newDate string, err error) {
+	newDate = date
+	if newDate != "" {
+		if len(dateChange) > 0 {
+			var dateTime time.Time
+			dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+			if err != nil {
+				err = fmt.Errorf("日期解析失败: %s", err.Error())
+				return
+			}
+			for _, v := range dateChange {
+				if v.ChangeType == 1 {
+					dateTime = dateTime.AddDate(v.Year, v.Month, v.Day)
+					newDate = dateTime.Format(utils.FormatDate)
+				} else if v.ChangeType == 2 {
+					newDate, err, _ = utils.HandleSystemAppointDateT(dateTime, v.FrequencyDay, v.Frequency)
+					if err != nil {
+						return
+					}
+					dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+					if err != nil {
+						err = fmt.Errorf("日期解析失败: %s", err.Error())
+						return
+					}
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// GetSource 获取来源编码id
+func (obj CalculateRangeAnalysis) GetSource() int {
+	return utils.DATA_SOURCE_CALCULATE_RANGEANLYSIS
+}
+
+// GetSourceName 获取来源名称
+func (obj CalculateRangeAnalysis) GetSourceName() string {
+	return utils.DATA_SOURCE_NAME_CALCULATE_RANGEANLYSIS
+}
+
+// GetEdbType 获取指标类型
+func (obj CalculateRangeAnalysis) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}

+ 14 - 0
models/edb_info.go

@@ -1592,3 +1592,17 @@ func TransEdbInfoDataList2SearchData(items []*EdbDataList) (list []*EdbInfoSearc
 	}
 	return
 }
+
+type SortEdbDataList []*EdbInfoSearchData
+
+func (m SortEdbDataList) Len() int {
+	return len(m)
+}
+
+func (m SortEdbDataList) Less(i, j int) bool {
+	return m[i].DataTime > m[j].DataTime
+}
+
+func (m SortEdbDataList) Swap(i, j int) {
+	m[i], m[j] = m[j], m[i]
+}

+ 210 - 0
models/factor_edb_series_calculate_data_qjjs.go

@@ -0,0 +1,210 @@
+package models
+
+import (
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesCalculateDataQjjs 因子指标系列-区间计算数据表
+type FactorEdbSeriesCalculateDataQjjs struct {
+	FactorEdbSeriesCalculateDataId int       `orm:"column(factor_edb_series_calculate_data_id);pk"`
+	FactorEdbSeriesId              int       `description:"因子指标系列ID"`
+	EdbInfoId                      int       `description:"指标ID"`
+	EdbCode                        string    `description:"指标编码"`
+	DataTime                       time.Time `description:"数据日期"`
+	Value                          float64   `description:"数据值"`
+	CreateTime                     time.Time `description:"创建时间"`
+	ModifyTime                     time.Time `description:"修改时间"`
+	DataTimestamp                  int64     `description:"数据日期时间戳"`
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) TableName() string {
+	return "factor_edb_series_calculate_data_qjjs"
+}
+
+type FactorEdbSeriesCalculateDataQjjsCols struct {
+	PrimaryId         string
+	FactorEdbSeriesId string
+	EdbInfoId         string
+	EdbCode           string
+	DataTime          string
+	Value             string
+	CreateTime        string
+	ModifyTime        string
+	DataTimestamp     string
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Cols() FactorEdbSeriesCalculateDataQjjsCols {
+	return FactorEdbSeriesCalculateDataQjjsCols{
+		PrimaryId:         "factor_edb_series_calculate_data_id",
+		FactorEdbSeriesId: "factor_edb_series_id",
+		EdbInfoId:         "edb_info_id",
+		EdbCode:           "edb_code",
+		DataTime:          "data_time",
+		Value:             "value",
+		CreateTime:        "create_time",
+		ModifyTime:        "modify_time",
+		DataTimestamp:     "data_timestamp",
+	}
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesCalculateDataId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) CreateMulti(items []*FactorEdbSeriesCalculateDataQjjs) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(500, items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Remove() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesCalculateDataId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemById(id int) (item *FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrm()
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesCalculateDataQjjsItem 因子指标系列-计算数据信息
+type FactorEdbSeriesCalculateDataQjjsItem struct {
+	DataId            int     `description:"数据ID"`
+	FactorEdbSeriesId int     `description:"因子指标系列ID"`
+	EdbInfoId         int     `description:"指标ID"`
+	EdbCode           string  `description:"指标编码"`
+	DataTime          string  `description:"数据日期"`
+	Value             float64 `description:"数据值"`
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Format2Item() (item *FactorEdbSeriesCalculateDataQjjsItem) {
+	item = new(FactorEdbSeriesCalculateDataQjjsItem)
+	item.DataId = m.FactorEdbSeriesCalculateDataId
+	item.FactorEdbSeriesId = m.FactorEdbSeriesId
+	item.EdbInfoId = m.EdbInfoId
+	item.EdbCode = m.EdbCode
+	return
+}
+
+// TransEdbSeriesCalculateDataQjjs2EdbDataList 转换数据格式
+func TransEdbSeriesCalculateDataQjjs2EdbDataList(items []*FactorEdbSeriesCalculateDataQjjs) (list []*EdbDataList) {
+	list = make([]*EdbDataList, 0)
+	for _, v := range items {
+		list = append(list, &EdbDataList{
+			DataTime: v.DataTime.Format(utils.FormatDate),
+			Value:    v.Value,
+		})
+	}
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetEdbDataList(seriesId int, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	var pars []interface{}
+	sql := `SELECT factor_edb_series_calculate_data_id as edb_data_id  ,edb_info_id,data_time,value,data_timestamp FROM %s WHERE edb_info_id=? and factor_edb_series_id=? `
+	pars = append(pars, edbInfoId, seriesId)
+	if startDate != "" {
+		sql += ` AND data_time>=? `
+		pars = append(pars, startDate)
+	}
+	if endDate != "" {
+		sql += ` AND data_time<=? `
+		pars = append(pars, endDate)
+	}
+
+	sql += ` ORDER BY data_time ASC `
+	sql = fmt.Sprintf(sql, m.TableName())
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}

+ 1 - 0
models/factor_edb_series_chart_mapping.go

@@ -10,6 +10,7 @@ import (
 
 const (
 	FactorEdbSeriesChartCalculateTypeCorrelation = 1 // 相关性计算
+	FactorEdbSeriesChartCalculateTypeRange       = 2 // 	区间计算
 )
 
 // FactorEdbSeriesChartMapping 因子指标系列-图表关联

+ 7 - 0
models/factor_edb_series_mapping.go

@@ -165,3 +165,10 @@ func (m *FactorEdbSeriesMapping) Format2Item() (item *FactorEdbSeriesMappingItem
 	item.EdbCode = m.EdbCode
 	return
 }
+
+func (m *FactorEdbSeriesMapping) GetItemBySeriesId(seriesId int) (items []*FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().FactorEdbSeriesId)
+	_, err = o.Raw(sql, seriesId).QueryRows(&items)
+	return
+}

+ 344 - 0
models/predict_edb_data_calculate_qjjs.go

@@ -0,0 +1,344 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type PredictCalculateRangeAnalysis struct {
+}
+
+func (obj PredictCalculateRangeAnalysis) Add(params BatchSaveCalculateBatchParams) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error, errMsg string) {
+	req := params.Req
+	edbCode := params.EdbCode
+	uniqueCode := params.UniqueCode
+	sysUserId := params.SysUserId
+	sysUserRealName := params.SysUserRealName
+	//req *EdbInfoCalculateBatchSaveReq, edbCode, uniqueCode string, sysUserId int, sysUserRealName string
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId > 0 {
+		err = errors.New("无法新增")
+		return
+	}
+
+	edbInfo = new(EdbInfo)
+	edbInfo.Source = obj.GetSource()
+	edbInfo.SourceName = obj.GetSourceName()
+	edbInfo.EdbCode = edbCode
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.SysUserId = sysUserId
+	edbInfo.SysUserRealName = sysUserRealName
+	edbInfo.CreateTime = time.Now()
+	edbInfo.ModifyTime = time.Now()
+	edbInfo.UniqueCode = uniqueCode
+	edbInfo.CalculateFormula = req.CalculateFormula
+	edbInfo.EdbNameEn = req.EdbName
+	edbInfo.UnitEn = req.Unit
+	edbInfo.EdbType = obj.GetEdbType()
+	edbInfo.EdbInfoType = 1
+	newEdbInfoId, tmpErr := to.Insert(edbInfo)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	edbInfo.EdbInfoId = int(newEdbInfoId)
+
+	//关联关系
+	fromEdbInfo, e := GetEdbInfoById(req.FromEdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取来源指标失败,Err:%s", e.Error())
+		return
+	}
+
+	calculateMappingItem := new(EdbInfoCalculateMapping)
+	calculateMappingItem.CreateTime = time.Now()
+	calculateMappingItem.ModifyTime = time.Now()
+	calculateMappingItem.Sort = 1
+	calculateMappingItem.EdbCode = edbCode
+	calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+	calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+	calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+	calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+	calculateMappingItem.FromSource = fromEdbInfo.Source
+	calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+	calculateMappingItem.FromTag = ""
+	calculateMappingItem.Source = edbInfo.Source
+	calculateMappingItem.SourceName = edbInfo.SourceName
+	calculateMappingItem.FromSubSource = edbInfo.SubSource
+
+	_, err = to.Insert(calculateMappingItem)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj PredictCalculateRangeAnalysis) Edit(params BatchSaveCalculateBatchParams) (latestDateStr string, latestValue float64, err error, errMsg string) {
+	edbInfo := params.EdbInfo
+	req := params.Req
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//修改指标信息
+	edbInfo.EdbName = req.EdbName
+	edbInfo.EdbNameSource = req.EdbName
+	edbInfo.Frequency = req.Frequency
+	edbInfo.Unit = req.Unit
+	edbInfo.ClassifyId = req.ClassifyId
+	edbInfo.CalculateFormula = req.CalculateFormula
+	//修改指标信息
+	switch params.Lang {
+	case utils.EnLangVersion:
+		edbInfo.EdbNameEn = req.EdbName
+		edbInfo.UnitEn = req.Unit
+	default:
+		edbInfo.EdbName = req.EdbName
+		edbInfo.Unit = req.Unit
+		edbInfo.EdbNameSource = req.EdbName
+	}
+	edbInfo.ModifyTime = time.Now()
+	_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EdbNameEn", "UnitEn")
+	if err != nil {
+		return
+	}
+
+	//删除,计算指标关联的,基础指标的关联关系
+	sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+		return
+	}
+	//清空原有数据
+	tableName := GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
+	sql = ` DELETE FROM ` + tableName + ` WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		return
+	}
+
+	fromEdbInfo, e := GetEdbInfoById(req.FromEdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取来源指标失败,Err:%s", e.Error())
+		return
+	}
+
+	calculateMappingItem := new(EdbInfoCalculateMapping)
+	calculateMappingItem.CreateTime = time.Now()
+	calculateMappingItem.ModifyTime = time.Now()
+	calculateMappingItem.Sort = 1
+	calculateMappingItem.EdbCode = edbInfo.EdbCode
+	calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+	calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+	calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+	calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+	calculateMappingItem.FromSource = fromEdbInfo.Source
+	calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+	calculateMappingItem.FromTag = ""
+	calculateMappingItem.Source = edbInfo.Source
+	calculateMappingItem.SourceName = edbInfo.SourceName
+	calculateMappingItem.FromSubSource = edbInfo.SubSource
+
+	_, err = to.Insert(calculateMappingItem)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj PredictCalculateRangeAnalysis) Refresh(params RefreshParams) (latestDateStr string, latestValue float64, err error, errMsg string) {
+	edbInfo := params.EdbInfo
+	edbInfoCalculateDetailList, err := GetEdbInfoCalculateDetailList(edbInfo.EdbInfoId)
+	if err != nil {
+		return
+	}
+	var fromEdbInfo *EdbInfo
+	for _, v := range edbInfoCalculateDetailList {
+		fromEdbInfo, _ = GetEdbInfoById(v.FromEdbInfoId)
+		break
+	}
+
+	if fromEdbInfo == nil {
+		errMsg = "指标异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateRangeAnalysis,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	latestDateStr, latestValue, err, errMsg = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, fromEdbInfo, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func (obj PredictCalculateRangeAnalysis) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, fromEdbInfo *EdbInfo, edbCode, calculateFormula string) (latestDateStr string, latestValue float64, err error, errMsg string) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(obj.GetSource(), utils.DATA_SUB_SOURCE_EDB)
+
+	//获取扩散指数指标所有数据
+	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source, subSource)
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+	//计算指标的map
+	existDataMap := make(map[string]*EdbData, 0)
+	removeDateMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v
+		removeDateMap[v.DataTime] = ``
+	}
+	var rangeAnalysisConf RangeAnalysisCalculateFormula
+	//fmt.Println("calculateFormula:", calculateFormula)
+	err = json.Unmarshal([]byte(calculateFormula), &rangeAnalysisConf)
+	if err != nil {
+		err = fmt.Errorf("解析区间计算公式失败 %s", err.Error())
+		return
+	}
+
+	rangeAnalysisChartData, err := GetRangeAnalysisChartDataByEdbInfo(fromEdbInfo, rangeAnalysisConf)
+	if err != nil {
+		err = fmt.Errorf("获取区间计算数据失败 %s", err.Error())
+		return
+	}
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	for _, item := range rangeAnalysisChartData {
+		currDateStr := item.DataTime
+		currVal := item.Value
+		// 判断扩散指数指标是否存在数据
+		if existData, ok := existDataMap[currDateStr]; ok {
+			// 处理扩散指数数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Round(4).Float64()
+			// 判断扩散指数数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, subSource, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := item.DataTimestamp
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, currDateStr, timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+
+		delete(removeDateMap, currDateStr)
+	}
+
+	// 数据入库
+	{
+
+		if isAdd {
+			addSql = strings.TrimRight(addSql, ",")
+			_, err = to.Raw(addSql).Exec()
+		}
+
+		// 移除不存在的日期数据
+		if len(removeDateMap) > 0 {
+			removeDateList := make([]string, 0) //需要移除的日期
+			for k := range removeDateMap {
+				removeDateList = append(removeDateList, k)
+			}
+			removeDateStr := strings.Join(removeDateList, `","`)
+			removeDateStr = `"` + removeDateStr + `"`
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+			_, err = to.Raw(sql, edbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除扩散指数指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+	//确定实际数据的最终值
+	{
+		finalLast, tmpErr := GetFinalLastByTo(to, edbInfoId, obj.GetSource(), utils.DATA_SUB_SOURCE_EDB, fromEdbInfo.LatestDate)
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			return
+		}
+		if tmpErr == nil {
+			latestDateStr = finalLast.DataTime
+			latestValue = finalLast.Value
+		}
+	}
+	return
+}
+
+// GetSource 获取来源编码id
+func (obj PredictCalculateRangeAnalysis) GetSource() int {
+	return utils.DATA_SOURCE_PREDICT_CALCULATE_RANGEANLYSIS
+}
+
+// GetSourceName 获取来源名称
+func (obj PredictCalculateRangeAnalysis) GetSourceName() string {
+	return utils.DATA_SOURCE_NAME_PREDICT_CALCULATE_RANGEANLYSIS
+}
+
+// GetEdbType 获取指标类型
+func (obj PredictCalculateRangeAnalysis) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}

+ 93 - 0
services/factor_edb_series.go

@@ -1,6 +1,8 @@
 package services
 
 import (
+	"encoding/json"
+	"errors"
 	"eta/eta_index_lib/models"
 	"eta/eta_index_lib/services/alarm_msg"
 	"eta/eta_index_lib/utils"
@@ -73,3 +75,94 @@ func FactorEdbStepCalculate(seriesId, edbInfoId int, edbCode string, edbData []*
 	}
 	return
 }
+
+func RangeAnalysisChartCalculate(seriesId, chartInfoId int, seriesMappingItem *models.FactorEdbSeriesChartMapping) (err error, errMsg string) {
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("RangeAnalysisChartCalculate 区间分析图表计算失败, 图表ID:%d, ErrMsg: %v", chartInfoId, err)
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+	}()
+	chartInfo, err := models.GetChartInfoById(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "图表已被删除,请刷新页面"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取图表信息失败"
+		err = errors.New("获取图表信息失败,Err:" + err.Error())
+		return
+	}
+	// 区间计算图表配置校验
+	var extraConfig models.RangeAnalysisCalculateFormula
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConfig)
+	if err != nil {
+		errMsg = "配置信息错误"
+		err = errors.New(errMsg + ", Err: " + err.Error())
+		return
+	}
+	if seriesMappingItem.FactorEdbSeriesChartMappingId > 0 {
+		ob := new(models.FactorEdbSeriesMapping)
+		seriesEdbMappingList, e := ob.GetItemBySeriesId(seriesMappingItem.FactorEdbSeriesId)
+		if e != nil { // 没有数据,则不计算
+			return
+		}
+		edbInfoIds := make([]int, 0)
+		for _, item := range seriesEdbMappingList {
+			edbInfoIds = append(edbInfoIds, item.EdbInfoId)
+		}
+
+		edbInfoList, e := models.GetEdbInfoByIdList(edbInfoIds)
+		if e != nil {
+			errMsg = "获取指标信息失败"
+			err = errors.New(errMsg + ", Err: " + e.Error())
+			return
+		}
+		// 重新计算-先清除原数据
+		calculateDataOb := new(models.FactorEdbSeriesCalculateDataQjjs)
+
+		cond := fmt.Sprintf("%s = ?", calculateDataOb.Cols().FactorEdbSeriesId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, seriesId)
+		if e := calculateDataOb.RemoveByCondition(cond, pars); e != nil {
+			err = fmt.Errorf("清除原数据失败, err: %v", e)
+			return
+		}
+
+		// 计算成功的保存结果
+		dataArr := make([]*models.FactorEdbSeriesCalculateDataQjjs, 0)
+		for _, fromEdbInfo := range edbInfoList {
+			dataList, e := models.GetRangeAnalysisChartDataByEdbInfo(fromEdbInfo, extraConfig)
+			if e != nil {
+				errMsg = "获取区间分析图表数据失败"
+				err = errors.New(errMsg + ", Err: " + e.Error())
+				return
+			}
+			for _, dataItem := range dataList {
+				dataTime, _ := time.ParseInLocation(utils.FormatDate, dataItem.DataTime, time.Local)
+				dataArr = append(dataArr, &models.FactorEdbSeriesCalculateDataQjjs{
+					FactorEdbSeriesId: seriesId,
+					EdbInfoId:         fromEdbInfo.EdbInfoId,
+					EdbCode:           fromEdbInfo.EdbCode,
+					DataTime:          dataTime,
+					Value:             dataItem.Value,
+					CreateTime:        time.Now().Local(),
+					ModifyTime:        time.Now().Local(),
+					DataTimestamp:     dataItem.DataTimestamp,
+				})
+			}
+		}
+		if len(dataArr) == 0 {
+			err = fmt.Errorf("计算结果无数据, seriesId: %d", seriesId)
+			return
+		}
+		if e := calculateDataOb.CreateMulti(dataArr); e != nil {
+			err = fmt.Errorf("保存计算结果失败, seriesId: %d, err: %v, ", seriesId, e)
+			return
+		}
+	}
+	return
+}

+ 145 - 0
utils/common.go

@@ -1326,6 +1326,151 @@ func FormatFloatPlaces(val float64, places int32) (newVal float64, err error) {
 	return
 }
 
+// handleSystemAppointDateT
+// @Description: 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
+// @author: Roc
+// @datetime2023-10-27 09:31:35
+// @param Frequency string
+// @param Day string
+// @return date string
+// @return err error
+// @return errMsg string
+func HandleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) {
+	//currDate := time.Now()
+	switch frequency {
+	case "本周":
+		day := int(currDate.Weekday())
+		if day == 0 { // 周日
+			day = 7
+		}
+		num := 0
+		switch appointDay {
+		case "周一":
+			num = 1
+		case "周二":
+			num = 2
+		case "周三":
+			num = 3
+		case "周四":
+			num = 4
+		case "周五":
+			num = 5
+		case "周六":
+			num = 6
+		case "周日":
+			num = 7
+		}
+		day = num - day
+		date = currDate.AddDate(0, 0, day).Format(FormatDate)
+	case "本旬":
+		day := currDate.Day()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if day <= 10 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
+			} else if day <= 20 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 11, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 21, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if day <= 10 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 10, 0, 0, 0, 0, currDate.Location())
+			} else if day <= 20 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 20, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
+			}
+		}
+		date = tmpDate.Format(FormatDate)
+	case "本月":
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
+		case "最后一天":
+			tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
+		}
+		date = tmpDate.Format(FormatDate)
+	case "本季":
+		month := currDate.Month()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if month <= 3 {
+				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 4, 1, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 9 {
+				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 10, 1, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if month <= 3 {
+				tmpDate = time.Date(currDate.Year(), 3, 31, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 9 {
+				tmpDate = time.Date(currDate.Year(), 9, 30, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+			}
+		}
+		date = tmpDate.Format(FormatDate)
+	case "本半年":
+		month := currDate.Month()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+			}
+		}
+		date = tmpDate.Format(FormatDate)
+	case "本年":
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+		case "最后一天":
+			tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+		}
+		date = tmpDate.Format(FormatDate)
+	default:
+		errMsg = "错误的日期频度:" + frequency
+		err = errors.New(errMsg)
+		return
+	}
+
+	return
+}
+
+func CompareFloatByOpStrings(op string, a, b float64) bool {
+	switch op {
+	case "=":
+		return a == b
+	case ">":
+		return a > b
+	case ">=":
+		return a >= b
+	case "<=":
+		return a <= b
+	case "<":
+		return a < b
+	}
+	return false
+}
+
 // IsDivideZero
 // @Description: 判断是否分母为0的bug
 // @author: Roc

+ 9 - 4
utils/constants.go

@@ -109,8 +109,10 @@ const (
 	DATA_SOURCE_BUSINESS                             = 84 // 来源于自有数据
 	DATA_SOURCE_SCI99                                = 85 // 卓创资讯
 	DATA_SOURCE_CCF                                  = 86 // CCF化纤信息
+	DATA_SOURCE_CALCULATE_RANGEANLYSIS               = 87 //区间计算->87
 	DATA_SOURCE_SCI_HQ                               = 88 // 卓创红期->88
-	DATA_SOURCE_OILCHEM       = 89 // 隆众资讯 -> 89
+	DATA_SOURCE_OILCHEM                              = 89 // 隆众资讯 -> 89
+	DATA_SOURCE_PREDICT_CALCULATE_RANGEANLYSIS       = 90 // 预测指标区间计算->90
 )
 
 // 指标来源的中文展示
@@ -196,9 +198,12 @@ const (
 	DATA_SOURCE_NAME_CALCULATE_SUM                        = `多指标求和`
 	DATA_SOURCE_NAME_CALCULATE_AVG                        = `多指标求平均`
 	DATA_SOURCE_NAME_BUSINESS                             = `自有数据`
-	DATA_SOURCE_NAME_CCF                                  = `CCF`  // CCF化纤信息
-	DATA_SOURCE_NAME_SCI_HQ                               = `卓创红期` // 卓创红期
-	DATA_SOURCE_NAME_OILCHEM                              = `隆众资讯` // 隆众资讯 -> 89
+
+	DATA_SOURCE_NAME_CCF                            = `CCF`    // CCF化纤信息
+	DATA_SOURCE_NAME_SCI_HQ                         = `卓创红期`   // 卓创红期
+	DATA_SOURCE_NAME_OILCHEM                        = `隆众资讯`   // 隆众资讯 -> 89
+	DATA_SOURCE_NAME_CALCULATE_RANGEANLYSIS         = `区间计算`   //区间计算->87
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_RANGEANLYSIS = `预测区间计算` //区间计算->90
 )
 
 // 基础数据初始化日期