Browse Source

Merge branch 'feature/eta_1.6.8'

hsun 1 year ago
parent
commit
d140638608

+ 86 - 0
controllers/data_manage/cross_variety/chart_info.go

@@ -1586,3 +1586,89 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 	isOk = true
 	return
 }
+
+// Save
+// @Title 保存图表
+// @Description 保存图表
+// @Param	request	body request.SaveChartReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /chart_info/save [post]
+func (c *ChartInfoController) Save() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = true
+		}
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.SaveChartReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ChartInfoId: %d", req.ChartInfoId)
+		return
+	}
+
+	chartItem, e := data_manage.GetChartInfoById(req.ChartInfoId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "保存失败"
+		br.ErrMsg = "获取图表信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 更新图表上下限
+	chartItem.LeftMin = req.LeftMin
+	chartItem.LeftMax = req.LeftMax
+	chartItem.XMin = req.XMin
+	chartItem.XMax = req.XMax
+	chartUpdateCols := []string{"ChartName", "ExtraConfig", "ModifyTime", "LeftMin", "LeftMax", "XMin", "XMax"}
+	if e = chartItem.Update(chartUpdateCols); e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "更新图表上下限失败, Err: " + e.Error()
+		return
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartItem.ChartInfoId
+	resp.UniqueCode = chartItem.UniqueCode
+
+	// 新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "保存跨品种分析图表"
+		chartLog.Method = c.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}

+ 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)

+ 4 - 0
models/data_manage/chart_info.go

@@ -32,6 +32,8 @@ type ChartInfo struct {
 	SeasonEndDate     string `description:"季节性图开始日期"`
 	ChartImage        string `description:"图表图片"`
 	Sort              int    `description:"排序字段,数字越小越排前面"`
+	XMin              string `description:"图表X轴最小值"`
+	XMax              string `description:"图表X轴最大值"`
 	LeftMin           string `description:"图表左侧最小值"`
 	LeftMax           string `description:"图表左侧最大值"`
 	RightMin          string `description:"图表右侧最小值"`
@@ -1389,6 +1391,8 @@ type ChartInfoView struct {
 	MyChartClassifyId string `description:"我的图表分类,多个用逗号隔开"`
 	ChartClassify     []*ChartClassifyView
 	EdbEndDate        string `description:"指标最新更新日期"`
+	XMin              string `description:"图表X轴最小值"`
+	XMax              string `description:"图表X轴最大值"`
 	LeftMin           string `description:"图表左侧最小值"`
 	LeftMax           string `description:"图表左侧最大值"`
 	RightMin          string `description:"图表右侧最小值"`

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

@@ -9,28 +9,28 @@ 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:"图表名称"`
+	XMin           string `description:"图表X轴最小值"`
+	XMax           string `description:"图表X轴最大值"`
+	LeftMin        string `description:"图表左侧最小值"`
+	LeftMax        string `description:"图表左侧最大值"`
+	ChartImage     string `description:"图表截图,复制的时候才用到" json:"-"`
+	ChartConfigReq `description:"跨品种分析的图表配置"`
 
 	// 主题相关
 	ChartThemeId int    `description:"图表应用主题ID"`
@@ -43,17 +43,14 @@ 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:"图表名称"`
+	XMin           string `description:"图表X轴最小值"`
+	XMax           string `description:"图表X轴最大值"`
+	LeftMin        string `description:"图表左侧最小值"`
+	LeftMax        string `description:"图表左侧最大值"`
+	ChartImage     string `description:"图表截图,复制的时候才用到" json:"-"`
+	ChartConfigReq `description:"跨品种分析的图表配置"`
 }
 
 // CopyAddChartInfoReq
@@ -85,3 +82,13 @@ type VarietyNameEnReq struct {
 	ChartVarietyId int    `json:"ChartVarietyId"`
 	VarietyNameEn  string `json:"VarietyNameEn"`
 }
+
+// SaveChartReq
+// @Description: 保存图表的请求
+type SaveChartReq struct {
+	ChartInfoId int    `description:"图表ID"`
+	XMin        string `description:"图表X轴最小值"`
+	XMax        string `description:"图表X轴最大值"`
+	LeftMin     string `description:"图表左侧最小值"`
+	LeftMax     string `description:"图表左侧最大值"`
+}

+ 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 {

+ 9 - 0
routers/commentsRouter.go

@@ -340,6 +340,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/cross_variety:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/cross_variety:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "Save",
+            Router: `/chart_info/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/cross_variety:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/cross_variety:ChartInfoController"],
         beego.ControllerComments{
             Method: "SearchByEs",

+ 141 - 37
services/data/cross_variety/chart.go

@@ -66,6 +66,9 @@ type CoordinatePoint struct {
 	YEdbInfoId int
 	XDate      string
 	YDate      string
+	DateType   int `description:"日期类型:1-最新日期;2-N天前;3-固定日期"`
+	DaysAgo    int `description:"N天前的N值"`
+	ShowTips   int `description:"是否显示标注:0-否;1-是"`
 }
 
 // GetChartData
@@ -161,7 +164,14 @@ 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值
+	showTipsMap := make(map[int]int) // 日期配置key对应点是否显示标注
+
 	for dateIndex, dateConfig := range config.DateConfigList {
+		dateTypeMap[dateIndex] = dateConfig.DateType
+		daysAgoMap[dateIndex] = dateConfig.Num
+		showTipsMap[dateIndex] = dateConfig.ShowTips
 		for _, edbInfoMapping := range mappingList {
 			// 数据会是正序的
 			dataList, ok := edbDataListMap[edbInfoMapping.EdbInfoId]
@@ -193,8 +203,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 +232,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 +282,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).Mul(decimal.NewFromFloat(100)).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 +424,9 @@ 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值
+				ShowTips:   showTipsMap[dateIndex], // 是否显示标注
 			})
 		}
 
@@ -512,6 +598,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 = "请选择品种!"
@@ -610,6 +702,8 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin) (chartInfo *da
 	//chartInfo.SeasonEndDate = req.EndDate
 	chartInfo.LeftMin = req.LeftMin
 	chartInfo.LeftMax = req.LeftMax
+	chartInfo.XMin = req.XMin
+	chartInfo.XMax = req.XMax
 	//chartInfo.RightMin = req.RightMin
 	//chartInfo.RightMax = req.RightMax
 	//chartInfo.Disabled = disableVal
@@ -724,6 +818,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 = "请选择品种!"
@@ -783,7 +883,11 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin) (chartItem *
 	chartItem.ChartName = req.ChartName
 	chartItem.ExtraConfig = string(extraConfigByte)
 	chartItem.ModifyTime = time.Now()
-	chartUpdateCols := []string{"ChartName", "ExtraConfig", "ModifyTime"}
+	chartItem.LeftMin = req.LeftMin
+	chartItem.LeftMax = req.LeftMax
+	chartItem.XMin = req.XMin
+	chartItem.XMax = req.XMax
+	chartUpdateCols := []string{"ChartName", "ExtraConfig", "ModifyTime", "LeftMin", "LeftMax", "XMin", "XMax"}
 
 	// 跨品种分析配置
 	chartInfoCrossVariety, err := cross_varietyModel.GetChartInfoCrossVarietyByChartInfoId(chartItem.ChartInfoId)

+ 81 - 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,91 @@ 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))
+			// 因为是百分位所以这里是要*100, 跟之前的算法保持同步
+			percentVal, _ := numerator.Div(denominator).Mul(decimal.NewFromFloat(100)).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

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