Ver Fonte

Merge branch 'feature/eta_1.6.8'

hsun há 1 ano atrás
pai
commit
9b1f904f30

+ 1 - 1
controllers/data_manage/chart_common.go

@@ -259,7 +259,7 @@ func GetLineFeatureChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInf
 			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 request.FrequencyDistribution
 		err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &frequencyDistributionConfig)

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

@@ -1575,3 +1575,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 - 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:"图表右侧最小值"`
@@ -1343,6 +1345,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:"图表右侧最小值"`

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

@@ -9,44 +9,48 @@ 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"`
+	SourcesFrom  string `description:"图表来源"`
+	Instructions string `description:"图表说明"`
+	MarkersLines string `description:"标识线"`
+	MarkersAreas string `description:"标识区"`
 }
 
 // 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
@@ -78,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

@@ -34,6 +34,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

@@ -160,6 +160,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/cross_variety:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/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_mobile/controllers/data_manage/cross_variety:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/cross_variety:ChartInfoController"],
         beego.ControllerComments{
             Method: "SearchByEs",

+ 166 - 46
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]
@@ -173,25 +183,28 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 			if lenData <= 0 {
 				continue
 			}
+			// 数据的开始索引
+			k := lenData - 1
 
+			// 数据的最晚日期
+			dataEndDateStr := dataList[k].DataTime
+			dataEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, dataEndDateStr, time.Local)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
 			// 数据开始日期
 			endDateStr := ``
 			var endDate time.Time
-			// 数据的开始索引
-			k := lenData - 1
+
 			var currVal float64
 			switch dateConfig.DateType {
 			case 1: // 1:最新日期;
-				endDateStr = dataList[k].DataTime
-				tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
-				if tmpErr != nil {
-					err = tmpErr
-					return
-				}
-				endDate = tmpDate
+				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-- {
@@ -200,6 +213,7 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 					if tmpEndDateStr == tmpDateStr {
 						k = i
 						endDateStr = tmpDateStr
+						endDate = tmpEndDate
 						currVal = dataList[i].Value
 						break
 					}
@@ -218,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
+				}
 			}
 
 			// 没有找到日期,那么就不处理
@@ -229,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
 		}
 	}
@@ -337,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], // 是否显示标注
 			})
 		}
 
@@ -347,6 +437,7 @@ func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*da
 			CoordinatePointData: coordinatePointList,
 		})
 	}
+
 	// 处理颜色
 	colorMap := utils.GetColorMap()
 	for k, _ := range dataList {
@@ -507,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 = "请选择品种!"
@@ -543,6 +640,9 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin) (chartInfo *da
 			return
 		}
 
+		// 分类没有,需要创建新的分类,那么err置空
+		err = nil
+
 		timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 		chartClassify = &data_manage.ChartClassify{
 			ChartClassifyId:   0,
@@ -558,6 +658,7 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin) (chartInfo *da
 			Sort:              0,
 			Source:            source,
 		}
+		_, err = data_manage.AddChartClassify(chartClassify)
 	}
 
 	var chartInfoId int
@@ -586,6 +687,7 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin) (chartInfo *da
 	//chartInfo.ChartClassifyId = req.ChartClassifyId
 	chartInfo.SysUserId = sysUser.AdminId
 	chartInfo.SysUserRealName = sysUser.RealName
+	chartInfo.ChartImage = req.ChartImage
 	chartInfo.CreateTime = time.Now()
 	chartInfo.ModifyTime = time.Now()
 	chartInfo.IsSetName = 0
@@ -600,11 +702,19 @@ 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
 	chartInfo.Source = source
 	chartInfo.ExtraConfig = string(extraConfigByte)
+	chartInfo.ChartImage = req.ChartImage
+	chartInfo.ChartThemeId = req.ChartThemeId
+	chartInfo.SourcesFrom = req.SourcesFrom
+	chartInfo.Instructions = req.Instructions
+	chartInfo.MarkersLines = req.MarkersLines
+	chartInfo.MarkersAreas = req.MarkersAreas
 
 	// 图表品种
 	chartVarietyMappingList := make([]*cross_varietyModel.ChartVarietyMapping, 0)
@@ -708,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 = "请选择品种!"
@@ -767,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)

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

@@ -403,3 +403,8 @@ const (
 const (
 	TelAreaCodeHome = "86" // 大陆区号
 )
+
+const (
+	PercentCalculateTypeRange = 0 // 百分位算法类型-数据区间
+	PercentCalculateTypeNum   = 1 // 百分位算法类型-数据个数
+)