Browse Source

Merge branch 'chart/14.3'

Roc 1 year ago
parent
commit
1492b4df9e

+ 120 - 28
controller/chart/chart_common.go

@@ -20,6 +20,7 @@ import (
 	"hongze/hongze_yb/services/chart"
 	"hongze/hongze_yb/services/chart/correlation"
 	future_goodServ "hongze/hongze_yb/services/chart/future_good"
+	"hongze/hongze_yb/services/chart/line_equation"
 	"hongze/hongze_yb/services/user"
 	"hongze/hongze_yb/utils"
 	"io/ioutil"
@@ -63,39 +64,20 @@ func CommonChartInfoDetailFromUniqueCode(c *gin.Context) {
 		return
 	}
 
+	var resp *chart_info.ChartInfoDetailResp
+	var isOk bool
+	var msg, errMsg string
 	switch chartInfo.Source {
 	case utils.CHART_SOURCE_DEFAULT:
-		resp, isOk, msg, errMsg := getChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
-		if !isOk {
-			response.FailMsg(msg, errMsg, c)
-			return
-		}
-		response.OkData("获取成功", resp, c)
-		return
+		resp, isOk, msg, errMsg = getChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	case utils.CHART_SOURCE_FUTURE_GOOD:
-		resp, isOk, msg, errMsg := getFutureGoodChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
-		if !isOk {
-			response.FailMsg(msg, errMsg, c)
-			return
-		}
-		response.OkData("获取成功", resp, c)
-		return
+		resp, isOk, msg, errMsg = getFutureGoodChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	case utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
-		resp, isOk, msg, errMsg := getFutureGoodProfitChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
-		if !isOk {
-			response.FailMsg(msg, errMsg, c)
-			return
-		}
-		response.OkData("获取成功", resp, c)
-		return
+		resp, isOk, msg, errMsg = getFutureGoodProfitChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	case utils.CHART_SOURCE_CORRELATION, utils.CHART_SOURCE_ROLLING_CORRELATION:
-		resp, isOk, msg, errMsg := getCorrelationChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
-		if !isOk {
-			response.FailMsg(msg, errMsg, c)
-			return
-		}
-		response.OkData("获取成功", resp, c)
-		return
+		resp, isOk, msg, errMsg = getCorrelationChartInfoDetail(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
+	case utils.CHART_SOURCE_LINE_EQUATION:
+		resp, isOk, msg, errMsg = getChartInfoDetailFromUniqueCode(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	default:
 		msg := "错误的图表"
 		errMsg := "错误的图表"
@@ -103,6 +85,19 @@ func CommonChartInfoDetailFromUniqueCode(c *gin.Context) {
 		return
 	}
 
+	if !isOk {
+		response.FailMsg(msg, errMsg, c)
+		return
+	}
+
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := chart.GetEdbSourceByEdbInfoIdList(resp.EdbInfoList)
+	resp.ChartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	resp.ChartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+	response.OkData("获取成功", resp, c)
+
+	return
+
 }
 
 // getFutureGoodChartInfoDetail 获取商品价格曲线图表详情
@@ -362,6 +357,103 @@ func getFutureGoodProfitChartInfoDetail(chartInfo *chartInfoModel.ChartInfoView,
 	return
 }
 
+// getChartInfoDetailFromUniqueCode 获取拟合方程图表详情
+func getChartInfoDetailFromUniqueCode(chartInfo *chartInfoModel.ChartInfoView, myChartClassifyId int, userInfo user.UserInfo) (resp *chart_info.ChartInfoDetailResp, isOk bool, msg, errMsg string) {
+	resp = new(chart_info.ChartInfoDetailResp)
+	// 获取图表信息
+	var err error
+
+	if chartInfo.ExtraConfig == `` {
+		msg = "获取失败"
+		errMsg = "获取配置信息失败"
+		return
+	}
+	var lineChartInfoConfig request.LineChartInfoReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &lineChartInfoConfig)
+	if err != nil {
+		msg = "获取失败"
+		errMsg = "获取图表配置信息失败, Err:" + err.Error()
+		return
+	}
+
+	var getAData, getBData, getR2Data bool
+	switch lineChartInfoConfig.Source {
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_ONE:
+		getAData = true
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_TWO:
+		getBData = true
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_THREE:
+		getR2Data = true
+	}
+
+	edbList, dataResp, sourceArr, err, errMsg := line_equation.GetChartEdbData(chartInfo.ChartInfoId, lineChartInfoConfig, getAData, getBData, getR2Data)
+	if err != nil {
+		if errMsg == `` {
+			errMsg = "获取失败"
+		}
+		return
+	}
+
+	var resultResp interface{}
+	switch lineChartInfoConfig.Source {
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_ONE:
+		resultResp = dataResp.AData
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_TWO:
+		resultResp = dataResp.BData
+	case utils.CHART_MULTIPLE_GRAPH_LINE_EQUATION_THREE:
+		resultResp = dataResp.R2Data
+	}
+
+	sourceArr = append(sourceArr, "弘则研究")
+	chartInfo.ChartSource = strings.Join(sourceArr, ",")
+
+	baseEdbInfo := edbList[0] //现货指标
+	chartInfo.UnitEn = baseEdbInfo.UnitEn
+
+	// 访问记录-仅普通用户记录
+	ok, _, _ := user.GetAdminByUserInfo(userInfo)
+	if !ok {
+		go chart.SaveChartVisitLog(userInfo, chartInfo, myChartClassifyId)
+	}
+
+	// 用户是否有收藏该图表
+	{
+		ob := new(yb_my_chart.YbMyChart)
+		cond := `user_id = ? AND chart_info_id = ?`
+		pars := make([]interface{}, 0)
+		pars = append(pars, userInfo.UserID, chartInfo.ChartInfoId)
+		exists, e := ob.FetchByCondition(cond, pars)
+		if e != nil && e != utils.ErrNoRow {
+			msg = `操作失败`
+			errMsg = "获取用户图表失败, Err: " + e.Error()
+			return
+		}
+		myChartInfo := new(responseModel.MyChartItem)
+		if exists != nil && exists.MyChartID > 0 {
+			myChartInfo.MyChartID = exists.MyChartID
+			myChartInfo.MyChartClassifyID = exists.MyChartClassifyID
+			myChartInfo.ChartInfoID = exists.ChartInfoID
+			myChartInfo.ChartName = exists.ChartName
+			myChartInfo.UniqueCode = exists.UniqueCode
+			myChartInfo.ChartImage = exists.ChartImage
+			myChartInfo.UserID = exists.UserID
+			myChartInfo.ReportID = exists.ReportID
+			myChartInfo.ReportChapterID = exists.ReportChapterID
+			myChartInfo.CreateTime = utils.TimeTransferString(utils.FormatDateTime, exists.CreateTime)
+		}
+
+		resp.MyChartInfo = myChartInfo
+	}
+
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.DataResp = resultResp
+
+	isOk = true
+
+	return
+}
+
 // RefreshFutureGoodChartInfo 刷新商品价格曲线图表信息
 // @Tags 图库模块
 // @Summary  刷新图表信息

+ 5 - 0
controller/chart/chart_info.go

@@ -249,6 +249,11 @@ func GetChartInfoDetail(c *gin.Context) {
 		myChartInfo.CreateTime = utils.TimeTransferString(utils.FormatDateTime, exists.CreateTime)
 	}
 
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := chart.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
 	resp := new(chart_info.ChartInfoDetailResp)
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList

+ 10 - 0
models/request/chart.go

@@ -152,3 +152,13 @@ type ChartInfoDateReq struct {
 	Color string `description:"颜色"`
 	Name  string `description:"别名"`
 }
+
+// LineChartInfoReq 线性拟合图表预览请求数据
+type LineChartInfoReq struct {
+	DateType       int    `description:"日期类型"`
+	StartDate      string `description:"开始日期"`
+	EndDate        string `description:"结束日期"`
+	XEdbInfoIdList []int  `description:"X轴的指标id列表"`
+	YEdbInfoIdList []int  `description:"Y轴的指标id列表"`
+	Source         int    `description:"来源,5:斜率图;6:截距图;7:相关性图"`
+}

+ 23 - 1
models/tables/chart_edb_mapping/query.go

@@ -1,8 +1,10 @@
 package chart_edb_mapping
 
 import (
+	"fmt"
 	"hongze/hongze_yb/global"
 	"hongze/hongze_yb/utils"
+	"strings"
 	"time"
 )
 
@@ -58,7 +60,7 @@ type ChartEdbInfoMappingList struct {
 func GetMappingListByChartInfoId(chartInfoId int) (list []*ChartEdbInfoMapping, err error) {
 	aField := `a.chart_edb_mapping_id,a.chart_info_id,a.edb_info_id,a.create_time,a.modify_time,a.unique_code,a.max_data,a.min_data,a.is_order,a.is_axis,a.edb_info_type,a.lead_value,a.lead_unit,a.chart_style,a.chart_color,a.predict_chart_color,a.chart_width,a.source as mapping_source`
 
-	sql := ` SELECT ` + aField + `,b.source_name,b.source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type
+	sql := ` SELECT ` + aField + `,b.source_name,b.source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE chart_info_id=? 
@@ -119,3 +121,23 @@ func GetChartEdbMappingByEdbInfoId(edbInfoId int) (item *ChartEdbInfoMapping, er
 	err = global.MYSQL["data"].Raw(sql, edbInfoId).First(&item).Error
 	return
 }
+
+// GetChartEdbMappingListByEdbInfoIdList 根据指标id列表获取关联关系
+func GetChartEdbMappingListByEdbInfoIdList(edbIdList []int) (list []*ChartEdbInfoMapping, err error) {
+	num := len(edbIdList)
+	if num <= 0 {
+		return
+	}
+	sql := ` SELECT edb_info_id,source_name,source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value
+             FROM edb_info
+			 WHERE edb_info_id IN(?)
+			ORDER BY FIELD(edb_info_id,?)
+              `
+	edbIdStrList := make([]string, 0)
+	for _, v := range edbIdList {
+		edbIdStrList = append(edbIdStrList, fmt.Sprint(v))
+	}
+	err = global.MYSQL["data"].Raw(sql, edbIdList, strings.Join(edbIdStrList, ",")).Find(&list).Error
+
+	return
+}

+ 1 - 0
models/tables/chart_info/query.go

@@ -35,6 +35,7 @@ type ChartInfoView struct {
 	RightMin          string `description:"图表右侧最小值"`
 	RightMax          string `description:"图表右侧最大值"`
 	ChartSource       string `description:"图表来源str"`
+	ChartSourceEn     string `description:"图表来源(英文)"`
 	BarConfig         string `description:"柱方图的配置,json数据" json:"-"`
 	ChartNameEn       string `description:"英文图表名称"`
 	UnitEn            string `description:"英文单位名称"`

+ 6 - 0
services/chart/chart_info.go

@@ -472,6 +472,12 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 	return
 }
 
+// GetEdbDataMapList 获取指标最后的基础数据
+func GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*chartEdbMappingModel.ChartEdbInfoMapping) (edbDataListMap map[int][]*edbDataModel.EdbDataList, edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, sourceArr []string, err error) {
+	edbDataListMap, edbList, sourceArr, err = getEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList)
+	return
+}
+
 // getEdbDataMapList 获取指标最后的基础数据
 func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*chartEdbMappingModel.ChartEdbInfoMapping) (edbDataListMap map[int][]*edbDataModel.EdbDataList, edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, sourceArr []string, err error) {
 	// 关联指标来源

+ 37 - 0
services/chart/edb_info.go

@@ -3,6 +3,7 @@ package chart
 import (
 	"errors"
 	"fmt"
+	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
 	edbInfoModel "hongze/hongze_yb/models/tables/edb_info"
 	predictEdbConfCalculateMappingModel "hongze/hongze_yb/models/tables/predict_edb_conf_calculate_mapping"
 	"hongze/hongze_yb/services/alarm_msg"
@@ -541,3 +542,39 @@ func getRefreshEdbInfoListByIds(edbInfoIdList []int) (newBaseEdbInfoArr, newBase
 
 	return
 }
+
+// GetEdbSourceByEdbInfoIdList 获取关联指标的来源
+func GetEdbSourceByEdbInfoIdList(chartEdbInfoMappingList []*chartEdbMappingModel.ChartEdbInfoMappingList) (sourceNameList, sourceNameEnList []string) {
+	sourceNameList = []string{}
+	sourceNameEnList = []string{}
+	sourceMap := make(map[int]string)
+	for _, v := range chartEdbInfoMappingList {
+		// 指标类型:1:基础指标,2:计算指标
+		if v.EdbType == 2 || v.EdbInfoCategoryType == 1 {
+			//sourceMap[0] = "弘则研究"
+			baseEdbInfoArr, _, _ := edbInfoModel.GetRefreshEdbInfoFromBase(v.EdbInfoId, v.Source)
+			for _, baseEdbInfo := range baseEdbInfoArr {
+				sourceMap[baseEdbInfo.Source] = baseEdbInfo.SourceName
+			}
+		} else {
+			sourceMap[v.Source] = v.SourceName
+		}
+	}
+
+	for source, sourceName := range sourceMap {
+		if source == utils.DATA_SOURCE_MANUAL {
+			continue
+		}
+		sourceNameList = append(sourceNameList, sourceName)
+
+		sourceNameEn, ok := utils.DataSourceEnMap[source]
+		if !ok {
+			sourceNameEn = sourceName
+		}
+		sourceNameEnList = append(sourceNameEnList, sourceNameEn)
+	}
+	sourceNameList = append(sourceNameList, `弘则研究`)
+	sourceNameEnList = append(sourceNameEnList, `Horizon Insights`)
+
+	return
+}

+ 42 - 0
services/chart/handle_data.go

@@ -77,3 +77,45 @@ func HandleDataByLinearRegression(edbInfoDataList []*edbDataModel.EdbDataList, h
 
 	return
 }
+
+// HandleDataByPreviousData 当前日期无值时,用上一个日期的数据补充当前日期的数据
+func HandleDataByPreviousData(edbInfoDataList []*edbDataModel.EdbDataList, handleDataMap map[string]float64) (err error) {
+	if len(edbInfoDataList) < 2 {
+		return
+	}
+
+	var startEdbInfoData *edbDataModel.EdbDataList
+	for _, v := range edbInfoDataList {
+		handleDataMap[v.DataTime] = v.Value
+
+		// 第一个数据就给过滤了,给后面的试用
+		if startEdbInfoData == nil {
+			startEdbInfoData = v
+			continue
+		}
+
+		// 获取两条数据之间相差的天数
+		startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
+		currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+		betweenHour := int(currDataTime.Sub(startDataTime).Hours())
+		betweenDay := betweenHour / 24
+
+		// 如果相差一天,那么过滤
+		if betweenDay <= 1 {
+			startEdbInfoData = v
+			continue
+		}
+
+		// 生成对应的值
+		{
+			for i := 1; i < betweenDay; i++ {
+				tmpDataTime := startDataTime.AddDate(0, 0, i)
+				handleDataMap[tmpDataTime.Format(utils.FormatDate)] = startEdbInfoData.Value
+			}
+		}
+
+		startEdbInfoData = v
+	}
+
+	return
+}

+ 353 - 0
services/chart/line_equation/chart_info.go

@@ -0,0 +1,353 @@
+package line_equation
+
+import (
+	"errors"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_yb/models/request"
+	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
+	edbDataModel "hongze/hongze_yb/models/tables/edb_data"
+	"hongze/hongze_yb/services/chart"
+	"hongze/hongze_yb/utils"
+	"math"
+	"time"
+)
+
+type LineEquationResp struct {
+	AData  LineEquationDataResp
+	BData  LineEquationDataResp
+	R2Data LineEquationDataResp
+}
+
+type LineEquationDataResp struct {
+	MaxData             float64
+	MinData             float64
+	LatestDate          time.Time `description:"真实数据的最后日期"`
+	EdbInfoCategoryType int
+	ChartColor          string
+	ChartStyle          string
+	PredictChartColor   string
+	ChartType           int
+	ChartWidth          int
+	EdbName             string
+	EdbNameEn           string
+	Unit                string
+	UnitEn              string
+	IsAxis              int
+	DataList            []edbDataModel.EdbDataList
+}
+
+// GetChartEdbData 获取图表数据
+func GetChartEdbData(chartInfoId int, lineChartInfoConfig request.LineChartInfoReq, getAData, getBData, getR2Data bool) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp LineEquationResp, sourceArr []string, err error, errMsg string) {
+	// 获取基本信息
+	mappingList, startDate, endDate, err, errMsg := getConfigData(lineChartInfoConfig)
+	if err != nil {
+		return
+	}
+	xEdbInfoIdList := lineChartInfoConfig.XEdbInfoIdList
+	yEdbInfoIdList := lineChartInfoConfig.YEdbInfoIdList
+
+	aLineEquationDataResp := LineEquationDataResp{
+		DataList:          make([]edbDataModel.EdbDataList, 0),
+		MaxData:           0,
+		MinData:           0,
+		ChartColor:        "#00f",
+		ChartStyle:        `spline`,
+		PredictChartColor: `#00f`,
+		ChartType:         0,
+		ChartWidth:        3,
+		EdbName:           `弹性系数`,
+		EdbNameEn:         `elastic coefficient`,
+		IsAxis:            1,
+	}
+	bLineEquationDataResp := LineEquationDataResp{
+		DataList:          make([]edbDataModel.EdbDataList, 0),
+		MaxData:           0,
+		MinData:           0,
+		ChartColor:        "#00f",
+		ChartStyle:        `spline`,
+		PredictChartColor: `#00f`,
+		ChartType:         0,
+		ChartWidth:        3,
+		EdbName:           `截距`,
+		EdbNameEn:         `intercept`,
+		IsAxis:            1,
+	}
+	r2LineEquationDataResp := LineEquationDataResp{
+		DataList:          make([]edbDataModel.EdbDataList, 0),
+		MaxData:           0,
+		MinData:           0,
+		ChartColor:        "#00f",
+		ChartStyle:        `spline`,
+		PredictChartColor: `#00f`,
+		ChartType:         0,
+		ChartWidth:        3,
+		EdbName:           `相关系数`,
+		EdbNameEn:         `coefficient of association`,
+		IsAxis:            1,
+	}
+	edbList = make([]*chartEdbMappingModel.ChartEdbInfoMappingList, 0)
+	dataResp = LineEquationResp{
+		AData:  aLineEquationDataResp,
+		BData:  bLineEquationDataResp,
+		R2Data: r2LineEquationDataResp,
+	}
+
+	var baseEdbInfo *chartEdbMappingModel.ChartEdbInfoMapping
+	// 获取确定以哪个指标的日期作为基准日期
+	{
+		var xEdbInfo, yEdbInfo *chartEdbMappingModel.ChartEdbInfoMapping
+		for _, v := range mappingList {
+			if v.EdbInfoId == xEdbInfoIdList[0] {
+				xEdbInfo = v
+			} else if v.EdbInfoId == yEdbInfoIdList[0] {
+				yEdbInfo = v
+			}
+		}
+		if xEdbInfo == nil {
+			errMsg = `X轴第一个指标异常`
+			err = errors.New(errMsg)
+			return
+		}
+		if yEdbInfo == nil {
+			errMsg = `Y轴第一个指标异常`
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 时间截面规则:按照什么频率来取不同的截面的问题。原则是:按照X轴和Y轴所选择的第一个指标(X和Y分别有一个第一个指标),两个指标中,以低频的那个作为基准。如果X轴和Y轴是同频的,那以Y轴第一个指标的为准。
+		frequencyIntMap := map[string]int{
+			"日度": 1,
+			"周度": 2,
+			"旬度": 3,
+			"月度": 4,
+			"季度": 5,
+			"年度": 6,
+		}
+		// 如果x是高频 或者 x与y是同频的,那么就是Y轴的第一个指标为主
+		if frequencyIntMap[xEdbInfo.Frequency] <= frequencyIntMap[yEdbInfo.Frequency] {
+			baseEdbInfo = yEdbInfo
+		} else {
+			// 否则是X轴的第一个指标是低频
+			baseEdbInfo = xEdbInfo
+		}
+	}
+
+	// 指标对应的所有数据
+	chartType := 1 //1:普通图,2:季节性图
+	calendar := "公历"
+	edbDataListMap, edbList, sourceArr, err := chart.GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList)
+	if err != nil {
+		return
+	}
+
+	// 获取所有的日期
+	dateList := make([]string, 0)
+	for _, v := range edbDataListMap[baseEdbInfo.EdbInfoId] {
+		dateList = append(dateList, v.DataTime)
+	}
+
+	// 数据整理
+	// [日期][A指标id:值,B指标id:值]
+	dateEdbMap, err := handleData(baseEdbInfo.EdbInfoId, edbDataListMap)
+	if err != nil {
+		return
+	}
+
+	lenX := len(xEdbInfoIdList)
+
+	var isNotAFirst, isNotBFirst, isNotR2First bool
+	for i, date := range dateList {
+		coordinateData := make([]utils.Coordinate, 0)
+		for k := 0; k < lenX; k++ {
+			xVal, ok1 := dateEdbMap[date][xEdbInfoIdList[k]]
+			yVal, ok2 := dateEdbMap[date][yEdbInfoIdList[k]]
+			if !ok1 || !ok2 {
+				continue
+			}
+			tmpCoordinate1 := utils.Coordinate{
+				X: xVal,
+				Y: yVal,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate1)
+		}
+		dataTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
+		timestamp := dataTime.UnixNano() / 1e6
+		// 只有存在两个坐标点的时候,才能去计算线性方程和R平方
+		if len(coordinateData) >= 2 {
+			a, b := utils.GetLinearResult(coordinateData)
+			if !math.IsNaN(a) && !math.IsNaN(b) && !math.IsInf(a, 0) && !math.IsInf(b, 0) {
+				if getAData {
+					a, _ = decimal.NewFromFloat(a).Round(4).Float64()
+					dataResp.AData.DataList = append(dataResp.AData.DataList, edbDataModel.EdbDataList{
+						EdbDataId:     i,
+						EdbInfoId:     0,
+						DataTime:      date,
+						DataTimestamp: timestamp,
+						Value:         a,
+					})
+					if !isNotAFirst {
+						dataResp.AData.MinData = a
+						dataResp.AData.MaxData = a
+						isNotAFirst = true
+					}
+					if dataResp.AData.MinData > a {
+						dataResp.AData.MinData = a
+					}
+					if dataResp.AData.MaxData < a {
+						dataResp.AData.MaxData = a
+					}
+				}
+				if getBData {
+					b, _ = decimal.NewFromFloat(b).Round(4).Float64()
+					dataResp.BData.DataList = append(dataResp.BData.DataList, edbDataModel.EdbDataList{
+						EdbDataId:     i,
+						EdbInfoId:     0,
+						DataTime:      date,
+						DataTimestamp: timestamp,
+						Value:         b,
+					})
+					if !isNotBFirst {
+						dataResp.BData.MinData = b
+						dataResp.BData.MaxData = b
+						isNotBFirst = true
+					}
+					if dataResp.BData.MinData > b {
+						dataResp.BData.MinData = b
+					}
+					if dataResp.BData.MaxData < b {
+						dataResp.BData.MaxData = b
+					}
+				}
+			}
+
+			// 计算R平方
+			if getR2Data {
+				tmpVal := utils.CalculationDecisive(coordinateData)
+				if math.IsNaN(tmpVal) || math.IsInf(tmpVal, 0) {
+					continue
+				}
+
+				tmpVal, _ = decimal.NewFromFloat(tmpVal).Round(4).Float64()
+				dataResp.R2Data.DataList = append(dataResp.R2Data.DataList, edbDataModel.EdbDataList{
+					EdbDataId:     i,
+					EdbInfoId:     0,
+					DataTime:      date,
+					DataTimestamp: timestamp,
+					Value:         tmpVal,
+				})
+				if !isNotR2First {
+					dataResp.R2Data.MinData = tmpVal
+					dataResp.R2Data.MaxData = tmpVal
+					isNotR2First = true
+				}
+				if dataResp.R2Data.MinData > tmpVal {
+					dataResp.R2Data.MinData = tmpVal
+				}
+				if dataResp.R2Data.MaxData < tmpVal {
+					dataResp.R2Data.MaxData = tmpVal
+				}
+			}
+		}
+	}
+	dataResp.AData.LatestDate = baseEdbInfo.LatestDate
+	dataResp.AData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
+	dataResp.BData.LatestDate = baseEdbInfo.LatestDate
+	dataResp.BData.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
+	dataResp.R2Data.LatestDate = baseEdbInfo.LatestDate
+	dataResp.R2Data.EdbInfoCategoryType = baseEdbInfo.EdbInfoCategoryType
+
+	return
+}
+
+// getConfigData 获取配置数据
+func getConfigData(lineChartInfoConfig request.LineChartInfoReq) (mappingList []*chartEdbMappingModel.ChartEdbInfoMapping, startDate, endDate string, err error, errMsg string) {
+	dateType := lineChartInfoConfig.DateType
+	switch dateType {
+	case 1:
+		startDate = "2000-01-01"
+	case 2:
+		startDate = "2010-01-01"
+	case 3:
+		startDate = "2015-01-01"
+	case 4:
+		//startDate = strconv.Itoa(time.Now().Year()) + "-01-01"
+		startDate = "2021-01-01"
+	case 5:
+		startDate = lineChartInfoConfig.StartDate + "-01"
+		endDate = lineChartInfoConfig.EndDate + "-01"
+	case 6:
+		startDate = lineChartInfoConfig.StartDate + "-01"
+	case 7:
+		startDate = "2018-01-01"
+	case 8:
+		startDate = "2019-01-01"
+	case 9:
+		startDate = "2020-01-01"
+	case 11:
+		startDate = "2022-01-01"
+	}
+
+	//指标数据
+	edbInfoIdList := make([]int, 0)
+	{
+		edbInfoIdMap := make(map[int]int, 0)
+		for _, edbInfoId := range lineChartInfoConfig.XEdbInfoIdList {
+			edbInfoIdMap[edbInfoId] = edbInfoId
+		}
+		for _, edbInfoId := range lineChartInfoConfig.YEdbInfoIdList {
+			edbInfoIdMap[edbInfoId] = edbInfoId
+		}
+		for _, edbInfoId := range edbInfoIdMap {
+			edbInfoIdList = append(edbInfoIdList, edbInfoId)
+		}
+	}
+	mappingList, err = chartEdbMappingModel.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+	if err != nil {
+		errMsg = `获取失败`
+		err = errors.New("获取图表,指标信息失败,Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// handleData 数据处理
+func handleData(baseEdbInfoId int, edbDataListMap map[int][]*edbDataModel.EdbDataList) (dateEdbMap map[string]map[int]float64, err error) {
+	dateEdbMap = make(map[string]map[int]float64) // [日期][A指标id:值,B指标id:值]
+	for edbInfoId, edbDataList := range edbDataListMap {
+		if edbInfoId != baseEdbInfoId {
+			// 用上期的数据补充当期的数据处理
+			handleDataMap := make(map[string]float64)
+			err = chart.HandleDataByPreviousData(edbDataList, handleDataMap)
+			if err != nil {
+				return
+			}
+
+			for date, val := range handleDataMap {
+				item, ok := dateEdbMap[date]
+				if ok {
+					item[edbInfoId] = val
+				} else {
+					item = map[int]float64{
+						edbInfoId: val,
+					}
+				}
+				dateEdbMap[date] = item
+			}
+		} else {
+			for _, edbData := range edbDataList {
+				item, ok := dateEdbMap[edbData.DataTime]
+				if ok {
+					item[edbInfoId] = edbData.Value
+				} else {
+					item = map[int]float64{
+						edbInfoId: edbData.Value,
+					}
+				}
+				dateEdbMap[edbData.DataTime] = item
+			}
+		}
+	}
+
+	return
+}

+ 9 - 0
utils/common.go

@@ -1101,3 +1101,12 @@ func TimeTransferString(format string, t time.Time) string {
 	}
 	return str
 }
+
+// GetOrmInReplace 获取orm的in查询替换?的方法
+func GetOrmInReplace(num int) string {
+	template := make([]string, num)
+	for i := 0; i < num; i++ {
+		template[i] = "?"
+	}
+	return strings.Join(template, ",")
+}

+ 37 - 0
utils/constants.go

@@ -257,6 +257,18 @@ const (
 	CHART_SOURCE_CORRELATION         = 3 // 相关性图表
 	CHART_SOURCE_ROLLING_CORRELATION = 4 // 滚动相关性图表
 	CHART_SOURCE_FUTURE_GOOD_PROFIT  = 5 // 商品利润曲线
+	CHART_SOURCE_LINE_EQUATION       = 6 // 拟合方程图表
+)
+
+// 图表类型
+const (
+	CHART_MULTIPLE_GRAPH_CURVE                   = 1 // 曲线图
+	CHART_MULTIPLE_GRAPH_CORRELATION             = 2 // 相关性图
+	CHART_MULTIPLE_GRAPH_ROLLING_CORRELATION_ONE = 3 // 滚动相关性图1
+	CHART_MULTIPLE_GRAPH_ROLLING_CORRELATION_TWO = 4 // 滚动相关性图2
+	CHART_MULTIPLE_GRAPH_LINE_EQUATION_ONE       = 5 // 拟合方程-斜率图
+	CHART_MULTIPLE_GRAPH_LINE_EQUATION_TWO       = 6 // 拟合方程-截距图
+	CHART_MULTIPLE_GRAPH_LINE_EQUATION_THREE     = 7 // 拟合方程-相关性图
 )
 
 // 图表样式类型
@@ -270,3 +282,28 @@ const (
 var FrequencyDaysMap = map[string]int{
 	"天": 1, "周": 7, "月": 30, "季": 90, "年": 365,
 }
+
+// DataSourceEnMap 指标来源的英文名称
+var DataSourceEnMap = map[int]string{
+	DATA_SOURCE_WIND:          "Wind",
+	DATA_SOURCE_THS:           "iFind",
+	DATA_SOURCE_PB:            "Bloomberg",
+	DATA_SOURCE_PB_FINANCE:    "Bloomberg Finance",
+	DATA_SOURCE_LT:            "Reuters",
+	DATA_SOURCE_MANUAL:        "Horizon Insights",
+	DATA_SOURCE_LZ:            "OilChem",
+	DATA_SOURCE_YS:            "SMM",
+	DATA_SOURCE_GL:            "MySteel",
+	DATA_SOURCE_ZZ:            "Zhengzhou Commodity Exchange",
+	DATA_SOURCE_DL:            "Dalian Commodity Exchange",
+	DATA_SOURCE_SH:            "Shanghai Futures Exchange",
+	DATA_SOURCE_CFFEX:         "China Financial Futures Exchange",
+	DATA_SOURCE_SHFE:          "Shanghai International Energy Exchange",
+	DATA_SOURCE_GIE:           "Eurostat",
+	DATA_SOURCE_COAL:          "China Coal Transport & Distribution Association",
+	DATA_SOURCE_GOOGLE_TRAVEL: "Our World in Data",
+	DATA_SOURCE_EIA_STEO:      "Energy Information Administration",
+	DATA_SOURCE_COM_TRADE:     "United Nations",
+	DATA_SOURCE_SCI:           "Sublime China Information",
+	DATA_SOURCE_BAIINFO:       "BAIINFO",
+}