Forráskód Böngészése

区间分析图表展示

xyxie 6 hónapja
szülő
commit
831e0fecac

+ 7 - 0
controllers/chart.go

@@ -122,6 +122,13 @@ func (this *ChartController) ChartInfoDetail() {
 			br.ErrMsg = errMsg
 			return
 		}
+	case utils.CHART_SOURCE_RANGE_ANALYSIS:
+		resp, isOk, msg, errMsg = GetRangeAnalysisChartInfoDetailFromUniqueCode(chartInfo, key, this.Lang)
+		if !isOk {
+			br.Msg = msg
+			br.ErrMsg = errMsg
+			return
+		}
 	default:
 		br.Msg = "错误的图表"
 		br.ErrMsg = "错误的图表"

+ 14 - 0
models/chart_info_range_analysis.go

@@ -93,3 +93,17 @@ type ChartRangeAnalysisConfigEdbItem struct {
 	FromEdbInfoId int    `description:"计算来源指标id"`
 	EdbTypeInfo   int    `description:"指标类型,0普通指标,1预测指标"`
 }
+
+type SortEdbDataList []*EdbDataList
+
+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]
+}

+ 323 - 166
services/data/range_analysis/chart_info.go

@@ -11,176 +11,350 @@ import (
 	"fmt"
 	"github.com/shopspring/decimal"
 	"math"
+	"sort"
 	"time"
 )
 
+// GetAutoCalculateDateDataList 获取当前时间相关的区间作为计算依据
+func GetAutoCalculateDateDataList(currentDate string, dataList []*models.EdbDataList, req *models.ChartRangeAnalysisExtraConf) (newDataList []*models.EdbDataList, 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 HandleDataByCalculateType(originList []*models.ChartRangeAnalysisDateDataItem, calculateType int) (newList []*models.EdbDataList, err error) {
+func HandleDataByCalculateType(originList []*models.ChartRangeAnalysisDateDataItem, originDataList []*models.EdbDataList, req *models.ChartRangeAnalysisExtraConf) (newList []*models.EdbDataList, err error) {
 	if len(originList) == 0 {
 		return
 	}
+	calculateType := req.CalculateType
 	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)
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{
-					DataTime:      v.DataTime,
-					Value:         val,
-					DataTimestamp: v.DataTimestamp,
-				})
+		if req.DateRangeType == 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, &models.EdbDataList{
+						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, &models.EdbDataList{
+						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
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{
-					DataTime:      v.DataTime,
-					Value:         val,
-					DataTimestamp: v.DataTimestamp,
-				})
+		if req.DateRangeType == 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, &models.EdbDataList{
+						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, &models.EdbDataList{
+						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 req.DateRangeType == 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[len(calDataList)-1].Value
 					if baseVal == 0 {
-						break
+						continue
 					}
+
+					val := (v.Value - baseVal) / baseVal
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &models.EdbDataList{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
+				}
+			}
+		} else {
+			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
+					val, _ = decimal.NewFromFloat(val).Round(4).Float64()
+					newList = append(newList, &models.EdbDataList{
+						DataTime:      v.DataTime,
+						Value:         val,
+						DataTimestamp: v.DataTimestamp,
+					})
 				}
-				val := (v.Value - baseVal) / baseVal
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{
-					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 req.DateRangeType == 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[len(calDataList)-1].Value
+					baseDate = calDataList[len(calDataList)-1].DataTime
+					if v.DataTime == baseDate {
+						continue
+					}
 					if baseVal == 0 {
-						break
+						continue
 					}
-					continue
-				}
-				baseDateT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
-				if e != nil {
-					err = fmt.Errorf("time.ParseInLocation err: %v", e)
-					return
+
+					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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 				}
-				tmpT, e := time.ParseInLocation(utils.FormatDate, baseDate, time.Local)
-				if e != nil {
-					err = fmt.Errorf("time.ParseInLocation err: %v", e)
-					return
+			}
+		} else {
+			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, 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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 				}
-				// 计算两个日期相差的天数
-				diff := tmpT.Sub(baseDateT).Hours() / 24
-				val := v.Value / baseVal
-				val = math.Pow(val, diff) - 1
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{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 req.DateRangeType == 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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 				}
-				if v.Value > maxVal {
-					maxVal = v.Value
+			}
+		} 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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 				}
-				val := maxVal
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{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
+		if req.DateRangeType == 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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 				}
-				val := minVal
-				val, _ = decimal.NewFromFloat(val).Round(4).Float64()
-				newList = append(newList, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
 			}
-		}
-	}
-
-	return
-}
-
-// MoveDataDaysToNewDataList 平移指标数据生成新的数据序列
-func MoveDataDaysToNewDataList(dataList []*models.EdbDataList, moveDay int) (newDataList []models.EdbDataList, dateDataMap map[string]float64) {
-	dateMap := make(map[time.Time]float64)
-	var minDate, maxDate time.Time
-	dateDataMap = make(map[string]float64)
-
-	for _, v := range dataList {
-		currDate, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
-		if minDate.IsZero() || currDate.Before(minDate) {
-			minDate = currDate
-		}
-		if maxDate.IsZero() || currDate.After(maxDate) {
-			maxDate = currDate
-		}
-		dateMap[currDate] = v.Value
-	}
-
-	// 处理领先、滞后数据
-	newDateMap := make(map[time.Time]float64)
-	for currDate, value := range dateMap {
-		newDate := currDate.AddDate(0, 0, moveDay)
-		newDateMap[newDate] = value
-	}
-	minDate = minDate.AddDate(0, 0, moveDay)
-	maxDate = maxDate.AddDate(0, 0, moveDay)
-
-	// 获取日期相差日
-	dayNum := utils.GetTimeSubDay(minDate, maxDate)
-
-	for i := 0; i <= dayNum; i++ {
-		currDate := minDate.AddDate(0, 0, i)
-		tmpValue, ok := newDateMap[currDate]
-		if !ok {
-			//找不到数据,那么就用前面的数据吧
-			if len(newDataList)-1 < 0 {
-				tmpValue = 0
-			} else {
-				tmpValue = newDataList[len(newDataList)-1].Value
+		} 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, &models.EdbDataList{DataTime: v.DataTime, Value: val, DataTimestamp: v.DataTimestamp})
+				}
 			}
 		}
-		tmpData := models.EdbDataList{
-			DataTime: currDate.Format(utils.FormatDate),
-			Value:    tmpValue,
-		}
-		dateDataMap[tmpData.DataTime] = tmpData.Value
-		newDataList = append(newDataList, tmpData)
 	}
 	return
 }
@@ -449,48 +623,26 @@ func getChartDataByEdbInfo(edbInfoMapping *models.ChartEdbInfoMapping, req *mode
 	edbEndDate := edbEndDateTime.AddDate(0, 0, 1).Format(utils.FormatDate)
 
 	// 获取时间基准指标在时间区间内的值
-	dataList := make([]*models.EdbDataList, 0)
+	dataListTmp := make([]*models.EdbDataList, 0)
 	switch edbInfoMapping.EdbInfoCategoryType {
 	case 0:
-		dataList, err = models.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, "", "")
+		dataListTmp, err = models.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, "", "")
 	case 1:
-		_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfoMapping.EdbInfoId, "", "", false)
+		_, dataListTmp, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfoMapping.EdbInfoId, "", "", false)
 	default:
 		err = errors.New("指标base类型异常")
 		return
 	}
+	var dataList models.SortEdbDataList
+	dataList = dataListTmp
+	sort.Sort(dataList)
 
 	dateList := make([]*models.ChartRangeAnalysisDateDataItem, 0)
 	switch req.DateRangeType {
 	case 0:
 		// 智能划分得到一个开始日期,和结束日期
 		var startDateTime, endDateTime 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 = 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
-				}
-			}
-			startDateTime, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
-		}
+		startDateTime = edbStartDateTime
 
 		if req.AutoDateConf.IsAutoEndDate == 0 { //固定设置
 			endDate := req.AutoDateConf.EndDate
@@ -504,7 +656,7 @@ func getChartDataByEdbInfo(edbInfoMapping *models.ChartEdbInfoMapping, req *mode
 			endConf := req.AutoDateConf.EndDateConf
 			endDate := edbEndDate
 			if endConf.MoveForward > 0 {
-				endDate = GetEdbDateByMoveForward(endConf.MoveForward, dataList)
+				endDate = GetEdbDateByMoveForward(endDate, endConf.MoveForward, dataList)
 			}
 			if len(endConf.DateChange) > 0 {
 				endDate, err = HandleEdbDateChange(endDate, endConf.DateChange)
@@ -564,7 +716,7 @@ func getChartDataByEdbInfo(edbInfoMapping *models.ChartEdbInfoMapping, req *mode
 		}
 	}
 	// 根据时间区间类型来获取数据的计算窗口,然后再拼接成整段数据
-	newDataList, err := HandleDataByCalculateType(dateList, req.CalculateType)
+	newDataList, err := HandleDataByCalculateType(dateList, dataList, req)
 	if err != nil {
 		return
 	}
@@ -732,14 +884,19 @@ func ChartInfoRefresh(chartInfoId int, uniqueCode string) (isAsync bool, err err
 	return
 }
 
-func GetEdbDateByMoveForward(moveForward int, edbDataList []*models.EdbDataList) (date string) {
-	moveForward = 0
+func GetEdbDateByMoveForward(startDate string, moveForward int, edbDataList []*models.EdbDataList) (date string) {
 	// 根据日期进行排序
-	index := len(edbDataList) - 1 - moveForward
-	for k, v := range edbDataList {
-		if k == index {
+	index := 0
+	for _, v := range edbDataList {
+		if v.DataTime == startDate {
+			index += 1
+		}
+		if index > 0 {
+			index += 1
+		}
+		if index == moveForward {
 			date = v.DataTime
-			return
+			break
 		}
 	}
 	return