Răsfoiți Sursa

区间计算指标保存

xyxie 7 luni în urmă
părinte
comite
dc8d072703
4 a modificat fișierele cu 847 adăugiri și 12 ștergeri
  1. 2 0
      models/common.go
  2. 702 0
      models/edb_data_calculate_qjjs.go
  3. 129 0
      utils/common.go
  4. 14 12
      utils/constants.go

+ 2 - 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:
 
 	}

+ 702 - 0
models/edb_data_calculate_qjjs.go

@@ -0,0 +1,702 @@
+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:"起始日期"` //固定模式下,截止日期为指标的最新日期
+	StartDateConf   ChartRangeAnalysisAutoDateChangeConf `description:"动态起始日期配置"`
+	EndDateConf     ChartRangeAnalysisAutoDateChangeConf `description:"动态截止日期配置"`
+}
+
+type ChartRangeAnalysisAutoDateChangeConf struct {
+	BaseDateType int `description:"基准日期类型:0指标日期,1系统日期,2固定日期"`
+	MoveForward  int `description:"前移的期数"`
+	DateChange   []*EdbDateConfDateChange
+}
+
+type EdbDateConfDateChange 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
+}
+
+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.Formula
+	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.Formula
+	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 {
+		return
+	}
+
+	rangeAnalysisChartData, err := GetRangeAnalysisChartDataByEdbInfo(to, 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
+}
+
+// GetRangeAnalysisChartDataByEdbInfo 区间计算
+func GetRangeAnalysisChartDataByEdbInfo(to orm.TxOrmer, 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.AddDate(0, 0, 1).Format(utils.FormatDate)
+
+	// 获取时间基准指标在时间区间内的值
+	dataList, err := GetEdbDataListAllByTo(to, fromEdbInfo.Source, fromEdbInfo.SubSource, FindEdbDataListAllCond{
+		EdbInfoId: fromEdbInfo.EdbInfoId,
+	}, 0)
+	if err != nil {
+		err = fmt.Errorf("获取时间基准指标在时间区间内的值失败,Err:" + err.Error())
+		return
+	}
+
+	dateList := make([]*ChartRangeAnalysisDateDataItem, 0)
+	switch calculateFormula.DateRangeType {
+	case 0:
+		// 智能划分得到一个开始日期,和结束日期
+		var startDateTime, endDateTime time.Time
+		if calculateFormula.AutoDateConf.IsAutoStartDate == 0 { //固定设置
+			startDate := calculateFormula.AutoDateConf.StartDate
+			if startDate == "" {
+				startDate = "2020-01-01"
+			}
+			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+			endDateTime = edbEndDateTime
+		} else {
+			startConf := calculateFormula.AutoDateConf.StartDateConf
+			endConf := calculateFormula.AutoDateConf.EndDateConf
+			startDate := ""
+			endDate := ""
+			if startConf.BaseDateType == 0 { //
+				startDate = edbEndDate
+			} else if startConf.BaseDateType == 1 {
+				startDate = time.Now().Format(utils.FormatDate)
+			}
+			if startConf.MoveForward > 0 {
+				startDate = GetEdbDateByMoveForward(startConf.MoveForward, dataList)
+			}
+			if len(startConf.DateChange) > 0 {
+				startDate, err = HandleEdbDateChange(startDate, startConf.DateChange)
+				if err != nil {
+					err = fmt.Errorf("智能划分开始日期处理失败:%s", err.Error())
+					return
+				}
+			}
+
+			if endConf.BaseDateType == 0 { //
+				endDate = edbEndDate
+			} else if endConf.BaseDateType == 2 {
+				endDate = "2020-01-01"
+			}
+			if endConf.MoveForward > 0 {
+				endDate = GetEdbDateByMoveForward(endConf.MoveForward, dataList)
+			}
+			if len(endConf.DateChange) > 0 {
+				endDate, err = HandleEdbDateChange(endDate, endConf.DateChange)
+				if err != nil {
+					err = fmt.Errorf("智能划分结束日期处理失败:%s", err.Error())
+					return
+				}
+			}
+
+			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+			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 = HandleDataByCalculateType(dateList, calculateFormula.CalculateType)
+	if err != nil {
+		return
+	}
+	if calculateFormula.UnNormalDataDealType > 0 {
+		// todo 异常数据处理
+	}
+
+	if calculateFormula.DataConvertType > 0 {
+		// 数据转换类型 0不转, 1乘 2除 3对数
+		switch calculateFormula.DataConvertType {
+		case 1:
+			for i, v := range newDataList {
+				newDataList[i].Value = v.Value * calculateFormula.DataConvertConf.Value
+			}
+			//item.MaxData = item.MaxData * v.ConvertValue
+			//item.MinData = item.MinData * v.ConvertValue
+		case 2:
+			for i, v := range newDataList {
+				newDataList[i].Value = v.Value / calculateFormula.DataConvertConf.Value
+			}
+			//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
+				}
+				newDataList[i].Value = math.Log(v.Value) / math.Log(calculateFormula.DataConvertConf.Value)
+			}
+			//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+			//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+		}
+	}
+
+	return
+}
+
+// HandleDataByCalculateType 根据计算公式处理数据
+func HandleDataByCalculateType(originList []*ChartRangeAnalysisDateDataItem, calculateType int) (newList []*EdbInfoSearchData, err error) {
+	if len(originList) == 0 {
+		return
+	}
+	switch calculateType {
+	case 0: //均值
+		var sum float64
+		for _, item := range originList {
+			sum = 0
+			for k, v := range item.DataList {
+				sum += v.Value
+				val := sum / float64(k+1)
+				newList = append(newList, &EdbInfoSearchData{
+					DataTime:      v.DataTime,
+					Value:         val,
+					DataTimestamp: v.DataTimestamp,
+				})
+			}
+		}
+	case 1: //累计值
+		var sum float64
+		for _, item := range originList {
+			sum = 0
+			for _, v := range item.DataList {
+				sum += v.Value
+				val := sum
+				newList = append(newList, &EdbInfoSearchData{
+					DataTime:      v.DataTime,
+					Value:         val,
+					DataTimestamp: v.DataTimestamp,
+				})
+			}
+		}
+	case 2: //涨幅
+		for _, item := range originList {
+			var baseVal float64
+			for k, v := range item.DataList {
+				if k == 0 {
+					baseVal = v.Value
+					if baseVal == 0 {
+						break
+					}
+				}
+				val := (v.Value - baseVal) / baseVal
+				newList = append(newList, &EdbInfoSearchData{
+					DataTime:      v.DataTime,
+					Value:         val,
+					DataTimestamp: v.DataTimestamp,
+				})
+			}
+		}
+	case 3: //复合增长率
+		for _, item := range originList {
+			var baseVal float64
+			var baseDate string
+			for k, v := range item.DataList {
+				if k == 0 {
+					baseVal = v.Value
+					baseDate = v.DataTime
+					if baseVal == 0 {
+						break
+					}
+					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, baseDate, time.Local)
+				if e != nil {
+					err = fmt.Errorf("time.ParseInLocation err: %v", e)
+					return
+				}
+				// 计算两个日期相差的天数
+				diff := tmpT.Sub(baseDateT).Hours() / 24
+				val := v.Value / baseVal
+				val = math.Pow(val, diff) - 1
+				newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+			}
+		}
+	case 4: //最大值
+		var maxVal float64
+		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
+				newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+			}
+		}
+	case 5: //最小值
+		var minVal float64
+		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
+				newList = append(newList, &EdbInfoSearchData{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+			}
+		}
+	}
+
+	return
+}
+
+func GetEdbDateByMoveForward(moveForward int, edbDataList []*EdbInfoSearchData) (date string) {
+	moveForward = 0
+	// 根据日期进行排序
+	index := len(edbDataList) - 1 - moveForward
+	for k, v := range edbDataList {
+		if k == index {
+			date = v.DataTime
+			return
+		}
+	}
+	return
+}
+
+// HandleEdbDateChange 处理日期变换
+func HandleEdbDateChange(date string, dateChange []*EdbDateConfDateChange) (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
+}

+ 129 - 0
utils/common.go

@@ -1325,3 +1325,132 @@ func FormatFloatPlaces(val float64, places int32) (newVal float64, err error) {
 	newVal, _ = di.Float64()
 	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
+}

+ 14 - 12
utils/constants.go

@@ -99,17 +99,18 @@ const (
 	DATA_SOURCE_CALCULATE_ZDYFX                                 // 自定义分析->74
 	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
 
-	DATA_SOURCE_YONYI         = 76 //涌益咨询
-	DATA_SOURCE_FENWEI        = 77 //汾渭煤炭
-	DATA_SOURCE_GFEX          = 78 // 广州期货交易所->78
-	DATA_SOURCE_ICPI          = 79 // ICPI消费价格指数->79
-	DATA_SOURCE_MTJH          = 80 // 煤炭江湖->80
-	DATA_SOURCE_CALCULATE_SUM = 81
-	DATA_SOURCE_CALCULATE_AVG = 82
-	DATA_SOURCE_BLOOMBERG     = 83 // bloomberg彭博数据
-	DATA_SOURCE_BUSINESS      = 84 // 来源于自有数据
-	DATA_SOURCE_SCI99         = 85 // 卓创资讯
-	DATA_SOURCE_CCF           = 86 // CCF化纤信息
+	DATA_SOURCE_YONYI                  = 76 //涌益咨询
+	DATA_SOURCE_FENWEI                 = 77 //汾渭煤炭
+	DATA_SOURCE_GFEX                   = 78 // 广州期货交易所->78
+	DATA_SOURCE_ICPI                   = 79 // ICPI消费价格指数->79
+	DATA_SOURCE_MTJH                   = 80 // 煤炭江湖->80
+	DATA_SOURCE_CALCULATE_SUM          = 81
+	DATA_SOURCE_CALCULATE_AVG          = 82
+	DATA_SOURCE_BLOOMBERG              = 83 // bloomberg彭博数据
+	DATA_SOURCE_BUSINESS               = 84 // 来源于自有数据
+	DATA_SOURCE_SCI99                  = 85 // 卓创资讯
+	DATA_SOURCE_CCF                    = 86 // CCF化纤信息
+	DATA_SOURCE_CALCULATE_RANGEANLYSIS = 87 //区间计算->87
 )
 
 // 指标来源的中文展示
@@ -195,7 +196,8 @@ const (
 	DATA_SOURCE_NAME_CALCULATE_SUM                        = `多指标求和`
 	DATA_SOURCE_NAME_CALCULATE_AVG                        = `多指标求平均`
 	DATA_SOURCE_NAME_BUSINESS                             = `自有数据`
-	DATA_SOURCE_NAME_CCF                                  = `CCF` // CCF化纤信息
+	DATA_SOURCE_NAME_CCF                                  = `CCF`  // CCF化纤信息
+	DATA_SOURCE_NAME_CALCULATE_RANGEANLYSIS               = `区间计算` //区间计算->87
 )
 
 // 基础数据初始化日期