浏览代码

Merge branch 'ETA_1.9.4' into debug

# Conflicts:
#	models/data_manage/chart_info.go
zwxi 9 月之前
父节点
当前提交
e1f4c2e42b
共有 3 个文件被更改,包括 171 次插入23 次删除
  1. 32 22
      models/data_manage/chart_info.go
  2. 70 1
      services/data/chart_info.go
  3. 69 0
      services/data/edb_info_calculate.go

+ 32 - 22
models/data_manage/chart_info.go

@@ -2,6 +2,7 @@ package data_manage
 
 import (
 	"errors"
+	"eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/models/mgo"
 	"eta/eta_api/utils"
 	"fmt"
@@ -264,22 +265,31 @@ type EditChartInfoReq struct {
 }
 
 type MarkersLine struct {
-	Axis             int    `json:"axis" description:"1左轴 2右轴 3横轴"`
-	AxisName         string `json:"axisName" description:"轴的名称,例如'左轴'"`
-	MarkLineType     int    `json:"markLineType" description:"1:固定 2:指标计算"`
-	Value            string `json:"value" description:"连线指向的数值,例如'4000'"`
-	From             string `json:"from" description:"连线的起始点,可以为空"`
-	To               string `json:"to" description:"连线的结束点,可以为空"`
-	LineWidth        int    `json:"lineWidth" description:"连线的宽度"`
-	DashStyle        string `json:"dashStyle" description:"连线的虚线样式,例如'ShortDashDot'"`
-	Color            string `json:"color" description:"连线的颜色"`
-	Text             string `json:"text" description:"连线旁边显示的文本"`
-	TextPosition     string `json:"textPosition" description:"文本的显示位置,例如'bottom'"`
-	TextColor        string `json:"textColor" description:"文本颜色"`
-	TextFontSize     int    `json:"textFontSize" description:"文本的字号大小"`
-	IsShow           bool   `json:"isShow" description:"是否显示连线及文本"`
-	Calculation      int    `json:"calculation" description:"计算方式 1区间均值 2区间均值加N倍标准差 3区间个数分位 4区间数值分位"`
-	CalculationValue int    `json:"calculationValue" description:"计算方式对应的值 2就是几倍标准差 3就是分位值 4就是数值值·"`
+	Axis             int             `json:"axis" description:"1左轴 2右轴 3横轴"`
+	AxisName         string          `json:"axisName" description:"轴的名称,例如'左轴'"`
+	MarkLineType     int             `json:"markLineType" description:"1:固定 2:指标计算"`
+	Value            string          `json:"value" description:"连线指向的数值,例如'4000'"`
+	From             string          `json:"from" description:"连线的起始点,可以为空"`
+	To               string          `json:"to" description:"连线的结束点,可以为空"`
+	LineWidth        int             `json:"lineWidth" description:"连线的宽度"`
+	DashStyle        string          `json:"dashStyle" description:"连线的虚线样式,例如'ShortDashDot'"`
+	Color            string          `json:"color" description:"连线的颜色"`
+	Text             string          `json:"text" description:"连线旁边显示的文本"`
+	TextPosition     string          `json:"textPosition" description:"文本的显示位置,例如'bottom'"`
+	TextColor        string          `json:"textColor" description:"文本颜色"`
+	TextFontSize     int             `json:"textFontSize" description:"文本的字号大小"`
+	IsShow           bool            `json:"isShow" description:"是否显示连线及文本"`
+	Calculation      int             `json:"calculation" description:"计算方式 1区间均值 2区间均值加N倍标准差 3区间个数分位 4区间数值分位"`
+	CalculationValue int             `json:"calculationValue" description:"计算方式对应的值 2就是几倍标准差 3就是分位值 4就是数值值·"`
+	TimeIntervalType int             `json:"timeInterval" description:"时间区间 0跟随图表 1自定义"`
+	StartDate        MarkersLineTime `json:"startTime" description:"开始时间"`
+	EndDate          MarkersLineTime `json:"endTime" description:"结束时间"`
+}
+
+type MarkersLineTime struct {
+	TimeType int                       `json:"timeType" description:"时间类型 1固定 2动态"`
+	Date     string                    `json:"date" description:"日期"`
+	Conf     request.EdbDateChangeConf `json:"conf" description:"动态时间配置"`
 }
 
 type EditFutureGoodChartInfoReq struct {
@@ -1565,18 +1575,18 @@ type SamePeriodAverageData struct {
 
 // 自定义同期标准差
 type SamePeriodStandardDeviation struct {
-	Color    string `description:"颜色"`
-	Year     int    `description:"标准差取值范围"`
-	Legend   string `description:"图例名称"`
-	Multiple int    `description:"标准差倍数"`
-	IsShow   bool   `description:"是否显示"`
+	Color    string  `description:"颜色"`
+	Year     int     `description:"标准差取值范围"`
+	Legend   string  `description:"图例名称"`
+	Multiple float64 `description:"标准差倍数"`
+	IsShow   bool    `description:"是否显示"`
 }
 
 type SamePeriodStandardDeviationResp struct {
 	Color    string              `description:"颜色"`
 	Year     int                 `description:"标准差取值范围"`
 	Legend   string              `description:"图例名称"`
-	Multiple int                 `description:"标准差倍数"`
+	Multiple float64             `description:"标准差倍数"`
 	IsShow   bool                `description:"是否显示"`
 	List     []*MaxMinLimitsData `description:"自定义标准差列表"`
 }

+ 70 - 1
services/data/chart_info.go

@@ -3186,6 +3186,10 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 
 	// 特殊图形数据处理
 	switch chartType {
+	case 2: // 季节性图
+		if seasonExtraConfig != "" {
+			dataResp, err = SeasonChartData(edbList, seasonExtraConfig)
+		}
 	case 7: // 柱形图
 		barChartConf := extraConfig.(data_manage.BarChartInfoReq)
 		xEdbIdValue, yDataList, err = BarChartData(mappingList, edbDataListMap, barChartConf.DateList, barChartConf.Sort)
@@ -3409,8 +3413,73 @@ func SeasonChartData(dataList []*data_manage.ChartEdbInfoMapping, seasonExtraCon
 		}
 
 		// 自定义同期标准差
-		if seasonConfig.SamePeriodAverage.Year > 0 {
+		if seasonConfig.SamePeriodStandardDeviation.Year > 1 && seasonConfig.SamePeriodStandardDeviation.Multiple > 0 {
+			// 先算均值,再算标准差
+			handleDataMap := make(map[string]float64)
+			dataTimeMap := make(map[time.Time]time.Time)
+			dataTimeValueMap := make(map[time.Time][]float64)
+			dataTimeList := make([]string, 0)
+			valueMap := make(map[time.Time]float64)
+
+			samePeriodStandardDeviationList := make([]*data_manage.MaxMinLimitsData, 0)
+			for i := len(quarterDataList) - 1 ; i > len(quarterDataList) - seasonConfig.SamePeriodAverage.Year-1 && i > 0; i-- {
+				// 插值成日度
+				dataTimeList, _, err = HandleDataByLinearRegressionToListV2(quarterDataList[i].DataList, handleDataMap)
+				if err != nil {
+					err = errors.New("插值处理数据异常, Err:" + err.Error())
+					return
+				}
+				for _, date := range dataTimeList {
+					dateTime, e := time.Parse(utils.FormatDate, date)
+					if e != nil {
+						err = errors.New("时间格式化异常, Err:" + e.Error())
+						return
+					}
+					newDate := dateTime.AddDate(time.Now().Year()-dateTime.Year(), 0, 0)
+					// 处理均值
+					if value, ok := valueMap[newDate]; ok {
+						valueMap[newDate] = (handleDataMap[date] + value)/2
+					} else {
+						valueMap[newDate] = handleDataMap[date]
+					}
+
+					dataTimeMap[newDate] = newDate
+					valueList := dataTimeValueMap[newDate]
+					valueList = append(valueList, handleDataMap[date])
+					dataTimeValueMap[newDate] = valueList
+				}
+			}
+
+			for _, v := range dataTimeMap {
+				valueList := dataTimeValueMap[v]
+				stdev := utils.CalculateStandardDeviation(valueList)
+				stdev, _ = decimal.NewFromFloat(stdev).Round(4).Float64()
+
+				maxMinItem := &data_manage.MaxMinLimitsData{}
+
+				if value, ok := valueMap[v]; ok {
+					maxMinItem.MaxValue = value + stdev*seasonConfig.SamePeriodStandardDeviation.Multiple
+					maxMinItem.MinValue = value - stdev*seasonConfig.SamePeriodStandardDeviation.Multiple
+				}
+
+				maxMinItem.DataTime = v.Format(utils.FormatDate)
+				maxMinItem.DataTimestamp = v.UnixNano() / 1e6
+
+				samePeriodStandardDeviationList = append(samePeriodStandardDeviationList, maxMinItem)
+
+			}
+
+			// 排序
+			sort.Slice(samePeriodStandardDeviationList, func(i, j int) bool {
+				return samePeriodStandardDeviationList[i].DataTime < samePeriodStandardDeviationList[j].DataTime
+			})
 
+			dataResp.SamePeriodStandardDeviation.List = samePeriodStandardDeviationList
+			dataResp.SamePeriodStandardDeviation.Color = seasonConfig.SamePeriodStandardDeviation.Color
+			dataResp.SamePeriodStandardDeviation.Legend = seasonConfig.SamePeriodStandardDeviation.Legend
+			dataResp.SamePeriodStandardDeviation.IsShow = seasonConfig.SamePeriodStandardDeviation.IsShow
+			dataResp.SamePeriodStandardDeviation.Multiple = seasonConfig.SamePeriodStandardDeviation.Multiple
+			dataResp.SamePeriodStandardDeviation.Year = seasonConfig.SamePeriodStandardDeviation.Year
 		}
 
 	}

+ 69 - 0
services/data/edb_info_calculate.go

@@ -9,6 +9,7 @@ import (
 	"github.com/shopspring/decimal"
 	"math"
 	"regexp"
+	"sort"
 	"strings"
 	"time"
 )
@@ -386,6 +387,7 @@ func HandleDataByLinearRegressionToList (edbInfoDataList []*data_manage.EdbDataL
 		// 第一个数据就给过滤了,给后面的试用
 		if startEdbInfoData == nil {
 			startEdbInfoData = v
+			//startEdbInfoData.DataTime = startEdbInfoData.DataTime[:5]+ "01-01"
 			continue
 		}
 
@@ -443,3 +445,70 @@ func HandleDataByLinearRegressionToList (edbInfoDataList []*data_manage.EdbDataL
 
 	return
 }
+
+// HandleDataByLinearRegressionToList 保证生成365个数据点的线性插值法
+func HandleDataByLinearRegressionToListV2(edbInfoDataList []*data_manage.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string, valueList []float64, err error) {
+	if len(edbInfoDataList) < 2 {
+		return
+	}
+
+	// 确保至少有两天数据来生成线性方程
+	if len(edbInfoDataList) < 2 {
+		err = errors.New("至少需要两天的数据来执行线性插值")
+		return
+	}
+
+	// 对数据按日期排序,确保顺序正确
+	sort.Slice(edbInfoDataList, func(i, j int) bool {
+		t1, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[i].DataTime, time.Local)
+		t2, _ := time.ParseInLocation(utils.FormatDate, edbInfoDataList[j].DataTime, time.Local)
+		return t1.Before(t2)
+	})
+
+	startEdbInfoData := edbInfoDataList[0]
+	endEdbInfoData := edbInfoDataList[len(edbInfoDataList)-1]
+
+	// 计算起始和结束日期间实际的天数
+	startDate, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
+	endDate, _ := time.ParseInLocation(utils.FormatDate, endEdbInfoData.DataTime, time.Local)
+	actualDays := endDate.Sub(startDate).Hours() / 24
+
+	// 生成365个数据点,首先处理已有数据
+	for _, v := range edbInfoDataList {
+		handleDataMap[v.DataTime] = v.Value
+		dataTimeList = append(dataTimeList, v.DataTime)
+		valueList = append(valueList, v.Value)
+	}
+
+	// 如果已有数据跨越天数不足365天,则对缺失的日期进行线性插值
+	if actualDays < 365 {
+		// 使用已有数据点生成线性方程(这里简化处理,实际可能需更细致处理边界情况)
+		var a, b float64
+		coordinateData := []utils.Coordinate{
+			{X: 1, Y: startEdbInfoData.Value},
+			{X: float64(len(edbInfoDataList)), Y: endEdbInfoData.Value},
+		}
+		a, b = utils.GetLinearResult(coordinateData)
+		if math.IsNaN(a) || math.IsNaN(b) {
+			err = errors.New("线性方程公式生成失败")
+			return
+		}
+
+		// 对剩余日期进行插值
+		for i := 1; i < 365; i++ {
+			day := startDate.AddDate(0, 0, i)
+			if _, exists := handleDataMap[day.Format(utils.FormatDate)]; !exists {
+				aDecimal := decimal.NewFromFloat(a)
+				xDecimal := decimal.NewFromInt(int64(i) + 1)
+				bDecimal := decimal.NewFromFloat(b)
+
+				val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
+				handleDataMap[day.Format(utils.FormatDate)] = val
+				dataTimeList = append(dataTimeList, day.Format(utils.FormatDate))
+				valueList = append(valueList, val)
+			}
+		}
+	}
+
+	return
+}