浏览代码

Merge branch 'feature/eta_1.6.8' into debug

hsun 1 年之前
父节点
当前提交
c96bd20f22

+ 4 - 4
controllers/data_manage/line_feature/chart_info.go

@@ -282,7 +282,7 @@ func (this *LineFeaturesChartInfoController) MultipleGraphPreview() {
 			tmpChartInfo.ChartName = fmt.Sprintf("%s%d%s百分位", edbInfoMapping.EdbName, req.Percentile.CalculateValue, req.Percentile.CalculateUnit)
 
 			// 获取图表中的指标数据
-			edbList, dataResp, err, errMsg := lineFeatureServ.GetPercentileData(0, startDate, endDate, edbInfoMapping, req.Percentile.CalculateValue, req.Percentile.CalculateUnit)
+			edbList, dataResp, err, errMsg := lineFeatureServ.GetPercentileData(0, startDate, endDate, edbInfoMapping, req.Percentile.CalculateValue, req.Percentile.CalculateUnit, req.Percentile.PercentType)
 			if err != nil && errMsg != `` {
 				br.Msg = errMsg
 				br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -694,7 +694,7 @@ func (this *LineFeaturesChartInfoController) MultipleGraphConfigSaveChart() {
 			extraConfig = string(extraConfigByte)
 
 			// 获取图表中的指标数据
-			_, dataResp, err, errMsg := lineFeatureServ.GetPercentileData(0, startDate, endDate, edbInfoMapping, req.Percentile.CalculateValue, req.Percentile.CalculateUnit)
+			_, dataResp, err, errMsg := lineFeatureServ.GetPercentileData(0, startDate, endDate, edbInfoMapping, req.Percentile.CalculateValue, req.Percentile.CalculateUnit, req.Percentile.PercentType)
 			if err != nil && errMsg != `` {
 				br.Msg = errMsg
 				br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -1849,7 +1849,7 @@ func (this *LineFeaturesChartInfoController) Detail() {
 			maxYear = latestDateT.Year()
 		}
 		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
-		edbList, resultResp, err, errMsg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit)
+		edbList, resultResp, err, errMsg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit, percentileConfig.PercentType)
 	case utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		var frequencyDistributionConfig request.FrequencyDistribution
 		err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &frequencyDistributionConfig)
@@ -2346,7 +2346,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 			maxYear = latestDateT.Year()
 		}
 		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
-		edbList, resultResp, err, msg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit)
+		edbList, resultResp, err, msg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit, percentileConfig.PercentType)
 	case utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		var frequencyDistributionConfig request.FrequencyDistribution
 		err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &frequencyDistributionConfig)

+ 16 - 23
models/data_manage/cross_variety/request/chart.go

@@ -9,28 +9,26 @@ 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-是"`
 }
 
 // AddChartReq
 // @Description: 添加图表的请求
 type AddChartReq struct {
-	ChartName      string            `description:"图表名称"`
-	LeftMin        string            `description:"图表左侧最小值"`
-	LeftMax        string            `description:"图表左侧最大值"`
-	ChartImage     string            `description:"图表截图,复制的时候才用到" json:"-"`
-	TagX           int               `description:"X轴的标签ID"`
-	TagY           int               `description:"Y轴的标签ID"`
-	CalculateValue int               `description:"计算窗口"`
-	CalculateUnit  string            `description:"计算频度"`
-	DateConfigList []ChartConfigDate `description:"日期配置列表"`
-	VarietyList    []int
+	ChartName      string `description:"图表名称"`
+	LeftMin        string `description:"图表左侧最小值"`
+	LeftMax        string `description:"图表左侧最大值"`
+	ChartImage     string `description:"图表截图,复制的时候才用到" json:"-"`
+	ChartConfigReq `description:"跨品种分析的图表配置"`
 
 	// 主题相关
 	ChartThemeId int    `description:"图表应用主题ID"`
@@ -43,17 +41,12 @@ type AddChartReq struct {
 // EditChartReq
 // @Description: 编辑图表的请求
 type EditChartReq struct {
-	ChartInfoId    int               `description:"图表id"`
-	ChartName      string            `description:"图表名称"`
-	LeftMin        string            `description:"图表左侧最小值"`
-	LeftMax        string            `description:"图表左侧最大值"`
-	ChartImage     string            `description:"图表截图,复制的时候才用到" json:"-"`
-	TagX           int               `description:"X轴的标签ID"`
-	TagY           int               `description:"Y轴的标签ID"`
-	CalculateValue int               `description:"计算窗口"`
-	CalculateUnit  string            `description:"计算频度"`
-	DateConfigList []ChartConfigDate `description:"日期配置列表"`
-	VarietyList    []int
+	ChartInfoId    int    `description:"图表id"`
+	ChartName      string `description:"图表名称"`
+	LeftMin        string `description:"图表左侧最小值"`
+	LeftMax        string `description:"图表左侧最大值"`
+	ChartImage     string `description:"图表截图,复制的时候才用到" json:"-"`
+	ChartConfigReq `description:"跨品种分析的图表配置"`
 }
 
 // CopyAddChartInfoReq

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

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

+ 130 - 36
services/data/cross_variety/chart.go

@@ -66,6 +66,8 @@ type CoordinatePoint struct {
 	YEdbInfoId int
 	XDate      string
 	YDate      string
+	DateType   int `description:"日期类型:1-最新日期;2-N天前;3-固定日期"`
+	DaysAgo    int `description:"N天前的N值"`
 }
 
 // GetChartData
@@ -161,7 +163,12 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 
 	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]
@@ -193,8 +200,8 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 				endDateStr = dataEndDateStr
 				endDate = dataEndDate
 				currVal = dataList[k].Value
-			case 2: // 2:N天前
-				tmpEndDate := dataEndDate.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-- {
@@ -222,6 +229,45 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 					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
+				}
 			}
 
 			// 没有找到日期,那么就不处理
@@ -233,51 +279,85 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 			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
 		}
 	}
@@ -341,6 +421,8 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 				YEdbInfoId: yEdbInfoId,
 				XDate:      dateMap[key1],
 				YDate:      dateMap[key2],
+				DateType:   dateTypeMap[dateIndex], // 日期类型
+				DaysAgo:    daysAgoMap[dateIndex],  // N天前的N值
 			})
 		}
 
@@ -512,6 +594,12 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin) (chartInfo *da
 		isSendEmail = false
 		return
 	}
+	if req.PercentType != utils.PercentCalculateTypeRange && req.PercentType != utils.PercentCalculateTypeNum {
+		errMsg = "请选择百分位"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
 	// 品种配置
 	if len(req.VarietyList) < 0 {
 		errMsg = "请选择品种!"
@@ -724,6 +812,12 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin) (chartItem *
 		isSendEmail = false
 		return
 	}
+	if req.PercentType != utils.PercentCalculateTypeRange && req.PercentType != utils.PercentCalculateTypeNum {
+		errMsg = "请选择百分位"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
 	// 品种配置
 	if len(req.VarietyList) < 0 {
 		errMsg = "请选择品种!"

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

@@ -82,7 +82,7 @@ func GetStandardDeviationData(chartInfoId int, startDate, endDate string, mappin
 }
 
 // GetPercentileData 获取百分位图表的指标数据
-func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *data_manage.ChartEdbInfoMapping, calculateValue int, calculateUnit string) (edbList []*data_manage.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
+func GetPercentileData(chartInfoId int, startDate, endDate string, mappingInfo *data_manage.ChartEdbInfoMapping, calculateValue int, calculateUnit string, percentType int) (edbList []*data_manage.ChartEdbInfoMapping, dataResp response.LineFeatureDataResp, err error, errMsg string) {
 	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
 	moveUnitDays, ok := utils.FrequencyDaysMap[calculateUnit]
 	if !ok {
@@ -115,41 +115,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, data_manage.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, data_manage.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, data_manage.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

@@ -413,3 +413,8 @@ const (
 const (
 	LdapInitPassword = "123456a" // 域用户初始密码
 )
+
+const (
+	PercentCalculateTypeRange = 0 // 百分位算法类型-数据区间
+	PercentCalculateTypeNum   = 1 // 百分位算法类型-数据个数
+)