Эх сурвалжийг харах

Merge branch 'feature/eta_1.6.8'

hsun 1 жил өмнө
parent
commit
dd311bea5f

+ 1 - 1
controllers/chart_common.go

@@ -467,7 +467,7 @@ func GetLineFeatureChartInfoDetailFromUniqueCode(chartInfo *models.ChartInfo, ke
 			return
 		}
 		startDate, endDate := utils.GetDateByDateType(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate)
-		edbList, resultResp, err, msg = lineFeatureServ.GetPercentileData(chartInfo.ChartInfoId, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit)
+		edbList, resultResp, err, msg = lineFeatureServ.GetPercentileData(chartInfo.ChartInfoId, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit, percentileConfig.PercentType)
 	case utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		var frequencyDistributionConfig line_featureReq.FrequencyDistribution
 		err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &frequencyDistributionConfig)

+ 2 - 0
models/chart.go

@@ -32,6 +32,8 @@ type ChartInfo struct {
 	SeasonEndDate     string    `description:"季节性图开始日期"`
 	ChartImage        string    `description:"图表图片"`
 	BarConfig         string    `description:"柱方图的配置,json数据" json:"-"`
+	XMin              string    `description:"图表X轴最小值"`
+	XMax              string    `description:"图表X轴最大值"`
 	LeftMin           string    `description:"图表左侧最小值"`
 	LeftMax           string    `description:"图表左侧最大值"`
 	RightMin          string    `description:"图表右侧最小值"`

+ 5 - 2
models/data_manage/cross_variety/request/chart.go

@@ -9,11 +9,14 @@ type ChartConfigReq struct {
 	CalculateUnit  string            `description:"计算频度"`
 	DateConfigList []ChartConfigDate `description:"日期配置列表"`
 	VarietyList    []int             `description:"品种id列表"`
+	PercentType    int               `description:"百分位:0-数据区间(兼容历史数据); 1-数据个数;"`
 }
 
 // ChartConfigDate
 // @Description: 跨品种分析的日期配置
 type ChartConfigDate struct {
-	DateType int `description:"日期类型,,1:最新日期;2:N天前"`
-	Num      int
+	DateType int    `description:"日期类型:1-最新日期;2-N天前;3-固定日期"`
+	Num      int    `description:"N天前的N值"`
+	FixDate  string `description:"固定日期的日期"`
+	ShowTips int    `description:"是否显示标注:0-否;1-是"`
 }

+ 1 - 0
models/data_manage/line_feature/request/line_feature.go

@@ -34,6 +34,7 @@ type StandardDeviation struct {
 type Percentile struct {
 	CalculateValue int    `description:"时间长度期数"`
 	CalculateUnit  string `description:"时间长度频度"`
+	PercentType    int    `description:"百分位:0-数据区间(兼容历史数据); 1-数据个数;"`
 }
 
 type FrequencyDistribution struct {

+ 121 - 40
services/data/cross_variety/chart.go

@@ -45,6 +45,8 @@ type CoordinatePoint struct {
 	YEdbInfoId int
 	XDate      string
 	YDate      string
+	DateType   int `description:"日期类型:1-最新日期;2-N天前;3-固定日期"`
+	DaysAgo    int `description:"N天前的N值"`
 }
 
 // GetChartData
@@ -140,7 +142,12 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 
 	dataMap := make(map[string]float64)
 	dateMap := make(map[string]string)
+	dateTypeMap := make(map[int]int) // 日期配置key对应的日期类型
+	daysAgoMap := make(map[int]int)  // 日期配置key对应的N天前的N值
+
 	for dateIndex, dateConfig := range config.DateConfigList {
+		dateTypeMap[dateIndex] = dateConfig.DateType
+		daysAgoMap[dateIndex] = dateConfig.Num
 		for _, edbInfoMapping := range mappingList {
 			// 数据会是正序的
 			dataList, ok := edbDataListMap[edbInfoMapping.EdbInfoId]
@@ -162,19 +169,18 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 				err = tmpErr
 				return
 			}
-
 			// 数据开始日期
 			endDateStr := ``
 			var endDate time.Time
-			var currVal float64
 
+			var currVal float64
 			switch dateConfig.DateType {
 			case 1: // 1:最新日期;
 				endDateStr = dataEndDateStr
 				endDate = dataEndDate
 				currVal = dataList[k].Value
-			case 2: // 2:N天前
-				tmpEndDate := currDay.AddDate(0, 0, -dateConfig.Num)
+			case 2: // 2:N天前(原为指标最新日期的N天前, 现为系统日期的N天)
+				tmpEndDate := time.Now().AddDate(0, 0, -dateConfig.Num)
 				tmpEndDateStr := tmpEndDate.Format(utils.FormatDate)
 
 				for i := k; i >= 0; i-- {
@@ -202,6 +208,45 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 					currVal = dataList[i].Value
 					break
 				}
+			case 3: // 固定日期
+				if dateConfig.FixDate == "" {
+					errMsg = "固定日期不可为空"
+					err = fmt.Errorf("固定日期为空")
+					return
+				}
+				strFixDate := dateConfig.FixDate
+				fixDate, e := time.ParseInLocation(utils.FormatDate, strFixDate, time.Local)
+				if e != nil {
+					errMsg = "固定日期格式有误"
+					err = fmt.Errorf("固定日期有误, FixDate: %s", dateConfig.FixDate)
+					return
+				}
+
+				for i := k; i >= 0; i-- {
+					strThisDate := dataList[i].DataTime
+					// 如果正好是这一天,那么就直接break了
+					if strFixDate == strThisDate {
+						k = i
+						endDateStr = strThisDate
+						endDate = fixDate
+						currVal = dataList[i].Value
+						break
+					}
+					// 若固定日期无值, 则取固定日期之前, 能找到的第一个值(同上N天前的逻辑)
+					thisDate, e := time.ParseInLocation(utils.FormatDate, strThisDate, time.Local)
+					if e != nil {
+						err = fmt.Errorf("数据日期格式有误: %s", e.Error())
+						return
+					}
+					if thisDate.After(fixDate) {
+						continue
+					}
+					k = i
+					endDateStr = strThisDate
+					endDate = thisDate
+					currVal = dataList[i].Value
+					break
+				}
 			}
 
 			// 没有找到日期,那么就不处理
@@ -213,51 +258,85 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 			earliestDate := endDate.AddDate(0, 0, -config.CalculateValue*moveUnitDays)
 			earliestDateStr := earliestDate.Format(utils.FormatDate)
 
-			var minVal, maxVal float64
-			var isNotFirst bool // 是否是第一条数据
-			for i := k; i >= 0; i-- {
-				tmpData := dataList[i]
-				if !isNotFirst {
-					maxVal = tmpData.Value
-					minVal = tmpData.Value
-					isNotFirst = true
-					continue
-				}
+			var percentVal float64 // 百分位计算值
+			// 百分位数据区间算法
+			if config.PercentType == utils.PercentCalculateTypeRange {
+				var minVal, maxVal float64
+				var isNotFirst bool // 是否是第一条数据
+				for i := k; i >= 0; i-- {
+					tmpData := dataList[i]
+					if !isNotFirst {
+						maxVal = tmpData.Value
+						minVal = tmpData.Value
+						isNotFirst = true
+						continue
+					}
 
-				tmpDateStr := dataList[i].DataTime
-				// 如果正好是这一天,那么就直接break了
-				if earliestDateStr == tmpDateStr {
-					break
-				}
-				tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local)
-				if tmpErr != nil {
-					err = tmpErr
-					return
+					tmpDateStr := dataList[i].DataTime
+					// 如果正好是这一天,那么就直接break了
+					if earliestDateStr == tmpDateStr {
+						break
+					}
+					tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					// 如果这期的日期早于选择的日期,那么继续停止遍历
+					if tmpDate.Before(earliestDate) {
+						continue
+					}
+
+					if tmpData.Value > maxVal {
+						maxVal = tmpData.Value
+					}
+					if tmpData.Value < minVal {
+						minVal = tmpData.Value
+					}
 				}
-				// 如果这期的日期早于选择的日期,那么继续停止遍历
-				if tmpDate.Before(earliestDate) {
+
+				// 最大值等于最小值,说明计算结果无效
+				if maxVal == minVal {
 					continue
 				}
+				// 数据区间百分位=(现值-Min)/(Max-Min)
+				tmpV := (currVal - minVal) / (maxVal - minVal) * 100
+				percentVal, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
+			}
 
-				if tmpData.Value > maxVal {
-					maxVal = tmpData.Value
+			// 百分位数据个数算法
+			// 数据区间第一个和最后一个数据点的时间和数据分别为(T1,S1)(T2,S2); N=T1到T2指标数据个数, n=小于等于S2的数据个数
+			// 个数百分位=(n-1)/(N-1)
+			if config.PercentType == utils.PercentCalculateTypeNum {
+				// T1为earliestDate, T2为endDate, S2为currVal
+				var tinyN, bigN int
+				lastVal := decimal.NewFromFloat(currVal)
+				for i := k; i >= 0; i-- {
+					date, e := time.ParseInLocation(utils.FormatDate, dataList[i].DataTime, time.Local)
+					if e != nil {
+						err = fmt.Errorf("数据日期格式有误: %s", e.Error())
+						return
+					}
+					if !date.Before(earliestDate) && !date.After(endDate) {
+						bigN += 1
+					}
+					dateVal := decimal.NewFromFloat(dataList[i].Value)
+					if dateVal.LessThanOrEqual(lastVal) {
+						tinyN += 1
+					}
 				}
-				if tmpData.Value < minVal {
-					minVal = tmpData.Value
+				// N=1时说明计算无效
+				if bigN == 1 {
+					continue
 				}
+				numerator := decimal.NewFromInt(int64(tinyN - 1))
+				denominator := decimal.NewFromInt(int64(bigN - 1))
+				percentVal, _ = numerator.Div(denominator).Round(4).Float64()
 			}
 
-			// 最大值等于最小值,说明计算结果无效
-			if maxVal == minVal {
-				continue
-			}
-			//百分位=(现值-Min)/(Max-Min)
-			tmpV := (currVal - minVal) / (maxVal - minVal) * 100
-			tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
-
 			// key的生成(日期配置下标+指标id)
 			key := fmt.Sprint(dateIndex, "_", edbInfoMapping.EdbInfoId)
-			dataMap[key] = tmpV
+			dataMap[key] = percentVal
 			dateMap[key] = endDateStr
 		}
 	}
@@ -283,7 +362,7 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 
 		coordinatePointList := make([]CoordinatePoint, 0)
 
-		for dateIndex := range config.DateConfigList {
+		for dateIndex, _ := range config.DateConfigList {
 			key1 := fmt.Sprint(dateIndex, "_", xEdbInfoId)
 			xVal, ok1 := dataMap[key1]
 			if !ok1 {
@@ -321,6 +400,8 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 				YEdbInfoId: yEdbInfoId,
 				XDate:      dateMap[key1],
 				YDate:      dateMap[key2],
+				DateType:   dateTypeMap[dateIndex], // 日期类型
+				DaysAgo:    daysAgoMap[dateIndex],  // N天前的N值
 			})
 		}
 
@@ -356,7 +437,7 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*mo
 	}
 
 	// 去除返回指标中的数据信息,避免没必要的数据传输
-	for k := range edbList {
+	for k, _ := range edbList {
 		edbList[k].DataList = nil
 	}
 

+ 80 - 31
services/data/line_feature/chart_info.go

@@ -78,7 +78,7 @@ func GetStandardDeviationData(chartInfoId int, startDate, endDate string, mappin
 }
 
 // GetPercentileData 获取百分位图表的指标数据
-func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int, calculateUnit string) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
+func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *models.ChartEdbInfoMapping, calculateValue int, calculateUnit string, percentType int) (edbList []*models.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
 	edbList = make([]*models.ChartEdbInfoMapping, 0)
 	moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit]
 	if !ok {
@@ -111,41 +111,90 @@ func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *
 	}
 
 	//百分位:对所选指标滚动地取对应时间长度的数据值,取最大值Max,最小值Min,计算Max-Min,百分位=(现值-Min)/(Max-Min),Max=Min时不予计算。
-	for i, tmpData := range dataList {
-		currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
-		maxVal := tmpData.Value
-		minVal := tmpData.Value
-		for k := 0; k < calculateDay; k++ {
-			preVal, ok2 := dataMap[currDateTime.AddDate(0, 0, -k)]
-			if ok2 {
-				if preVal > maxVal {
-					maxVal = preVal
-				}
-				if preVal < minVal {
-					minVal = preVal
+	if percentType == utils.PercentCalculateTypeRange {
+		for i, tmpData := range dataList {
+			currDateTime, _ := time.ParseInLocation(utils.FormatDate, tmpData.DataTime, time.Local)
+			maxVal := tmpData.Value
+			minVal := tmpData.Value
+			for k := 0; k < calculateDay; k++ {
+				preVal, ok2 := dataMap[currDateTime.AddDate(0, 0, -k)]
+				if ok2 {
+					if preVal > maxVal {
+						maxVal = preVal
+					}
+					if preVal < minVal {
+						minVal = preVal
+					}
 				}
 			}
-		}
 
-		if maxVal == minVal {
-			continue
-		}
-		//百分位=(现值-Min)/(Max-Min)
-		tmpV := (tmpData.Value - minVal) / (maxVal - minVal) * 100
-		tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
-		newDataList = append(newDataList, models.EdbDataList{
-			EdbDataId:     i,
-			EdbInfoId:     edb.EdbInfoId,
-			DataTime:      dataList[i].DataTime,
-			DataTimestamp: dataList[i].DataTimestamp,
-			Value:         tmpV,
-		})
+			if maxVal == minVal {
+				continue
+			}
+			//百分位=(现值-Min)/(Max-Min)
+			tmpV := (tmpData.Value - minVal) / (maxVal - minVal) * 100
+			tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
+			newDataList = append(newDataList, models.EdbDataList{
+				EdbDataId:     i,
+				EdbInfoId:     edb.EdbInfoId,
+				DataTime:      dataList[i].DataTime,
+				DataTimestamp: dataList[i].DataTimestamp,
+				Value:         tmpV,
+			})
 
-		if tmpV < edbMinVal {
-			edbMinVal = tmpV
+			if tmpV < edbMinVal {
+				edbMinVal = tmpV
+			}
+			if tmpV > edbMaxVal {
+				edbMaxVal = tmpV
+			}
 		}
-		if tmpV > edbMaxVal {
-			edbMaxVal = tmpV
+	}
+
+	// 百分位数据个数算法
+	// 数据区间第一个和最后一个数据点的时间和数据分别为(T1,S1)(T2,S2); N=T1到T2指标数据个数, n=小于等于S2的数据个数
+	// 个数百分位=(n-1)/(N-1)
+	if percentType == utils.PercentCalculateTypeNum {
+		for i, d := range dataList {
+			// T2为当前日期
+			s2 := decimal.NewFromFloat(d.Value)
+			t2, _ := time.ParseInLocation(utils.FormatDate, d.DataTime, time.Local)
+
+			// 计算N和n
+			var bigN, tinyN int
+			for k := 0; k < calculateDay; k++ {
+				preVal, preOk := dataMap[t2.AddDate(0, 0, -k)]
+				if !preOk {
+					continue
+				}
+				bigN += 1
+				if decimal.NewFromFloat(preVal).LessThanOrEqual(s2) {
+					tinyN += 1
+				}
+			}
+
+			// N=1时说明计算无效
+			if bigN == 1 {
+				continue
+			}
+			numerator := decimal.NewFromInt(int64(tinyN - 1))
+			denominator := decimal.NewFromInt(int64(bigN - 1))
+			percentVal, _ := numerator.Div(denominator).Round(4).Float64()
+
+			// 写进数组并判断指标最大最小值
+			newDataList = append(newDataList, models.EdbDataList{
+				EdbDataId:     i,
+				EdbInfoId:     edb.EdbInfoId,
+				DataTime:      dataList[i].DataTime,
+				DataTimestamp: dataList[i].DataTimestamp,
+				Value:         percentVal,
+			})
+			if percentVal < edbMinVal {
+				edbMinVal = percentVal
+			}
+			if percentVal > edbMaxVal {
+				edbMaxVal = percentVal
+			}
 		}
 	}
 

+ 5 - 0
utils/constants.go

@@ -202,3 +202,8 @@ const (
 	DATA_SUB_SOURCE_EDB  = iota //经济数据库
 	DATA_SUB_SOURCE_DATE        //日期序列
 )
+
+const (
+	PercentCalculateTypeRange = 0 // 百分位算法类型-数据区间
+	PercentCalculateTypeNum   = 1 // 百分位算法类型-数据个数
+)