Browse Source

Merge branch 'master' into feature/eta1.9.6_chart_series

# Conflicts:
#	models/chart.go
#	services/data/chart_info.go
xyxie 6 months ago
parent
commit
38035e7979

+ 41 - 10
controllers/chart_common.go

@@ -183,7 +183,7 @@ func GetFutureGoodChartInfoDetailFromUniqueCode(chartInfo *models.ChartInfo, key
 		}
 	}
 
-	edbInfoMapping, err := models.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := models.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
 		errMsg = "获取图表,现货指标信息失败,Err:" + err.Error()
@@ -197,8 +197,7 @@ func GetFutureGoodChartInfoDetailFromUniqueCode(chartInfo *models.ChartInfo, key
 	}
 
 	// 商品价格曲线图的一些配置
-	var barConfig data_manage.BarChartInfoReq
-	barChartInfoDateList := make([]data_manage.BarChartInfoDateReq, 0)
+	var barConfig data_manage.FutureGoodBarChartInfoReq
 	//barChartInfoSort := data_manage.BarChartInfoSortReq{}
 
 	if chartInfo.BarConfig == `` {
@@ -213,11 +212,25 @@ func GetFutureGoodChartInfoDetailFromUniqueCode(chartInfo *models.ChartInfo, key
 		return
 	}
 
-	barChartInfoDateList = barConfig.DateList
-	//barChartInfoSort = barConfig.Sort
+	baseEdbInfoId := barConfig.BaseEdbInfoId
+	var baseEdbInfoMapping *models.ChartEdbInfoMapping
+	// todo 兼容历史数据,
+	if baseEdbInfoId == 0 {
+		// 默认取第一个现货指标
+		baseEdbInfoId = edbInfoMappingList[0].EdbInfoId
+		baseEdbInfoMapping = edbInfoMappingList[0]
+		barConfig.BaseEdbInfoId = baseEdbInfoId
+	} else {
+		baseEdbInfoMapping, err = models.GetChartEdbMappingByEdbInfoId(baseEdbInfoId)
+		if err != nil {
+			msg = "获取失败"
+			errMsg = "获取图表,指标信息失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	// 获取图表中的指标数据
-	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfoId, startDate, endDate, edbInfoMapping, futureGoodEdbInfoMapping, barChartInfoDateList)
+	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfoId, startDate, endDate, baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoMapping, barConfig, true)
 	if err != nil {
 		msg = "获取失败"
 		errMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -252,11 +265,20 @@ func GetFutureGoodChartInfoDetailFromUniqueCode(chartInfo *models.ChartInfo, key
 	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
 	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
 
+	xDataListFinal := make([]models.XData, 0)
+	for _, v := range xDataList {
+		tmp := models.XData{
+			Name:   v.Name,
+			NameEn: v.NameEn,
+			IsHide: v.IsHide,
+		}
+		xDataListFinal = append(xDataListFinal, tmp)
+	}
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList
 	resp.XEdbIdValue = xEdbIdValue
 	resp.YDataList = yDataList
-	resp.XDataList = xDataList
+	resp.XDataList = xDataListFinal
 	//resp.BarChartInfo = barConfig
 	//resp.Status = true
 
@@ -295,14 +317,24 @@ func GetFutureGoodProfitChartInfoDetailFromUniqueCode(chartInfo *models.ChartInf
 		return
 	}
 
+	if len(extraConf.EdbInfoIdList) == 0 {
+		extraConf.EdbInfoIdList = append(extraConf.EdbInfoIdList, extraConf.BaseEdbInfoId)
+	}
+
 	edbList := make([]*models.ChartEdbInfoMapping, 0)
-	edbInfoMapping, err := models.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := models.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
 		errMsg = "获取商品利润图表,基础指标信息失败,Err:" + err.Error()
 		return
 	}
-	edbList = append(edbList, edbInfoMapping)
+	baseEdbInfo := new(models.ChartEdbInfoMapping)
+	for _, v := range edbInfoMappingList {
+		if v.EdbInfoId == extraConf.BaseEdbInfoId {
+			baseEdbInfo = v
+		}
+	}
+	edbList = edbInfoMappingList
 	futureGoodEdbInfoMappingList, err := models.GetFutureGoodEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
@@ -342,7 +374,6 @@ func GetFutureGoodProfitChartInfoDetailFromUniqueCode(chartInfo *models.ChartInf
 	}
 
 	warnEdbList := make([]string, 0)
-	baseEdbInfo := edbList[0] //现货指标
 	for _, v := range edbList {
 		if v.IsNullData {
 			warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")

+ 16 - 0
models/business_conf.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"eta/eta_chart_lib/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"html"
@@ -61,3 +62,18 @@ func GetBusinessConfByKey(key string) (item *BusinessConf, err error) {
 	err = o.Raw(sql, key).QueryRow(&item)
 	return
 }
+
+// InitUseMongoConf
+// @Description:
+// @author: Roc
+// @datetime 2024-07-01 13:49:09
+func InitUseMongoConf() {
+	useMongo, e := GetBusinessConfByKey("UseMongo")
+	if e != nil {
+		return
+	}
+
+	if useMongo.ConfVal == `true` {
+		utils.UseMongo = true
+	}
+}

+ 201 - 5
models/chart.go

@@ -145,9 +145,12 @@ type EdbDataList struct {
 // GetEdbDataList 获取指标的数据(日期正序返回)
 func GetEdbDataList(source, subSource, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
 	// 自有数据需要额外处理(从mongo获取)
-	if source == utils.DATA_SOURCE_BUSINESS {
+	if source == utils.DATA_SOURCE_BUSINESS && utils.UseMongo {
 		return getEdbDataListByMongo(source, subSource, edbInfoId, startDate, endDate)
 	}
+	if source == utils.DATA_SOURCE_THS && subSource == utils.DATA_SUB_SOURCE_HIGH_FREQUENCY && utils.UseMongo {
+		return getThsHfEdbDataListByMongo(source, subSource, edbInfoId, startDate, endDate)
+	}
 
 	return getEdbDataListByMysql(source, subSource, edbInfoId, startDate, endDate)
 }
@@ -289,6 +292,7 @@ type ChartInfoDetailResp struct {
 type XData struct {
 	Name   string `description:"别名"`
 	NameEn string `description:"英文别名"`
+	IsHide int    `description:"是否隐藏,0不隐藏,1隐藏"`
 }
 
 // YData 柱方图的y轴数据
@@ -680,10 +684,118 @@ type CorrelationInfo struct {
 }
 
 type SeasonExtraItem struct {
-	ChartLegend []SeasonChartLegend `description:"自定义的图例名称"`
-	XStartDate  string              `description:"横坐标显示的起始日"`
-	XEndDate    string              `description:"横坐标显示的截止日"`
-	JumpYear    int                 `description:"横坐标日期是否跨年,1跨年,0不跨年"`
+	ChartLegend                 []SeasonChartLegend         `description:"自定义的图例名称"`
+	XStartDate                  string                      `description:"横坐标显示的起始日"`
+	XEndDate                    string                      `description:"横坐标显示的截止日"`
+	JumpYear                    int                         `description:"横坐标日期是否跨年,1跨年,0不跨年"`
+	RightAxis                   SeasonRightAxis             `description:"自定义右轴指标"`
+	MaxMinLimits                MaxMinLimits                `description:"自定义同期上下限"`
+	SamePeriodAverage           SamePeriodAverage           `description:"自定义同期均线"`
+	SamePeriodStandardDeviation SamePeriodStandardDeviation `description:"自定义同期标准差"`
+}
+
+// 自定义右轴指标
+type SeasonRightAxis struct {
+	IndicatorType int     `description:"右轴指标类型 1:左轴指标同比,2:指标库,3:预测指标 "`
+	Style         string  `description:"生成样式"`
+	Shape         string  `description:"形状"`
+	ChartColor    string  `description:"图表颜色"`
+	Size          int     `description:"大小"`
+	Legend        string  `description:"图例名称"`
+	NumFormat     int     `description:"数值格式 1:百分比 2:小数"`
+	IsConnected   int     `description:"是否连接 0不连接 1连接"`
+	LineColor     string  `description:"线条颜色"`
+	LineWidth     float64 `description:"线条宽度"`
+	LineStyle     string  `description:"线条样式"`
+	IsShow        bool    `description:"是否显示"`
+	IsAdd         bool    `description:"是否添加"`
+}
+
+// 自定义同期上下限
+type MaxMinLimits struct {
+	Color  string `description:"颜色"`
+	Year   int    `description:"上下限取值范围"`
+	Legend string `description:"图例名称"`
+	IsShow bool   `description:"是否显示"`
+	IsAdd  bool   `description:"是否添加"`
+}
+
+// 自定义同期均线
+type SamePeriodAverage struct {
+	Color     string  `description:"颜色"`
+	Year      int     `description:"均线取值范围"`
+	Legend    string  `description:"图例名称"`
+	LineType  string  `description:"线型"`
+	LineWidth float64 `description:"线宽"`
+	IsShow    bool    `description:"是否显示"`
+	IsAdd     bool    `description:"是否添加"`
+}
+
+// 自定义同期均线
+type SamePeriodAverageResp struct {
+	Color     string                   `description:"颜色"`
+	Year      int                      `description:"均线取值范围"`
+	Legend    string                   `description:"图例名称"`
+	LineType  string                   `description:"线型"`
+	LineWidth float64                  `description:"线宽"`
+	IsShow    bool                     `description:"是否显示"`
+	List      []*SamePeriodAverageData `description:"自定义均线列表"`
+	IsAdd     bool                     `description:"是否添加"`
+}
+
+type SamePeriodAverageData struct {
+	DataTime      string  `description:"数据日期"`
+	DataTimestamp int64   `description:"数据日期时间戳"`
+	Value         float64 `description:"均值"`
+}
+
+// 自定义同期标准差
+type SamePeriodStandardDeviation struct {
+	Color    string  `description:"颜色"`
+	Year     int     `description:"标准差取值范围"`
+	Legend   string  `description:"图例名称"`
+	Multiple float64 `description:"标准差倍数"`
+	IsShow   bool    `description:"是否显示"`
+	IsAdd    bool    `description:"是否添加"`
+}
+
+type SamePeriodStandardDeviationResp struct {
+	Color    string              `description:"颜色"`
+	Year     int                 `description:"标准差取值范围"`
+	Legend   string              `description:"图例名称"`
+	Multiple float64             `description:"标准差倍数"`
+	IsShow   bool                `description:"是否显示"`
+	List     []*MaxMinLimitsData `description:"自定义标准差列表"`
+	IsAdd    bool                `description:"是否添加"`
+}
+
+type SeasonChartResp struct {
+	MaxMinLimits                MaxMinLimitsResp                `description:"自定义上下限"`
+	SamePeriodAverage           SamePeriodAverageResp           `description:"自定义同期均线"`
+	SamePeriodStandardDeviation SamePeriodStandardDeviationResp `description:"自定义同期标准差线"`
+	RightAxis                   SeasonRightAxisResp             `description:"自定义右轴指标"`
+}
+
+// 自定义右轴指标
+type SeasonRightAxisResp struct {
+	SeasonRightAxis
+	EdbInfoList []*ChartEdbInfoMapping
+}
+
+type MaxMinLimitsResp struct {
+	List   []*MaxMinLimitsData `description:"自定义上下限列表"`
+	Color  string              `description:"颜色"`
+	Year   int                 `description:"上下限取值范围"`
+	Legend string              `description:"图例名称"`
+	IsShow bool                `description:"是否显示"`
+	IsAdd  bool                `description:"是否添加"`
+}
+
+type MaxMinLimitsData struct {
+	DataTime      string  `description:"数据日期"`
+	DataTimestamp int64   `description:"数据日期时间戳"`
+	MaxValue      float64 `description:"最大值"`
+	MinValue      float64 `description:"最小值"`
 }
 
 type SeasonChartLegend struct {
@@ -836,3 +948,87 @@ func GetChartInfoById(chartInfoId int) (item *ChartInfo, err error) {
 	err = o.Raw(sql, chartInfoId).QueryRow(&item)
 	return
 }
+
+type MarkersLine struct {
+	Axis             int             `json:"axis" description:"1左轴 2右轴 3横轴"`
+	AxisName         string          `json:"axisName" description:"轴的名称,例如'左轴'"`
+	MarkerType       string          `json:"markerType" description:"标识线或标识区"`
+	MarkLineType     int             `json:"markLineType" description:"1:固定 2:指标计算"`
+	Value            string          `json:"value" description:"连线指向的数值,例如'4000'"`
+	FromValue        string          `json:"fromValue" description:"连线的起始点,可以为空"`
+	ToValue          string          `json:"toValue" description:"连线的结束点,可以为空"`
+	LineWidth        float64         `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:"是否显示连线及文本"`
+	EdbType          int             `json:"edbType" description:"指标类型 0图中第一个指标 1其他指标 前端回显用"`
+	EdbInfoId        int             `json:"edbInfoId" description:"指标id"`
+	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动态 3至今(仅结束时间)"`
+	Date     string            `json:"date" description:"日期"`
+	Conf     EdbDateChangeConf `json:"conf" description:"动态时间配置"`
+}
+
+// EdbDateExtraConf
+// @Description: 导入指标日期前移和日期变换
+type EdbDateChangeConf struct {
+	MoveForward int `json:"moveForward" description:"前移的期数"`
+	BaseDate    int `json:"baseDate" description:"基准日期 0系统日期 1指标最新日期"`
+	DateChange  []*EdbDateConfDateChange
+}
+
+type EdbDateConfDateChange struct {
+	Year         int    `json:"year" description:"前移的期数"`
+	Month        int    `json:"month" description:"前移的期数"`
+	Day          int    `json:"day" description:"前移的期数"`
+	Frequency    string `json:"moveForward" description:"频度变换"`
+	FrequencyDay string `json:"frequencyDay" description:"频度的固定日期"`
+	ChangeType   int    `json:"changeType" description:"日期变换类型1日期位移,2指定频率"`
+}
+
+func getThsHfEdbDataListByMongo(source, subSource, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	list = make([]*EdbDataList, 0)
+
+	mogDataObj := mgo.EdbDataThsHf{}
+	// 构建查询条件
+	queryConditions := bson.M{
+		"edb_info_id": edbInfoId,
+	}
+
+	// 数据日期
+	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
+	if err != nil {
+		return
+	}
+	if len(dateCondition) > 0 {
+		queryConditions["data_time"] = dateCondition
+	}
+
+	// 获取列表数据
+	tmpDataList, tmpErr := mogDataObj.GetAllDataList(queryConditions, []string{"data_time"})
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	for k, v := range tmpDataList {
+		list = append(list, &EdbDataList{
+			EdbDataId:     k + 1,
+			EdbInfoId:     v.EdbInfoId,
+			DataTime:      v.DataTime.Format(utils.FormatDate),
+			DataTimestamp: v.DataTimestamp,
+			Value:         v.Value,
+		})
+	}
+	return
+}

+ 14 - 0
models/chart_edb_mapping.go

@@ -19,6 +19,20 @@ func GetEtaEdbChartEdbMapping(chartInfoId int) (item *ChartEdbInfoMapping, err e
 	return
 }
 
+// GetEtaEdbChartEdbMappingList       商品曲线图查询对应的普通指标
+func GetEtaEdbChartEdbMappingList(chartInfoId int) (items []*ChartEdbInfoMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	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.sub_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.classify_id,b.is_join_permission
+             FROM chart_edb_mapping AS a
+			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
+			 WHERE a.chart_info_id=? AND a.source = ?
+             ORDER BY chart_edb_mapping_id ASC `
+	_, err = o.Raw(sql, chartInfoId, utils.CHART_SOURCE_DEFAULT).QueryRows(&items)
+	return
+}
+
 // GetFutureGoodEdbChartEdbMapping       商品曲线图查询对应的商品指标
 func GetFutureGoodEdbChartEdbMapping(chartInfoId int) (item *ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")

+ 15 - 0
models/data_manage/chart_info.go

@@ -64,12 +64,27 @@ type BarChartInfoReq struct {
 	Sort          BarChartInfoSortReq      `description:"排序"`
 }
 
+type FutureGoodBarChartInfoReq struct {
+	EdbInfoIdList []BarChartInfoEdbItemReq `description:"指标信息"`
+	DateList      []BarChartInfoDateReq    `description:"日期配置"`
+	XDataList     []XData                  `description:"横轴配置"`
+	BaseEdbInfoId int                      `description:"日期基准指标id"`
+}
+
+// XData 商品价格曲线的的x轴数据
+type XData struct {
+	Name   string `description:"别名"`
+	NameEn string `description:"英文别名"`
+	IsHide int    `description:"是否隐藏,0不隐藏,1隐藏"`
+}
+
 // BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
 type BarChartInfoEdbItemReq struct {
 	EdbInfoId int    `description:"指标ID"`
 	Name      string `description:"别名"`
 	NameEn    string `description:"英文别名"`
 	Source    int    `description:"1:ETA图库;2:商品价格"`
+	IsHide    int    `description:"是否隐藏该项,0不隐藏,1隐藏"`
 }
 
 // BarChartInfoDateReq 柱方图预览请求数据(日期相关)

+ 2 - 2
models/data_manage/chart_theme/chart_theme.go

@@ -191,7 +191,7 @@ type DrawOption struct {
 
 type LineOptions struct {
 	DashStyle string  `json:"dashStyle"`
-	LineWidth int     `json:"lineWidth"`
+	LineWidth float64     `json:"lineWidth"`
 	LineType  string  `json:"lineType"`
 	Radius    float64 `json:"radius"`
 }
@@ -225,7 +225,7 @@ type NewLineOptions struct {
 type LineStyleOptions struct {
 	DashStyle string `json:"dashStyle"`
 	Color     string `json:"color"`
-	LineWidth int    `json:"lineWidth"`
+	LineWidth float64    `json:"lineWidth"`
 	LineType  string `json:"lineType"`
 	Radius    int    `json:"radius"`
 	DataMark  string `json:"dataMark"`

+ 19 - 0
models/data_manage/future_good/future_good_edb_info_data.go

@@ -1,6 +1,7 @@
 package future_good
 
 import (
+	"eta/eta_chart_lib/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
 	"time"
@@ -101,3 +102,21 @@ func GetFutureGoodEdbDataListByDate(futureGoodEdbInfoId int, startDate, endDate
 	_, err = o.Raw(sql, futureGoodEdbInfoId, pars).QueryRows(&list)
 	return
 }
+
+func GetFutureGoodEdbDataListByIdsAndDate(futureGoodEdbInfoIds []int, startDate, endDate string) (list []*FutureGoodEdbData, err error) {
+	var pars []interface{}
+	sql := `SELECT * FROM future_good_edb_data WHERE 1=1 AND future_good_edb_info_id in (` + utils.GetOrmInReplace(len(futureGoodEdbInfoIds)) + `)  `
+	if startDate != "" {
+		sql += ` AND data_time>=? `
+		pars = append(pars, startDate)
+	}
+	if endDate != "" {
+		sql += ` AND data_time<=? `
+		pars = append(pars, endDate)
+	}
+
+	sql += ` ORDER BY data_time ASC `
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, futureGoodEdbInfoIds, pars).QueryRows(&list)
+	return
+}

+ 6 - 0
models/data_manage/future_good/request/future_good_chart.go

@@ -1,5 +1,9 @@
 package request
 
+import (
+	"eta/eta_chart_lib/models"
+)
+
 type EditChartEnInfoReq struct {
 	ChartInfoId int    `description:"图表ID"`
 	ChartNameEn string `description:"英文图表名称"`
@@ -13,6 +17,8 @@ type ChartInfoReq struct {
 	BaseEdbInfoId           int                `description:"基础的指标id"`
 	DateList                []ChartInfoDateReq `description:"日期配置"`
 	ProfitNameEn            string             `description:"利润英文名称"`
+	EdbInfoIdList           []int              `description:"现货指标ID列表"`
+	XDataList               []models.XData     `description:"横轴配置"`
 }
 
 // EdbInfoFromTag 计算指标的关联指标

+ 13 - 1
models/db.go

@@ -43,7 +43,7 @@ func init() {
 	initFutureGood()
 
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
-	data_manage.InitEdbSourceVar()
+	afterInitTable()
 }
 
 // initFutureGood 注册期货数据 数据表
@@ -55,3 +55,15 @@ func initFutureGood() {
 		new(future_good.ChartInfoFutureGoodProfit), //期货利润图的扩展表
 	)
 }
+
+// afterInitTable
+// @Description: 初始化表结构的的后置操作
+// @author: Roc
+// @datetime 2024-07-01 13:31:09
+func afterInitTable() {
+	// 初始化指标来源配置
+	data_manage.InitEdbSourceVar()
+
+	// 初始化是否启用mongo配置
+	InitUseMongoConf()
+}

+ 6 - 4
models/edb_data_base.go

@@ -8,11 +8,13 @@ import (
 func GetEdbDataTableName(source, subSource int) (tableName string) {
 	switch source {
 	case utils.DATA_SOURCE_THS:
-		tableName = "edb_data_ths"
-		if subSource == utils.DATA_SUB_SOURCE_EDB {
-			tableName = "edb_data_ths"
-		} else {
+		switch subSource {
+		case utils.DATA_SUB_SOURCE_DATE:
 			tableName = "edb_data_ths_ds"
+		case utils.DATA_SUB_SOURCE_HIGH_FREQUENCY:
+			tableName = "edb_data_ths_hf"
+		default:
+			tableName = "edb_data_ths"
 		}
 	case utils.DATA_SOURCE_WIND:
 		if subSource == utils.DATA_SUB_SOURCE_EDB {

+ 510 - 0
models/mgo/edb_data_ths_hf.go

@@ -0,0 +1,510 @@
+package mgo
+
+import (
+	"context"
+	"errors"
+	"eta/eta_chart_lib/utils"
+	"fmt"
+	"github.com/qiniu/qmgo"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"time"
+)
+
+// EdbDataThsHf
+// @Description: 同花顺高频集合(指标库)
+type EdbDataThsHf struct {
+	ID            primitive.ObjectID `json:"_id" bson:"_id,omitempty" `            // 文档id
+	EdbInfoId     int                `json:"edb_info_id" bson:"edb_info_id"`       // 指标ID
+	EdbCode       string             `json:"edb_code" bson:"edb_code"`             // 指标编码
+	DataTime      time.Time          `json:"data_time" bson:"data_time"`           // 数据日期
+	Value         float64            `json:"value" bson:"value"`                   // 数据值
+	CreateTime    time.Time          `json:"create_time" bson:"create_time"`       // 创建时间
+	ModifyTime    time.Time          `json:"modify_time" bson:"modify_time"`       // 修改时间
+	DataTimestamp int64              `json:"data_timestamp" bson:"data_timestamp"` // 数据日期时间戳
+}
+
+// CollectionName
+// @Description:  获取集合名称
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:36
+// @return string
+func (m *EdbDataThsHf) CollectionName() string {
+	return "edb_data_ths_hf"
+}
+
+// DataBaseName
+// @Description: 获取数据库名称
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:33
+// @return string
+func (m *EdbDataThsHf) DataBaseName() string {
+	return utils.MgoDataDbName
+}
+
+// GetCollection
+// @Description: 获取mongodb集合的句柄
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:33
+// @return string
+func (m *EdbDataThsHf) GetCollection() *qmgo.Collection {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	return db.Collection(m.CollectionName())
+}
+
+// GetItem
+// @Description: 根据条件获取单条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-09 10:00:49
+// @param whereParams interface{}
+// @return item *EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetItem(whereParams interface{}) (item *EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.GetItemByColl(coll, whereParams)
+}
+
+// GetItemByColl
+// @Description: 根据条件获取单条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-09 13:22:06
+// @param coll *qmgo.Collection
+// @param whereParams interface{}
+// @return item *EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetItemByColl(coll *qmgo.Collection, whereParams interface{}) (item *EdbDataThsHf, err error) {
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).One(&item)
+	if err != nil {
+		return
+	}
+
+	item.DataTime = item.DataTime.In(time.Local)
+	item.CreateTime = item.CreateTime.In(time.Local)
+	item.ModifyTime = item.ModifyTime.In(time.Local)
+
+	return
+}
+
+// GetAllDataList
+// @Description: 根据条件获取所有数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:42:19
+// @param whereParams interface{}
+// @param sort []string
+// @return result []EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetAllDataList(whereParams interface{}, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetLimitDataList
+// @Description: 根据条件获取指定数量数据列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-06 17:08:32
+// @param whereParams interface{}
+// @param size int64
+// @param sort []string
+// @return result []*BaseFromBusinessData
+// @return err error
+func (m *EdbDataThsHf) GetLimitDataList(whereParams interface{}, size int64, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).Limit(size).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetPageDataList
+// @Description: 根据条件获取分页数据列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-07 10:21:07
+// @param whereParams interface{}
+// @param startSize int64
+// @param size int64
+// @param sort []string
+// @return result []*EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetPageDataList(whereParams interface{}, startSize, size int64, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).Skip(startSize).Limit(size).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetCountDataList
+// @Description:  根据条件获取数据列表总数
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-07 10:29:00
+// @param whereParams interface{}
+// @return count int64
+// @return err error
+func (m *EdbDataThsHf) GetCountDataList(whereParams interface{}) (count int64, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	count, err = coll.Find(ctx, whereParams).Count()
+
+	return
+}
+
+// InsertDataByColl
+// @Description: 写入单条数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param addData interface{}
+// @return err error
+func (m *EdbDataThsHf) InsertDataByColl(coll *qmgo.Collection, addData interface{}) (err error) {
+	ctx := context.TODO()
+	_, err = coll.InsertOne(ctx, addData)
+	if err != nil {
+		fmt.Println("InsertDataByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// BatchInsertData
+// @Description: 批量写入数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param bulk int 每次请求保存的数据量
+// @param dataList []interface{}
+// @return err error
+func (m *EdbDataThsHf) BatchInsertData(bulk int, dataList []interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.BatchInsertDataByColl(coll, bulk, dataList)
+}
+
+// BatchInsertDataByColl
+// @Description: 批量写入数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param coll *qmgo.Collection
+// @param bulk int 每次请求保存的数据量
+// @param dataList []interface{}
+// @return err error
+func (m *EdbDataThsHf) BatchInsertDataByColl(coll *qmgo.Collection, bulk int, dataList []interface{}) (err error) {
+	ctx := context.TODO()
+	dataNum := len(dataList)
+	if dataNum <= 0 {
+		return
+	}
+
+	// 不设置每次保存切片数量大小,或者实际数据量小于设置的切片数量大小,那么就直接保存吧
+	if bulk <= 0 || dataNum <= bulk {
+		_, err = coll.InsertMany(ctx, dataList)
+		if err != nil {
+			fmt.Println("BatchInsertData:Err:" + err.Error())
+			return
+		}
+		return
+	}
+
+	// 分批保存
+	i := 0
+	tmpAddDataList := make([]interface{}, 0)
+	for _, v := range dataList {
+		tmpAddDataList = append(tmpAddDataList, v)
+		i++
+		if i >= bulk {
+			_, err = coll.InsertMany(ctx, tmpAddDataList)
+			if err != nil {
+				fmt.Println("BatchInsertData:Err:" + err.Error())
+				return
+			}
+			i = 0
+			tmpAddDataList = make([]interface{}, 0)
+		}
+	}
+
+	if len(tmpAddDataList) > 0 {
+		_, err = coll.InsertMany(ctx, tmpAddDataList)
+		if err != nil {
+			fmt.Println("BatchInsertData:Err:" + err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+// UpdateData
+// @Description: 单条数据修改
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 15:01:51
+// @param whereParams interface{}
+// @param updateParams interface{}
+// @return err error
+func (m *EdbDataThsHf) UpdateData(whereParams, updateParams interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.UpdateDataByColl(coll, whereParams, updateParams)
+}
+
+// UpdateDataByColl
+// @Description: 单条数据修改(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 15:01:51
+// @param whereParams interface{}
+// @param updateParams interface{}
+// @return err error
+func (m *EdbDataThsHf) UpdateDataByColl(coll *qmgo.Collection, whereParams, updateParams interface{}) (err error) {
+	ctx := context.TODO()
+	err = coll.UpdateOne(ctx, whereParams, updateParams)
+	if err != nil {
+		fmt.Println("UpdateDataByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// RemoveMany
+// @Description: 根据条件删除多条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 13:17:02
+// @param whereParams interface{}
+// @return err error
+func (m *EdbDataThsHf) RemoveMany(whereParams interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.RemoveManyByColl(coll, whereParams)
+}
+
+// RemoveManyByColl
+// @Description: 根据条件删除多条数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 13:18:42
+// @param coll *qmgo.Collection
+// @param whereParams interface{}
+// @return err error
+func (m *EdbDataThsHf) RemoveManyByColl(coll *qmgo.Collection, whereParams interface{}) (err error) {
+	ctx := context.TODO()
+	_, err = coll.RemoveAll(ctx, whereParams)
+	if err != nil {
+		fmt.Println("RemoveManyByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// HandleData
+// @Description: 事务处理数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 10:39:01
+// @param addDataList []AddEdbDataThsHf
+// @param updateDataList []EdbDataThsHf
+// @return result interface{}
+// @return err error
+func (m *EdbDataThsHf) HandleData(addDataList, updateDataList []EdbDataThsHf) (result interface{}, err error) {
+
+	ctx := context.TODO()
+
+	callback := func(sessCtx context.Context) (interface{}, error) {
+		// 重要:确保事务中的每一个操作,都使用传入的sessCtx参数
+
+		db := utils.MgoDataCli.Database(m.DataBaseName())
+		coll := db.Collection(m.CollectionName())
+
+		// 插入数据
+		if len(addDataList) > 0 {
+			_, err = coll.InsertMany(sessCtx, addDataList)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		// 修改
+
+		if len(updateDataList) > 0 {
+			for _, v := range updateDataList {
+				err = coll.UpdateOne(ctx, bson.M{"_id": v.ID}, bson.M{"$set": bson.M{"value": v.Value, "modify_time": v.ModifyTime}})
+				if err != nil {
+					fmt.Println("BatchInsertData:Err:" + err.Error())
+					return nil, err
+				}
+			}
+		}
+
+		return nil, nil
+	}
+	result, err = utils.MgoDataCli.DoTransaction(ctx, callback)
+
+	return
+}
+
+// EdbInfoMaxAndMinInfo 指标最新数据记录结构体
+//type EdbInfoMaxAndMinInfo struct {
+//	MinDate     time.Time `description:"最小日期" bson:"min_date"`
+//	MaxDate     time.Time `description:"最大日期" bson:"max_date"`
+//	MinValue    float64   `description:"最小值" bson:"min_value"`
+//	MaxValue    float64   `description:"最大值" bson:"max_value"`
+//	LatestValue float64   `description:"最新值" bson:"latest_value"`
+//	LatestDate  time.Time `description:"实际数据最新日期" bson:"latest_date"`
+//	EndValue    float64   `description:"最新值" bson:"end_value"`
+//}
+
+// GetEdbInfoMaxAndMinInfo
+// @Description: 获取当前指标的最大最小值
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 17:15:39
+// @param whereParams interface{}
+// @return result EdbInfoMaxAndMinInfo
+// @return err error
+func (m *EdbDataThsHf) GetEdbInfoMaxAndMinInfo(whereParams interface{}) (result EdbInfoMaxAndMinInfo, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Aggregate(ctx, whereParams).One(&result)
+	if err != nil {
+		return
+	}
+	result.MinDate = result.MinDate.In(time.Local)
+	result.MaxDate = result.MaxDate.In(time.Local)
+	result.LatestDate = result.LatestDate.In(time.Local)
+
+	return
+}
+
+// LatestValue 指标最新数据记录结构体
+//type LatestValue struct {
+//	Value float64 `description:"值" bson:"value"`
+//}
+
+// GetLatestValue
+// @Description: 获取当前指标的最新数据记录
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 17:16:15
+// @param whereParams interface{}
+// @param selectParam interface{}
+// @return latestValue LatestValue
+// @return err error
+func (m *EdbDataThsHf) GetLatestValue(whereParams, selectParam interface{}) (latestValue LatestValue, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+
+	//var result interface{}
+	//err = coll.Find(ctx, whereParams).Select(selectParam).One(&result)
+	err = coll.Find(ctx, whereParams).Select(selectParam).One(&latestValue)
+	return
+}

+ 7 - 5
services/data/base_edb_lib.go

@@ -75,11 +75,13 @@ func RefreshEdbData(edbInfoId, source, subSource int, edbCode, startDate string)
 	urlStr := ``
 	switch source {
 	case utils.DATA_SOURCE_THS:
-		urlStr = "ths/refresh"
-		if subSource == 0 {
-			urlStr = "ths/refresh"
-		} else {
+		switch subSource {
+		case utils.DATA_SUB_SOURCE_DATE:
 			urlStr = "ths/ds/refresh"
+		case utils.DATA_SUB_SOURCE_HIGH_FREQUENCY:
+			urlStr = "ths/hf/edb/refresh"
+		default:
+			urlStr = "ths/refresh"
 		}
 	case utils.DATA_SOURCE_WIND:
 		if subSource == 0 {
@@ -137,7 +139,7 @@ func RefreshEdbData(edbInfoId, source, subSource int, edbCode, startDate string)
 		urlStr = "gz/refresh"
 	case utils.DATA_SOURCE_ICPI:
 		urlStr = "icpi/refresh"
-		case utils.DATA_SOURCE_SCI99:
+	case utils.DATA_SOURCE_SCI99:
 		urlStr = "sci99/refresh"
 	default:
 		edbSource := data_manage.EdbSourceIdMap[source]

+ 548 - 1
services/data/chart_info.go

@@ -290,6 +290,19 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 
 	// 特殊图形数据处理
 	switch chartType {
+	case 2: // 季节性图
+		if seasonExtraConfig != "" {
+			// 季节性图计算不管图上数据时间,拿所有数据
+			_, tempEdbList, e := getEdbDataMapList(chartInfoId, chartType, calendar, "1990-01-01", "", mappingList, seasonExtraConfig)
+			if e != nil {
+				err = e
+				return
+			}
+			dataResp, err = SeasonChartData(tempEdbList, seasonExtraConfig)
+		} else {
+			// 兼容无配置的老图
+			dataResp = new(models.SeasonChartResp)
+		}
 	case 6: //时序组合图
 		//判断是否堆积
 		timeConf := extraConfig.(models.ChartTimeCombineExtraConf)
@@ -417,6 +430,9 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 		var diffSeconds int64
 		if chartType == 2 { //季节性图
 			startDateReal = startDate
+			if len(mappingList) > 1 {
+				item.IsAxis = v.IsAxis
+			}
 		} else {
 			if v.EdbInfoType == 0 && v.LeadUnit != "" && v.LeadValue > 0 { //领先指标
 				var startTimeRealTemp time.Time
@@ -516,7 +532,7 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 			}
 		}
 
-		if chartType == 2 {
+		if chartType == 2 && item.IsAxis == 1 {
 			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
 			if tmpErr != nil {
 				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
@@ -548,6 +564,29 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 				}
 				item.DataList = quarterDataList
 			}
+		} else if chartType == 2 && item.IsAxis == 0 {
+			// 右轴数据处理,只要最新一年
+			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
+			if tmpErr != nil {
+				//item.DataList = dataList
+				item.IsNullData = true
+				edbList = append(edbList, item)
+				continue
+				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
+				return
+			}
+			newDataList := make([]*models.EdbDataList, 0)
+			for _, v := range dataList {
+				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
+				if e != nil {
+					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
+					return
+				}
+				if dataTime.Year() == latestDate.Year() {
+					newDataList = append(newDataList, v)
+				}
+			}
+			item.DataList = newDataList
 		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
 			//item.DataList = dataList
 		} else {
@@ -1917,3 +1956,511 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 	}
 	return
 }
+
+// SeasonChartData 季节性图的数据处理
+func SeasonChartData(dataList []*models.ChartEdbInfoMapping, seasonExtraConfig string) (dataResp models.SeasonChartResp, err error) {
+	var seasonConfig models.SeasonExtraItem
+	err = json.Unmarshal([]byte(seasonExtraConfig), &seasonConfig)
+	if err != nil {
+		err = errors.New("季节性图配置异常, Err:" + err.Error())
+		return
+	}
+
+	for _, mappingItem := range dataList {
+		if mappingItem.IsAxis == 0 {
+			continue
+		}
+		quarterDataList, ok := mappingItem.DataList.(models.QuarterDataList)
+		if !ok {
+			continue
+		}
+		// 上下限区间
+		if seasonConfig.MaxMinLimits.Year > 0 {
+			startYear := time.Now().AddDate(-seasonConfig.MaxMinLimits.Year, 0, 0).Year()
+			dataResp.MaxMinLimits.List = make([]*models.MaxMinLimitsData, 0)
+			dataTimeMap := make(map[time.Time]time.Time)
+			dataTimeList := make([]string, 0)
+			maxValueMap := make(map[time.Time]float64)
+			minValueMap := make(map[time.Time]float64)
+
+			maxMinDataList := make([]*models.MaxMinLimitsData, 0)
+			var startDateStr string
+			var endDateStr string
+			var newDate time.Time
+
+			startDateStr = fmt.Sprintf("%d-%s", time.Now().Year(), seasonConfig.XStartDate)
+			endDateStr = fmt.Sprintf("%d-%s", time.Now().Year(), seasonConfig.XEndDate)
+			startDate, e := time.Parse(utils.FormatDate, startDateStr)
+			if e != nil {
+				err = e
+				return
+			}
+			endDate, e := time.Parse(utils.FormatDate, endDateStr)
+			if e != nil {
+				err = e
+				return
+			}
+			// 日度 周度插值
+			for _, v := range quarterDataList {
+				if mappingItem.Frequency == "日度" || mappingItem.Frequency == "周度" {
+					handleDataMap := make(map[string]float64)
+					dataTimeList, _, err = HandleDataByLinearRegressionToList(v.DataList, handleDataMap)
+					if err != nil {
+						err = errors.New("插值处理数据异常, Err:" + err.Error())
+						return
+					}
+					// 不包含当年
+					if v.ChartLegend == strconv.Itoa(time.Now().Year()) {
+						continue
+					}
+					for _, date := range dataTimeList {
+						dateTime, e := time.Parse(utils.FormatDate, date)
+						if e != nil {
+							err = errors.New("时间格式化异常, Err:" + e.Error())
+							return
+						}
+						if dateTime.Year() < startYear {
+							continue
+						}
+						// 不包含2月29号
+						if dateTime.Month() == 2 && dateTime.Day() == 29 {
+							continue
+						}
+						newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year(), 0, 0)
+						if seasonConfig.JumpYear == 1 {
+							if startDate.After(endDate) {
+								// 如果跨年且不到一年
+								// 全年截取一部分
+								if newDate.Before(startDate.AddDate(0, 0, 1)) && newDate.After(endDate) {
+									continue
+								}
+								if newDate.After(startDate.AddDate(0, 0, -1)) {
+									// 减一年
+									newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year()-1, 0, 0)
+								}
+								// 处理上下限列表
+								if value, ok := maxValueMap[newDate]; ok {
+									if value < handleDataMap[date] {
+										maxValueMap[newDate] = handleDataMap[date]
+									}
+								} else {
+									maxValueMap[newDate] = handleDataMap[date]
+								}
+
+								if value, ok := minValueMap[newDate]; ok {
+									if value > handleDataMap[date] {
+										minValueMap[newDate] = handleDataMap[date]
+									}
+								} else {
+									minValueMap[newDate] = handleDataMap[date]
+								}
+
+								dataTimeMap[newDate] = newDate
+							} else {
+								// 如果跨年且大于等于一年
+								// double后截取
+								if newDate.After(startDate) {
+									// 处理上下限列表
+									if value, ok := maxValueMap[newDate]; ok {
+										if value < handleDataMap[date] {
+											maxValueMap[newDate] = handleDataMap[date]
+										}
+									} else {
+										maxValueMap[newDate] = handleDataMap[date]
+									}
+
+									if value, ok := minValueMap[newDate]; ok {
+										if value > handleDataMap[date] {
+											minValueMap[newDate] = handleDataMap[date]
+										}
+									} else {
+										minValueMap[newDate] = handleDataMap[date]
+									}
+
+									dataTimeMap[newDate] = newDate
+								}
+
+								newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year()+1, 0, 0)
+								newEndDate := endDate.AddDate(1, 0, 0)
+								if newDate.Before(newEndDate) {
+									// 处理上下限列表
+									if value, ok := maxValueMap[newDate]; ok {
+										if value < handleDataMap[date] {
+											maxValueMap[newDate] = handleDataMap[date]
+										}
+									} else {
+										maxValueMap[newDate] = handleDataMap[date]
+									}
+
+									if value, ok := minValueMap[newDate]; ok {
+										if value > handleDataMap[date] {
+											minValueMap[newDate] = handleDataMap[date]
+										}
+									} else {
+										minValueMap[newDate] = handleDataMap[date]
+									}
+
+									dataTimeMap[newDate] = newDate
+								}
+
+							}
+						} else {
+							// 如果不跨年 正常获取
+							// 获取当前日期所在区间
+							// 处理上下限列表
+							if value, ok := maxValueMap[newDate]; ok {
+								if value < handleDataMap[date] {
+									maxValueMap[newDate] = handleDataMap[date]
+								}
+							} else {
+								maxValueMap[newDate] = handleDataMap[date]
+							}
+
+							if value, ok := minValueMap[newDate]; ok {
+								if value > handleDataMap[date] {
+									minValueMap[newDate] = handleDataMap[date]
+								}
+							} else {
+								minValueMap[newDate] = handleDataMap[date]
+							}
+
+							dataTimeMap[newDate] = newDate
+						}
+					}
+				} else {
+					// 旬度、月度、季度、半年度 不插值,需要先把日期列表和数据map取出来
+					for _, vv := range v.DataList {
+						dateTime, e := time.Parse(utils.FormatDate, vv.DataTime)
+						if e != nil {
+							err = errors.New("时间格式化异常, Err:" + e.Error())
+							return
+						}
+
+						// 不包含当年
+						if v.ChartLegend == strconv.Itoa(time.Now().Year()) {
+							continue
+						}
+
+						if dateTime.Year() < startYear {
+							continue
+						}
+						// 不包含2月29号
+						if dateTime.Month() == 2 && dateTime.Day() == 29 {
+							continue
+						}
+						newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year(), 0, 0)
+						if seasonConfig.JumpYear == 1 {
+							if startDate.After(endDate) {
+								// 如果跨年且不到一年
+								// 全年截取一部分
+								if newDate.Before(startDate.AddDate(0, 0, 1)) && newDate.After(endDate) {
+									continue
+								}
+								if newDate.After(startDate.AddDate(0, 0, -1)) {
+									// 减一年
+									newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year()-1, 0, 0)
+								}
+								// 处理上下限列表
+								if value, ok := maxValueMap[newDate]; ok {
+									if value < vv.Value {
+										maxValueMap[newDate] = vv.Value
+									}
+								} else {
+									maxValueMap[newDate] = vv.Value
+								}
+
+								if value, ok := minValueMap[newDate]; ok {
+									if value > vv.Value {
+										minValueMap[newDate] = vv.Value
+									}
+								} else {
+									minValueMap[newDate] = vv.Value
+								}
+
+								dataTimeMap[newDate] = newDate
+							} else {
+								// 如果跨年且大于等于一年
+								// double后截取
+								if newDate.After(startDate) {
+									// 处理上下限列表
+									if value, ok := maxValueMap[newDate]; ok {
+										if value < vv.Value {
+											maxValueMap[newDate] = vv.Value
+										}
+									} else {
+										maxValueMap[newDate] = vv.Value
+									}
+
+									if value, ok := minValueMap[newDate]; ok {
+										if value > vv.Value {
+											minValueMap[newDate] = vv.Value
+										}
+									} else {
+										minValueMap[newDate] = vv.Value
+									}
+
+									dataTimeMap[newDate] = newDate
+								}
+
+								newDate = dateTime.AddDate(time.Now().Year()-dateTime.Year()+1, 0, 0)
+								newEndDate := endDate.AddDate(1, 0, 0)
+								if newDate.Before(newEndDate) {
+									// 处理上下限列表
+									if value, ok := maxValueMap[newDate]; ok {
+										if value < vv.Value {
+											maxValueMap[newDate] = vv.Value
+										}
+									} else {
+										maxValueMap[newDate] = vv.Value
+									}
+
+									if value, ok := minValueMap[newDate]; ok {
+										if value > vv.Value {
+											minValueMap[newDate] = vv.Value
+										}
+									} else {
+										minValueMap[newDate] = vv.Value
+									}
+
+									dataTimeMap[newDate] = newDate
+								}
+
+							}
+						} else {
+							// 如果不跨年 正常获取
+							// 获取当前日期所在区间
+							// 处理上下限列表
+							if value, ok := maxValueMap[newDate]; ok {
+								if value < vv.Value {
+									maxValueMap[newDate] = vv.Value
+								}
+							} else {
+								maxValueMap[newDate] = vv.Value
+							}
+
+							if value, ok := minValueMap[newDate]; ok {
+								if value > vv.Value {
+									minValueMap[newDate] = vv.Value
+								}
+							} else {
+								minValueMap[newDate] = vv.Value
+							}
+
+							dataTimeMap[newDate] = newDate
+						}
+
+					}
+				}
+			}
+
+			for _, v := range dataTimeMap {
+				maxMinItem := &models.MaxMinLimitsData{}
+				if maxValue, ok := maxValueMap[v]; ok {
+					maxMinItem.MaxValue = maxValue
+				} else {
+					maxMinItem.MaxValue = minValueMap[v]
+				}
+
+				if minValue, ok := minValueMap[v]; ok {
+					maxMinItem.MinValue = minValue
+				} else {
+					maxMinItem.MinValue = maxValueMap[v]
+				}
+
+				maxMinItem.DataTime = v.Format(utils.FormatDate)
+				maxMinItem.DataTimestamp = v.UnixNano() / 1e6
+
+				maxMinDataList = append(maxMinDataList, maxMinItem)
+
+			}
+
+			// 排序
+			sort.Slice(maxMinDataList, func(i, j int) bool {
+				return maxMinDataList[i].DataTime < maxMinDataList[j].DataTime
+			})
+
+			dataResp.MaxMinLimits.List = maxMinDataList
+			dataResp.MaxMinLimits.Color = seasonConfig.MaxMinLimits.Color
+			dataResp.MaxMinLimits.Legend = seasonConfig.MaxMinLimits.Legend
+			dataResp.MaxMinLimits.IsShow = seasonConfig.MaxMinLimits.IsShow
+			dataResp.MaxMinLimits.IsAdd = seasonConfig.MaxMinLimits.IsAdd
+			dataResp.MaxMinLimits.Year = seasonConfig.MaxMinLimits.Year
+		}
+
+		// 自定义同期均线
+		if seasonConfig.SamePeriodAverage.Year > 0 {
+			handleDataMap := make(map[string]float64)
+			dataTimeMap := make(map[time.Time]time.Time)
+			dataTimeList := make([]string, 0)
+			valueMap := make(map[time.Time]float64)
+			averageDataList := make([]*models.SamePeriodAverageData, 0)
+			for i := len(quarterDataList) - 1; i >= 0; i-- {
+				// 插值成日度
+				dataTimeList, _, err = HandleDataByLinearRegressionToList(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
+					}
+					startYear := time.Now().AddDate(-seasonConfig.SamePeriodAverage.Year, 0, 0).Year()
+					if dateTime.Year() < startYear {
+						continue
+					}
+					// 不包含2月29号
+					if dateTime.Month() == 2 && dateTime.Day() == 29 {
+						continue
+					}
+					// 不包含当年
+					if quarterDataList[i].ChartLegend == strconv.Itoa(time.Now().Year()) {
+						continue
+					}
+					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
+				}
+			}
+
+			for _, v := range dataTimeMap {
+				averageItem := &models.SamePeriodAverageData{}
+				if value, ok := valueMap[v]; ok {
+					averageItem.Value = value
+				}
+				averageItem.DataTime = v.Format(utils.FormatDate)
+				averageItem.DataTimestamp = v.UnixNano() / 1e6
+
+				averageDataList = append(averageDataList, averageItem)
+
+			}
+
+			// 排序
+			sort.Slice(averageDataList, func(i, j int) bool {
+				return averageDataList[i].DataTime < averageDataList[j].DataTime
+			})
+
+			dataResp.SamePeriodAverage.List = averageDataList
+			dataResp.SamePeriodAverage.Year = seasonConfig.SamePeriodAverage.Year
+			dataResp.SamePeriodAverage.Color = seasonConfig.SamePeriodAverage.Color
+			dataResp.SamePeriodAverage.Legend = seasonConfig.SamePeriodAverage.Legend
+			dataResp.SamePeriodAverage.IsShow = seasonConfig.SamePeriodAverage.IsShow
+			dataResp.SamePeriodAverage.LineType = seasonConfig.SamePeriodAverage.LineType
+			dataResp.SamePeriodAverage.LineWidth = seasonConfig.SamePeriodAverage.LineWidth
+			dataResp.SamePeriodAverage.IsAdd = seasonConfig.SamePeriodAverage.IsAdd
+
+		}
+
+		// 自定义同期标准差
+		if seasonConfig.SamePeriodStandardDeviation.Year > 1 && seasonConfig.SamePeriodStandardDeviation.Multiple > 0 {
+			startYear := time.Now().AddDate(-seasonConfig.SamePeriodStandardDeviation.Year, 0, 0).Year()
+
+			// 先算均值,再算标准差
+			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([]*models.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
+					}
+					if dateTime.Year() < startYear {
+						continue
+					}
+					// 不包含2月29号
+					if dateTime.Month() == 2 && dateTime.Day() == 29 {
+						continue
+					}
+					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 := &models.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
+			dataResp.SamePeriodStandardDeviation.IsAdd = seasonConfig.SamePeriodStandardDeviation.IsAdd
+		}
+
+		// 自定义右轴
+		if seasonConfig.RightAxis.IndicatorType != 0 {
+			if seasonConfig.RightAxis.IndicatorType == 1 {
+				startTime, _ := time.Parse(utils.FormatDate, mappingItem.StartDate)
+				for i := len(quarterDataList) - 1; i > len(quarterDataList)-2 && i > 0; i-- {
+					var rightMappingItem models.ChartEdbInfoMapping
+					rightMappingItem = *mappingItem
+					// 计算同比值
+					tbzDataList, minValue, maxValue, e := GetEdbDataTbzForSeason(mappingItem.Frequency, quarterDataList[i].DataList, startTime)
+					if e != nil {
+						err = errors.New("计算同比值失败, Err:" + e.Error())
+						return
+					}
+					rightMappingItem.DataList = tbzDataList
+					rightMappingItem.MaxData = maxValue
+					rightMappingItem.MinData = minValue
+					dataResp.RightAxis.EdbInfoList = append(dataResp.RightAxis.EdbInfoList, &rightMappingItem)
+				}
+			}
+			dataResp.RightAxis.SeasonRightAxis = seasonConfig.RightAxis
+		}
+	}
+
+	return
+}

+ 9 - 0
services/data/chart_theme.go

@@ -29,6 +29,9 @@ func GetChartThemeConfig(chartThemeId, source, chartType int) (chartTheme *chart
 		newConfig, e := ConvertOldChartOptions(chartTheme.Config)
 		if e == nil {
 			chartTheme.Config = newConfig
+		} else {
+			err = e
+			return
 		}
 		return
 	}
@@ -55,6 +58,9 @@ func GetChartThemeConfig(chartThemeId, source, chartType int) (chartTheme *chart
 		newConfig, e := ConvertOldChartOptions(chartTheme.Config)
 		if e == nil {
 			chartTheme.Config = newConfig
+		} else {
+			err = e
+			return
 		}
 		return
 	}
@@ -66,6 +72,9 @@ func GetChartThemeConfig(chartThemeId, source, chartType int) (chartTheme *chart
 	newConfig, e := ConvertOldChartOptions(chartTheme.Config)
 	if e == nil {
 		chartTheme.Config = newConfig
+	} else {
+		err = e
+		return
 	}
 	return
 }

+ 113 - 0
services/data/edb_data.go

@@ -0,0 +1,113 @@
+package data
+
+import (
+	"eta/eta_chart_lib/models"
+	"eta/eta_chart_lib/utils"
+	"time"
+)
+
+// GetEdbDataTbzForSeason 获取指标的同比值数据
+func GetEdbDataTbzForSeason(frequency string, tmpDataList []*models.EdbDataList, startDateTime time.Time) (dataList []*models.EdbDataList, minValue, maxValue float64, err error) {
+	dataList = make([]*models.EdbDataList, 0)
+
+	// 数据处理
+	var dateArr []string
+	dataMap := make(map[string]*models.EdbDataList)
+	for _, v := range tmpDataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+	}
+	for _, av := range dateArr {
+		currentItem, ok := dataMap[av]
+		// 如果找不到当前日期的数据,那么终止当前循环,进入下一循环
+		if !ok {
+			continue
+		}
+		tmpItem := *currentItem
+		var isOk bool //是否计算出来结果
+
+		//当前日期
+		currentDate, tmpErr := time.ParseInLocation(utils.FormatDate, av, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果存在开始日期,同时,当前日期早于开始日期,那么终止当前循环,进入下一循环
+		if !startDateTime.IsZero() && currentDate.Before(startDateTime) {
+			continue
+		}
+		//上一年的日期
+		preDate := currentDate.AddDate(-1, 0, 0)
+		preDateStr := preDate.Format(utils.FormatDate)
+		if findItem, ok := dataMap[preDateStr]; ok { //上一年同期找到
+			tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+			isOk = true
+		} else {
+			if frequency == "月度" { //向上和向下,各找一个月
+				for i := 0; i <= 35; i++ {
+					nextDateDay := preDate.AddDate(0, 0, i)
+					nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+					if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+						isOk = true
+						break
+					} else {
+						preDateDay := preDate.AddDate(0, 0, -i)
+						preDateDayStr := preDateDay.Format(utils.FormatDate)
+						if findItem, ok := dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+							isOk = true
+							break
+						}
+					}
+				}
+			} else if frequency == "季度" || frequency == "年度" {
+				if findItem, ok := dataMap[preDateStr]; ok { //上一年同期->下一个月找到
+					tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+					isOk = true
+					break
+				}
+			} else {
+				nextDateDay := preDate.AddDate(0, 0, 1)
+				nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+
+				preDateDay := preDate.AddDate(0, 0, -1)
+				preDateDayStr := preDateDay.Format(utils.FormatDate)
+
+				for i := 0; i < 35; i++ {
+					if i >= 1 {
+						nextDateDay = nextDateDay.AddDate(0, 0, i)
+						nextDateDayStr = nextDateDay.Format(utils.FormatDate)
+					}
+					if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+						isOk = true
+						break
+					} else {
+						if i >= 1 {
+							preDateDay = preDate.AddDate(0, 0, -i)
+							preDateDayStr = nextDateDay.Format(utils.FormatDate)
+						}
+						if findItem, ok := dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							tmpItem.Value = TbzDiv(currentItem.Value, findItem.Value)
+							isOk = true
+							break
+						}
+					}
+				}
+			}
+		}
+
+		if isOk {
+			if tmpItem.Value > maxValue {
+				maxValue = tmpItem.Value
+			}
+			if tmpItem.Value < minValue {
+				minValue = tmpItem.Value
+			}
+			dataList = append(dataList, &tmpItem)
+		}
+	}
+
+	return
+}

+ 142 - 0
services/data/edb_info.go

@@ -7,6 +7,8 @@ import (
 	"eta/eta_chart_lib/services/alarm_msg"
 	"eta/eta_chart_lib/utils"
 	"fmt"
+	"github.com/shopspring/decimal"
+	"math"
 	"sort"
 	"time"
 )
@@ -1265,3 +1267,143 @@ func GetEdbSourceByEdbInfoIdListForExcel(edbInfoIdList []int) (sourceNameList, s
 	}
 	return
 }
+
+
+// HandleDataByLinearRegressionToList 插值法补充数据(线性方程式)
+func HandleDataByLinearRegressionToList (edbInfoDataList []*models.EdbDataList, handleDataMap map[string]float64) (dataTimeList []string,valueList []float64, err error) {
+	if len(edbInfoDataList) < 2 {
+		return
+	}
+
+	var startEdbInfoData *models.EdbDataList
+	for _, v := range edbInfoDataList {
+		handleDataMap[v.DataTime] = v.Value
+		dataTimeList = append(dataTimeList, v.DataTime)
+		// 第一个数据就给过滤了,给后面的试用
+		if startEdbInfoData == nil {
+			startEdbInfoData = v
+			//startEdbInfoData.DataTime = startEdbInfoData.DataTime[:5]+ "01-01"
+			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
+		}
+
+		// 生成线性方程式
+		var a, b float64
+		{
+			coordinateData := make([]utils.Coordinate, 0)
+			tmpCoordinate1 := utils.Coordinate{
+				X: 1,
+				Y: startEdbInfoData.Value,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate1)
+			tmpCoordinate2 := utils.Coordinate{
+				X: float64(betweenDay) + 1,
+				Y: v.Value,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate2)
+
+			a, b = utils.GetLinearResult(coordinateData)
+			if math.IsNaN(a) || math.IsNaN(b) {
+				err = errors.New("线性方程公式生成失败")
+				return
+			}
+		}
+
+		// 生成对应的值
+		{
+			for i := 1; i < betweenDay; i++ {
+				tmpDataTime := startDataTime.AddDate(0, 0, i)
+				aDecimal := decimal.NewFromFloat(a)
+				xDecimal := decimal.NewFromInt(int64(i) + 1)
+				bDecimal := decimal.NewFromFloat(b)
+
+				val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
+				handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
+				dataTimeList = append(dataTimeList, tmpDataTime.Format(utils.FormatDate))
+				valueList = append(valueList, val)
+			}
+		}
+
+		startEdbInfoData = v
+	}
+
+	return
+}
+
+// HandleDataByLinearRegressionToList 保证生成365个数据点的线性插值法
+func HandleDataByLinearRegressionToListV2(edbInfoDataList []*models.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
+}

+ 390 - 197
services/data/future_good/chart_info.go

@@ -4,7 +4,7 @@ import (
 	"errors"
 	"eta/eta_chart_lib/models"
 	"eta/eta_chart_lib/models/data_manage"
-	"eta/eta_chart_lib/models/data_manage/future_good"
+	future_good2 "eta/eta_chart_lib/models/data_manage/future_good"
 	"eta/eta_chart_lib/services/alarm_msg"
 	"eta/eta_chart_lib/services/data"
 	"eta/eta_chart_lib/utils"
@@ -16,42 +16,46 @@ import (
 )
 
 // GetChartEdbData 获取图表的指标数据
-func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping, futureGoodEdbInfoMapping *models.ChartEdbInfoMapping, barChartInfoDateList []data_manage.BarChartInfoDateReq) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*models.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []models.XData, yDataList []models.YData, err error) {
+func GetChartEdbData(chartInfoId int, startDate, endDate string, baseEdbInfoMapping *models.ChartEdbInfoMapping, edbInfoMappingList []*models.ChartEdbInfoMapping, futureGoodEdbInfoMapping *models.ChartEdbInfoMapping, barChartInfoConf data_manage.FutureGoodBarChartInfoReq, needData bool) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*models.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []models.YData, err error) {
 	edbList = make([]*models.ChartEdbInfoMapping, 0)
-
+	barChartInfoDateList := barChartInfoConf.DateList
 	if futureGoodEdbInfoMapping == nil {
 		err = errors.New("商品指标未选取")
 		return
 	}
-	if edbInfoMapping == nil {
+	if len(edbInfoMappingList) == 0 {
 		err = errors.New("ETA指标未选取")
 		return
 	}
+
 	// 指标对应的所有数据
 	edbDataListMap := make(map[int][]*models.EdbDataList)
 
-	item := new(data_manage.ChartEdbInfoMapping)
-	edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency)
+	// todo item
+	//item := new(models.ChartEdbInfoMapping)
 
-	if edbInfoMapping.Unit == `无` {
-		edbInfoMapping.Unit = ``
-	}
 	if futureGoodEdbInfoMapping.Unit == `无` {
 		futureGoodEdbInfoMapping.Unit = ``
 	}
 
 	if chartInfoId <= 0 {
-		edbInfoMapping.IsAxis = 1
-		edbInfoMapping.LeadValue = 0
-		edbInfoMapping.LeadUnit = ""
-		edbInfoMapping.ChartEdbMappingId = 0
-		edbInfoMapping.ChartInfoId = 0
-		edbInfoMapping.IsOrder = false
-		edbInfoMapping.EdbInfoType = 1
-		edbInfoMapping.ChartStyle = ""
-		edbInfoMapping.ChartColor = ""
-		edbInfoMapping.ChartWidth = 0
-
+		for k, edbInfoMapping := range edbInfoMappingList {
+			edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency)
+			if edbInfoMapping.Unit == `无` {
+				edbInfoMapping.Unit = ``
+			}
+			edbInfoMapping.IsAxis = 1
+			edbInfoMapping.LeadValue = 0
+			edbInfoMapping.LeadUnit = ""
+			edbInfoMapping.ChartEdbMappingId = 0
+			edbInfoMapping.ChartInfoId = 0
+			edbInfoMapping.IsOrder = false
+			edbInfoMapping.EdbInfoType = 1
+			edbInfoMapping.ChartStyle = ""
+			edbInfoMapping.ChartColor = ""
+			edbInfoMapping.ChartWidth = 0
+			edbInfoMappingList[k] = edbInfoMapping
+		}
 		futureGoodEdbInfoMapping.IsAxis = 1
 		futureGoodEdbInfoMapping.LeadValue = 0
 		futureGoodEdbInfoMapping.LeadUnit = ""
@@ -63,37 +67,53 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		futureGoodEdbInfoMapping.ChartColor = ""
 		futureGoodEdbInfoMapping.ChartWidth = 0
 	} else {
-		edbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(edbInfoMapping.LeadUnit)
+		for k, edbInfoMapping := range edbInfoMappingList {
+			edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency)
+			if edbInfoMapping.Unit == `无` {
+				edbInfoMapping.Unit = ``
+			}
+			edbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(edbInfoMapping.LeadUnit)
+			edbInfoMappingList[k] = edbInfoMapping
+		}
 		futureGoodEdbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(futureGoodEdbInfoMapping.LeadUnit)
 	}
 
+	//查询横轴配置项
+	xDataItemMap := make(map[int]data_manage.XData)
+	for k, v := range barChartInfoConf.XDataList {
+		xDataItemMap[k] = v
+	}
+
 	// 普通的指标数据
 	{
-		dataList := make([]*models.EdbDataList, 0)
-
-		dataList, err = models.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, startDate, endDate)
-		edbDataListMap[edbInfoMapping.EdbInfoId] = dataList
-		item.DataList = dataList
-
-		edbList = append(edbList, edbInfoMapping)
-
-		barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, data_manage.BarChartInfoEdbItemReq{
-			EdbInfoId: edbInfoMapping.EdbInfoId,
-			//Name:      edbInfoMapping.EdbName,
-			Name:   "现货价",
-			NameEn: "Spot Price",
-			Source: edbInfoMapping.Source,
-		})
+		edbList = edbInfoMappingList
+
+		for k, edbInfoMapping := range edbInfoMappingList {
+			tmp := data_manage.BarChartInfoEdbItemReq{
+				EdbInfoId: edbInfoMapping.EdbInfoId,
+				Name:      edbInfoMapping.EdbName,
+				NameEn:    edbInfoMapping.EdbNameEn,
+				Source:    edbInfoMapping.Source,
+			}
+			// 如果有配置,则用配置中的指标名称替换
+			xItem, ok := xDataItemMap[k]
+			if ok && xItem.Name != "" {
+				tmp.Name = xItem.Name
+				tmp.NameEn = xItem.NameEn
+				tmp.IsHide = xItem.IsHide
+			}
+			barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, tmp)
+		}
 	}
 
 	// 获取主力合约和最新日期
-	var zlFutureGoodEdbInfo *future_good.FutureGoodEdbInfo
+	var zlFutureGoodEdbInfo *future_good2.FutureGoodEdbInfo
 	var latestDate string // 最新日期是这个
 	var regionType string // 交易所来源:“国内”,“海外”
 	var futureGoodEdbType int
 	{
 		// 寻找主力合约
-		zlFutureGoodEdbInfo, err = future_good.GetFutureGoodEdbInfo(futureGoodEdbInfoMapping.EdbInfoId)
+		zlFutureGoodEdbInfo, err = future_good2.GetFutureGoodEdbInfo(futureGoodEdbInfoMapping.EdbInfoId)
 		if err != nil {
 			return
 		}
@@ -102,7 +122,7 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 
 		// 如果当前合约配置的 "画图时,日期来源的指标id" 并不是自己的话,那么就去查找对应配置的合约
 		if zlFutureGoodEdbInfo.DateSourceId != zlFutureGoodEdbInfo.FutureGoodEdbInfoId {
-			sourceDateFutureGoodEdbInfo, tmpErr := future_good.GetFutureGoodEdbInfo(zlFutureGoodEdbInfo.DateSourceId)
+			sourceDateFutureGoodEdbInfo, tmpErr := future_good2.GetFutureGoodEdbInfo(zlFutureGoodEdbInfo.DateSourceId)
 			if tmpErr != nil {
 				err = tmpErr
 				return
@@ -118,7 +138,7 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 	}
 
 	// 获取期货指标以及期货数据
-	tmpFutureGoodEdbInfoList, err := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
+	tmpFutureGoodEdbInfoList, err := future_good2.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
 	if err != nil {
 		return
 	}
@@ -139,30 +159,30 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 			EdbName:             v.FutureGoodEdbName,
 			EdbAliasName:        v.FutureGoodEdbName,
 			EdbNameEn:           v.FutureGoodEdbNameEn,
-			EdbType:             edbInfoMapping.EdbType,
-			Frequency:           edbInfoMapping.Frequency,
-			FrequencyEn:         edbInfoMapping.FrequencyEn,
-			Unit:                edbInfoMapping.Unit,
-			UnitEn:              edbInfoMapping.UnitEn,
+			EdbType:             baseEdbInfoMapping.EdbType, //todo baseEdbInfoMapping
+			Frequency:           baseEdbInfoMapping.Frequency,
+			FrequencyEn:         baseEdbInfoMapping.FrequencyEn,
+			Unit:                baseEdbInfoMapping.Unit,
+			UnitEn:              baseEdbInfoMapping.UnitEn,
 			StartDate:           v.StartDate,
 			EndDate:             v.EndDate,
 			ModifyTime:          v.ModifyTime.Format(utils.FormatDateTime),
 			ChartEdbMappingId:   v.FutureGoodEdbInfoId,
-			ChartInfoId:         edbInfoMapping.ChartInfoId,
+			ChartInfoId:         baseEdbInfoMapping.ChartInfoId,
 			MaxData:             v.MaxValue,
 			MinData:             v.MinValue,
-			IsOrder:             edbInfoMapping.IsOrder,
-			IsAxis:              edbInfoMapping.IsAxis,
-			EdbInfoType:         edbInfoMapping.EdbInfoType,
-			EdbInfoCategoryType: edbInfoMapping.EdbInfoCategoryType,
-			LeadValue:           edbInfoMapping.LeadValue,
-			LeadUnit:            edbInfoMapping.LeadUnit,
-			LeadUnitEn:          edbInfoMapping.LeadUnitEn,
-			ChartStyle:          edbInfoMapping.ChartStyle,
-			ChartColor:          edbInfoMapping.ChartColor,
-			PredictChartColor:   edbInfoMapping.PredictChartColor,
-			ChartWidth:          edbInfoMapping.ChartWidth,
-			ChartType:           edbInfoMapping.ChartType,
+			IsOrder:             baseEdbInfoMapping.IsOrder,
+			IsAxis:              baseEdbInfoMapping.IsAxis,
+			EdbInfoType:         baseEdbInfoMapping.EdbInfoType,
+			EdbInfoCategoryType: baseEdbInfoMapping.EdbInfoCategoryType,
+			LeadValue:           baseEdbInfoMapping.LeadValue,
+			LeadUnit:            baseEdbInfoMapping.LeadUnit,
+			LeadUnitEn:          baseEdbInfoMapping.LeadUnitEn,
+			ChartStyle:          baseEdbInfoMapping.ChartStyle,
+			ChartColor:          baseEdbInfoMapping.ChartColor,
+			PredictChartColor:   baseEdbInfoMapping.PredictChartColor,
+			ChartWidth:          baseEdbInfoMapping.ChartWidth,
+			ChartType:           baseEdbInfoMapping.ChartType,
 			LatestDate:          v.LatestDate.Format(utils.FormatDateTime),
 			LatestValue:         v.LatestValue,
 			UniqueCode:          futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(k),
@@ -173,20 +193,113 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		}
 		futureGoodMappingList = append(futureGoodMappingList, newMappingInfo)
 
-		barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, data_manage.BarChartInfoEdbItemReq{
+		tmp := data_manage.BarChartInfoEdbItemReq{
 			EdbInfoId: newMappingInfo.EdbInfoId,
 			Name:      fmt.Sprint("M+", v.Month),
 			NameEn:    fmt.Sprint("M+", v.Month),
 			Source:    newMappingInfo.Source,
-		})
+		}
+		// 判断如果有配置,需要替换为配置内容
+		xItem, ok := xDataItemMap[k]
+		if ok && xItem.Name != "" {
+			tmp.Name = xItem.Name
+			tmp.NameEn = xItem.NameEn
+			tmp.IsHide = xItem.IsHide
+		}
+		barConfigEdbInfoIdList = append(barConfigEdbInfoIdList, tmp)
+
+	}
+
+	if regionType == `海外` {
+		zlFutureGoodEdbMapping := &models.ChartEdbInfoMapping{
+			EdbInfoId:           zlFutureGoodEdbInfo.FutureGoodEdbInfoId,
+			SourceName:          zlFutureGoodEdbInfo.Exchange,
+			Source:              0,
+			EdbCode:             zlFutureGoodEdbInfo.FutureGoodEdbCode,
+			EdbName:             zlFutureGoodEdbInfo.FutureGoodEdbName,
+			EdbAliasName:        zlFutureGoodEdbInfo.FutureGoodEdbName,
+			EdbNameEn:           zlFutureGoodEdbInfo.FutureGoodEdbNameEn,
+			EdbType:             baseEdbInfoMapping.EdbType,
+			Frequency:           baseEdbInfoMapping.Frequency,
+			FrequencyEn:         baseEdbInfoMapping.FrequencyEn,
+			Unit:                baseEdbInfoMapping.Unit,
+			UnitEn:              baseEdbInfoMapping.UnitEn,
+			StartDate:           zlFutureGoodEdbInfo.StartDate,
+			EndDate:             zlFutureGoodEdbInfo.EndDate,
+			ModifyTime:          zlFutureGoodEdbInfo.ModifyTime.Format(utils.FormatDateTime),
+			ChartEdbMappingId:   zlFutureGoodEdbInfo.FutureGoodEdbInfoId,
+			ChartInfoId:         baseEdbInfoMapping.ChartInfoId,
+			MaxData:             zlFutureGoodEdbInfo.MaxValue,
+			MinData:             zlFutureGoodEdbInfo.MinValue,
+			IsOrder:             baseEdbInfoMapping.IsOrder,
+			IsAxis:              baseEdbInfoMapping.IsAxis,
+			EdbInfoType:         baseEdbInfoMapping.EdbInfoType,
+			EdbInfoCategoryType: baseEdbInfoMapping.EdbInfoCategoryType,
+			LeadValue:           baseEdbInfoMapping.LeadValue,
+			LeadUnit:            baseEdbInfoMapping.LeadUnit,
+			LeadUnitEn:          baseEdbInfoMapping.LeadUnitEn,
+			ChartStyle:          baseEdbInfoMapping.ChartStyle,
+			ChartColor:          baseEdbInfoMapping.ChartColor,
+			PredictChartColor:   baseEdbInfoMapping.PredictChartColor,
+			ChartWidth:          baseEdbInfoMapping.ChartWidth,
+			ChartType:           baseEdbInfoMapping.ChartType,
+			LatestDate:          zlFutureGoodEdbInfo.LatestDate.Format(utils.FormatDateTime),
+			LatestValue:         zlFutureGoodEdbInfo.LatestValue,
+			UniqueCode:          futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(0),
+			MinValue:            zlFutureGoodEdbInfo.MinValue,
+			MaxValue:            zlFutureGoodEdbInfo.MaxValue,
+			DataList:            nil,
+			IsNullData:          false,
+		}
+		edbList = append(edbList, zlFutureGoodEdbMapping)
+		edbList = append(edbList, futureGoodMappingList...)
+	} else {
+		edbList = append(edbList, futureGoodMappingList...)
+	}
+
+	if !needData {
+		return
 	}
 
 	// 获取数据
-	for _, v := range futureGoodMappingList {
-		dataList := make([]*models.EdbDataList, 0)
 
-		tmpDataList, tmpErr := future_good.GetFutureGoodEdbDataListByDate(v.EdbInfoId, startDate, endDate)
+	// 现货数据
+	for _, edbInfoMapping := range edbInfoMappingList {
+		dataList := make([]*models.EdbDataList, 0)
+		dataList, err = models.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, startDate, endDate)
+		if err != nil {
+			return
+		}
+		edbDataListMap[edbInfoMapping.EdbInfoId] = dataList
+		// todo item
+		//item.DataList = dataList
+	}
+	futureEdbInfoIds := make([]int, 0)
+	for _, v := range futureGoodMappingList {
+		futureEdbInfoIds = append(futureEdbInfoIds, v.EdbInfoId)
+	}
+	tmpDataListMap := make(map[int][]*future_good2.FutureGoodEdbData)
+	if len(futureEdbInfoIds) > 0 {
+		// 期货数据
+		tmpDataList, tmpErr := future_good2.GetFutureGoodEdbDataListByIdsAndDate(futureEdbInfoIds, startDate, endDate)
 		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		for _, v := range tmpDataList {
+			if _, ok := tmpDataListMap[v.FutureGoodEdbInfoId]; !ok {
+				tmpDataListMap[v.FutureGoodEdbInfoId] = make([]*future_good2.FutureGoodEdbData, 0)
+			}
+			tmpDataListMap[v.FutureGoodEdbInfoId] = append(tmpDataListMap[v.FutureGoodEdbInfoId], v)
+		}
+	}
+
+	for _, v := range futureGoodMappingList {
+		dataList := make([]*models.EdbDataList, 0)
+		tmpDataList, ok := tmpDataListMap[v.EdbInfoId]
+		if !ok {
+			err = fmt.Errorf("期货数据不存在 FutureGoodEdbInfoId: %d", v.EdbInfoId)
 			return
 		}
 		for _, tmpData := range tmpDataList {
@@ -202,18 +315,22 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		v.DataList = dataList
 	}
 
-	edbList = append(edbList, futureGoodMappingList...)
-
-	xEdbIdValue, yDataList, err = BarChartData(edbList[0], futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, edbInfoMapping.EndDate)
+	xEdbIdValue, yDataList, err = BarChartData(baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, baseEdbInfoMapping.EndDate)
 
-	xDataList = []models.XData{
-		{
-			Name:   "现货价",
-			NameEn: "Spot Price",
-		},
+	if len(barChartInfoConf.XDataList) > 0 {
+		xDataList = barChartInfoConf.XDataList
+	} else {
+		for _, v := range edbInfoMappingList {
+			xDataList = append(xDataList, data_manage.XData{
+				Name:   v.EdbName,
+				NameEn: v.EdbNameEn,
+				IsHide: 0,
+			})
+		}
 	}
-	//yDataList =make([]data_manage.YData,0)
-	//data_manage.YData{
+
+	//yDataList =make([]models.YData,0)
+	//models.YData{
 	//	Date:           "",
 	//	Color:          "",
 	//	Name:           "",
@@ -241,14 +358,15 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		}
 
 		// 基础指标
-		{
-			baseEdbInfId := edbList[0].EdbInfoId
-			edbInfoIdList = append(edbInfoIdList, baseEdbInfId)
-			tmpVal, ok := yDataMap[baseEdbInfId]
+		baseEdbIds := make([]int, 0)
+		for _, tmp := range edbInfoMappingList {
+			edbInfoIdList = append(edbInfoIdList, tmp.EdbInfoId)
+			baseEdbIds = append(baseEdbIds, tmp.EdbInfoId)
+			tmpVal, ok := yDataMap[tmp.EdbInfoId]
 			valueList = append(valueList, tmpVal)
 			if !ok || tmpVal == 0 {
-				noDataEdbInfoIdList = append(noDataEdbInfoIdList, baseEdbInfId)
-				noDataEdbIdMap[baseEdbInfId] = baseEdbInfId
+				noDataEdbInfoIdList = append(noDataEdbInfoIdList, tmp.EdbInfoId)
+				noDataEdbIdMap[tmp.EdbInfoId] = tmp.EdbInfoId
 			}
 		}
 
@@ -271,7 +389,7 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 
 		for i := lenEdbId - 1; i >= 0; i-- {
 			// 如果没有在无数据的指标列表中找到,那么就找到了最大x轴的下标
-			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok {
+			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok || utils.InArrayByInt(baseEdbIds, edbInfoIdList[i]) {
 				// 如果最大x轴的下标 小于 当前下标,那么就重新赋值
 				if maxIndex < i-1 {
 					maxIndex = i - 1
@@ -307,32 +425,58 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 			yDataList[k].Value = v.Value[0 : maxIndex+1]
 		}
 	}
-
-	tmpXDataList, newYDataList, err := handleResultData(regionType, futureGoodEdbType, yDataList, futureGoodEdbInfoList, maxIndex)
+	baseEdbLen := len(edbInfoMappingList)
+	tmpXDataList, newYDataList, err := handleResultData(regionType, futureGoodEdbType, baseEdbLen, yDataList, futureGoodEdbInfoList, maxIndex)
 	if err != nil {
 		return
 	}
-	xDataList = append(xDataList, tmpXDataList...)
+	if len(barChartInfoConf.XDataList) == 0 {
+		xDataList = append(xDataList, tmpXDataList...)
+	}
+
 	yDataList = newYDataList
 
 	return
 }
 
-// BarChartData 柱方图的数据处理
-func BarChartData(edbInfoMapping *models.ChartEdbInfoMapping, futureGoodMappingList []*future_good.FutureGoodEdbInfo, edbDataListMap map[int][]*models.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []models.YData, err error) {
+// BarChartData 获取数据
+func BarChartData(baseEdbInfoMapping *models.ChartEdbInfoMapping, edbInfoMappingList []*models.ChartEdbInfoMapping, futureGoodMappingList []*future_good2.FutureGoodEdbInfo, edbDataListMap map[int][]*models.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []models.YData, err error) {
 	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
-	edbDataMap := make(map[int]map[string]float64)
+	// 现货指标数据map
+	baseEdbDataMap := make(map[int]map[string]float64)
+	edbInfoMappingMap := make(map[int]struct{})
+	for _, v := range edbInfoMappingList {
+		edbInfoMappingMap[v.EdbInfoId] = struct{}{}
+	}
 	for edbInfoId, edbDataList := range edbDataListMap {
+		if _, ok1 := edbInfoMappingMap[edbInfoId]; ok1 {
+			edbDateData := make(map[string]float64)
+			for _, edbData := range edbDataList {
+				edbDateData[edbData.DataTime] = edbData.Value
+			}
+			baseEdbDataMap[edbInfoId] = edbDateData
+		}
+	}
+
+	// 期货指标数据map
+	futureGoodEdbDataMap := make(map[int]map[string]float64)
+	for edbInfoId, edbDataList := range edbDataListMap {
+		if _, ok := edbInfoMappingMap[edbInfoId]; ok {
+			continue
+		}
 		edbDateData := make(map[string]float64)
 		for _, edbData := range edbDataList {
 			edbDateData[edbData.DataTime] = edbData.Value
 		}
-		edbDataMap[edbInfoId] = edbDateData
+		futureGoodEdbDataMap[edbInfoId] = edbDateData
 	}
 
 	// edbIdList 指标展示顺序;x轴的指标顺序
 	edbIdList = make([]int, 0)
-	edbIdList = append(edbIdList, edbInfoMapping.EdbInfoId)
+	for _, v := range edbInfoMappingList {
+		edbIdList = append(edbIdList, v.EdbInfoId)
+	}
+
 	for _, v := range futureGoodMappingList {
 		edbIdList = append(edbIdList, v.FutureGoodEdbInfoId)
 	}
@@ -373,23 +517,43 @@ func BarChartData(edbInfoMapping *models.ChartEdbInfoMapping, futureGoodMappingL
 		noDataIdMap := make(map[int]int, 0) // 没有数据的指标map
 		xEdbInfoIdList := make([]int, 0)    // 当前数据的指标id列表
 
-		// 现货指标
-		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[edbInfoMapping.EdbInfoId], edbDataMap[edbInfoMapping.EdbInfoId])
+		// 先找到基准日期
+		var realDateTime time.Time
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[baseEdbInfoMapping.EdbInfoId], baseEdbDataMap[baseEdbInfoMapping.EdbInfoId], futureGoodEdbDataMap)
 		if tmpErr != nil {
 			err = tmpErr
 			return
 		}
-		findDataList = append(findDataList, findDataValue)
-		yDataMap[edbInfoMapping.EdbInfoId] = findDataValue
-		if isFind {
-			maxDate = realDateTime
-		} else {
-			noDataIdList = append(noDataIdList, edbInfoMapping.EdbInfoId)
-			noDataIdMap[edbInfoMapping.EdbInfoId] = edbInfoMapping.EdbInfoId
+		// 处理其余现货指标
+		for _, v := range edbInfoMappingList {
+			if v.EdbInfoId == baseEdbInfoMapping.EdbInfoId {
+				findDataList = append(findDataList, findDataValue)
+				yDataMap[baseEdbInfoMapping.EdbInfoId] = findDataValue
+				if isFind {
+					maxDate = realDateTime
+				} else {
+					noDataIdList = append(noDataIdList, baseEdbInfoMapping.EdbInfoId)
+					noDataIdMap[baseEdbInfoMapping.EdbInfoId] = baseEdbInfoMapping.EdbInfoId
+				}
+				xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId)
+				continue
+			}
+			findDataValueTmp, isFindTmp := baseEdbDataMap[v.EdbInfoId][realDateTime.Format(utils.FormatDate)]
+			findDataList = append(findDataList, findDataValueTmp)
+			yDataMap[v.EdbInfoId] = findDataValueTmp
+			if !isFindTmp {
+				noDataIdList = append(noDataIdList, v.EdbInfoId)
+				noDataIdMap[v.EdbInfoId] = v.EdbInfoId
+			}
+			xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId)
 		}
-		currMonth := findDateTime.Month() // 当前月份
-		currYear := findDateTime.Year()   // 当前年份
-		xEdbInfoIdList = append(xEdbInfoIdList, edbInfoMapping.EdbInfoId)
+		//currMonth := findDateTime.Month() // 当前月份
+		//currYear := findDateTime.Year()   // 当前年份
+
+		// 用实际日期的月份作为基准,往前推12个月(2024-5-13 16:26:43修改)
+		currMonth := realDateTime.Month() // 当前月份
+		currYear := realDateTime.Year()   // 当前年份
+
 		mList := make([]int, 0) // 间隔月份
 		indexList := make([]int, 0)
 		if regionType == `国内` {
@@ -427,7 +591,7 @@ func BarChartData(edbInfoMapping *models.ChartEdbInfoMapping, futureGoodMappingL
 			//}
 			//tmpRealDateTime := findDateTime	// 按照配置找到的日期
 			tmpRealDateTime := realDateTime // 实际现货的日期
-			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
+			tmpFindDataValue, tmpIsFind := futureGoodEdbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
 			yDataMap[futureGoodMapping.FutureGoodEdbInfoId] = tmpFindDataValue
 
 			findDataList = append(findDataList, tmpFindDataValue)
@@ -508,86 +672,9 @@ func BarChartData(edbInfoMapping *models.ChartEdbInfoMapping, futureGoodMappingL
 	return
 }
 
-// GetNeedDateData 获取合约内需要的日期数据
-func GetNeedDateData(needDateTime time.Time, dataList []*models.EdbDataList, edbDataMap map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
-	//dataList := edbDataListMap[edbInfoId] //指标的所有数据值
-	if len(dataList) <= 0 {
-		// 没有数据的指标id
-		return
-	}
-
-	//最早的日期
-	minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
-	if err != nil {
-		return
-	}
-
-	for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
-		tmpDate := tmpDateTime.Format(utils.FormatDate)
-		if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据,那么就返回
-			// 数据为0,也直接返回,做无值处理
-			if tmpValue == 0 {
-				return
-			}
-			findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
-			findDataValue = tmpValue
-			isFind = true
-			return
-		}
-	}
-
-	return
-}
-
-// FutureGoodChartInfoRefresh
-// @author Roc
-// @datetime 2023-2-2 18:44:46
-// @description 商品价格曲线图表刷新
-func FutureGoodChartInfoRefresh(chartInfoId int) (err error) {
-	var errMsg string
-	defer func() {
-		if err != nil {
-			go alarm_msg.SendAlarmMsg("ChartInfoRefresh:"+errMsg, 3)
-			fmt.Println("ChartInfoRefresh Err:" + errMsg)
-		}
-	}()
-
-	edbInfoMapping, err := models.GetEtaEdbChartEdbMapping(chartInfoId)
-	if err != nil {
-		errMsg = "获取需要刷新的ETA指标失败:Err:" + err.Error()
-		return
-	}
-	// 获取期货指标
-	futureGoodEdbInfoMapping, err := models.GetFutureGoodEdbChartEdbMapping(chartInfoId)
-	if err != nil {
-		errMsg = "获取需要刷新的商品期货指标失败:Err:" + err.Error()
-		return
-	}
-
-	// 获取期货指标以及期货数据
-	futureGoodEdbInfoList, err := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
-	if err != nil {
-		return
-	}
-
-	// 批量刷新ETA指标
-	err, _ = data.EdbInfoRefreshAllFromBase([]int{edbInfoMapping.EdbInfoId}, false)
-	if err != nil {
-		return
-	}
-
-	// 批量刷新期货指标
-	err = FutureGoodEdbInfoRefreshAllFromBase(futureGoodEdbInfoList, false)
-	if err != nil {
-		return
-	}
-
-	return
-}
-
 // handleResultData 处理成最终的结果数据
-func handleResultData(regionType string, futureGoodEdbType int, yDataList []models.YData, futureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, maxIndex int) (xDataList []models.XData, newYDataList []models.YData, err error) {
-	xDataList = make([]models.XData, 0)
+func handleResultData(regionType string, futureGoodEdbType, baseEdbLen int, yDataList []models.YData, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, maxIndex int) (xDataList []data_manage.XData, newYDataList []models.YData, err error) {
+	xDataList = make([]data_manage.XData, 0)
 	newYDataList = yDataList
 
 	if regionType == `国内` {
@@ -595,7 +682,8 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 			if i > maxIndex {
 				break
 			}
-			xDataList = append(xDataList, models.XData{
+			// todo x轴 内容调整
+			xDataList = append(xDataList, data_manage.XData{
 				Name:   fmt.Sprint("M+", i),
 				NameEn: fmt.Sprint("M+", i),
 			})
@@ -603,7 +691,7 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 		return
 	}
 
-	futureGoodEdbInfoMap := make(map[int]*future_good.FutureGoodEdbInfo)
+	futureGoodEdbInfoMap := make(map[int]*future_good2.FutureGoodEdbInfo)
 	for _, v := range futureGoodEdbInfoList {
 		futureGoodEdbInfoMap[v.FutureGoodEdbInfoId] = v
 	}
@@ -611,7 +699,7 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 	if futureGoodEdbType == 2 { // 	FutureGoodEdbType   int       `description:"指标类型,1:年月是固定的合约;2:只有M+N期的合约,未固定年月"`
 		nList := []int{3, 15, 27}
 		for _, i := range nList {
-			xDataList = append(xDataList, models.XData{
+			xDataList = append(xDataList, data_manage.XData{
 				Name:   fmt.Sprint("M+", i),
 				NameEn: fmt.Sprint("M+", i),
 			})
@@ -623,11 +711,11 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 			tmpNList := nList
 
 			//当前的主力合约
-			newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0])
-			newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0])
+			newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0:baseEdbLen]...)
+			newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0:baseEdbLen]...)
 
-			xEdbInfoIdList := yData.XEdbInfoIdList[1:]
-			valIndex := 1
+			xEdbInfoIdList := yData.XEdbInfoIdList[baseEdbLen:]
+			valIndex := baseEdbLen
 			needNum := 0
 			for _, n := range tmpNList {
 				if len(xEdbInfoIdList) > 0 {
@@ -699,8 +787,8 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 		currYear := findDateTime.Year()   // 当前年份
 		//v.XEdbInfoIdList
 		for edbInfoIndex, edbInfoId := range v.XEdbInfoIdList {
-			// 第一个不处理
-			if edbInfoIndex == 0 {
+			// 现货指标不处理
+			if edbInfoIndex <= baseEdbLen-1 {
 				continue
 			}
 
@@ -727,7 +815,7 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 	//prevMonth := 1
 
 	for _, n := range nList {
-		xDataList = append(xDataList, models.XData{
+		xDataList = append(xDataList, data_manage.XData{
 			Name:   fmt.Sprint("M+", n),
 			NameEn: fmt.Sprint("M+", n),
 		})
@@ -739,12 +827,12 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 		tmpNList := nList
 
 		//当前的主力合约
-		newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0])
-		newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0])
+		newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, yData.XEdbInfoIdList[0:baseEdbLen]...)
+		newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[0:baseEdbLen]...)
 
-		xEdbInfoIdList := yData.XEdbInfoIdList[1:]
+		xEdbInfoIdList := yData.XEdbInfoIdList[baseEdbLen:]
 		currDataTime := yData.ConfigDate
-		valIndex := 1
+		valIndex := baseEdbLen
 		needNum := 0
 		for _, n := range tmpNList {
 			if len(xEdbInfoIdList) > 0 {
@@ -806,14 +894,13 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []mode
 			newYDataList[yIndex].Value = yData.Value[0 : maxI+1]
 		}
 	}
-
 	return
 }
 
 // getFutureGoodEdbInfoList 获取适用的指标列表
-func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, barChartInfoDateList []data_manage.BarChartInfoDateReq) (earliestDateTime time.Time, futureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, err error) {
+func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, barChartInfoDateList []data_manage.BarChartInfoDateReq) (earliestDateTime time.Time, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, err error) {
 	maxM := 36 //最大36期合约
-	futureGoodEdbInfoList = make([]*future_good.FutureGoodEdbInfo, 0)
+	futureGoodEdbInfoList = make([]*future_good2.FutureGoodEdbInfo, 0)
 	earliestDateTime = latestDateTime // 数据的最早日期,目的是为了找出最早的合约
 	for _, barChartInfoDate := range barChartInfoDateList {
 		var findDateTime time.Time
@@ -881,3 +968,109 @@ func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList
 
 	return
 }
+
+// GetNeedDateData 获取合约内需要的日期数据
+func GetNeedDateData(needDateTime time.Time, dataList []*models.EdbDataList, edbDataMap map[string]float64, allEdbDataMap map[int]map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
+	//dataList := edbDataListMap[edbInfoId] //指标的所有数据值
+	if len(dataList) <= 0 {
+		// 没有数据的指标id
+		return
+	}
+
+	//最早的日期
+	minDateTime, err := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+	if err != nil {
+		return
+	}
+
+	// 该日期存在数据的期货指标的最小数量,目前是现货和期货各1个,总共2个
+	maxCount := 1
+
+	for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
+		tmpDate := tmpDateTime.Format(utils.FormatDate)
+		tmpValue, ok := edbDataMap[tmpDate]
+		if !ok {
+			continue
+		}
+
+		// 该日期存在数据的指标数量
+		count := 0
+
+		for _, currEdbDataMap := range allEdbDataMap {
+			_, tmpIsFind := currEdbDataMap[tmpDate]
+			if tmpIsFind {
+				count++
+				if count >= maxCount {
+					continue
+				}
+			}
+		}
+
+		// 该日期存在数据的期货指标数量小于2个,那么要继续往前找
+		if count < maxCount {
+			continue
+		}
+
+		//如果能找到数据,那么就返回
+		// 数据为0,也直接返回,做无值处理
+		if tmpValue == 0 {
+			return
+		}
+		findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+		findDataValue = tmpValue
+		isFind = true
+		return
+	}
+
+	return
+}
+
+// FutureGoodChartInfoRefresh
+// @author Roc
+// @datetime 2023-2-2 18:44:46
+// @description 商品价格曲线图表刷新
+func FutureGoodChartInfoRefresh(chartInfoId int) (err error) {
+	var errMsg string
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("ChartInfoRefresh:"+errMsg, 3)
+			fmt.Println("ChartInfoRefresh Err:" + errMsg)
+		}
+	}()
+
+	edbInfoMappingList, err := models.GetEtaEdbChartEdbMappingList(chartInfoId)
+	if err != nil {
+		errMsg = "获取需要刷新的ETA指标失败:Err:" + err.Error()
+		return
+	}
+	edbInfoIds := make([]int, 0)
+	for _, edbInfoMapping := range edbInfoMappingList {
+		edbInfoIds = append(edbInfoIds, edbInfoMapping.EdbInfoId)
+	}
+	// 获取期货指标
+	futureGoodEdbInfoMapping, err := models.GetFutureGoodEdbChartEdbMapping(chartInfoId)
+	if err != nil {
+		errMsg = "获取需要刷新的商品期货指标失败:Err:" + err.Error()
+		return
+	}
+
+	// 获取期货指标以及期货数据
+	futureGoodEdbInfoList, err := future_good2.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
+	if err != nil {
+		return
+	}
+
+	// 批量刷新ETA指标
+	err, _ = data.EdbInfoRefreshAllFromBase(edbInfoIds, false)
+	if err != nil {
+		return
+	}
+
+	// 批量刷新期货指标
+	err = FutureGoodEdbInfoRefreshAllFromBase(futureGoodEdbInfoList, false)
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 6 - 0
services/dw_mini/base_mini_lib.go

@@ -18,9 +18,15 @@ func HttpPost(url, postData, token string) ([]byte, error) {
 	req.Header.Add("Authorization", token)
 	req.Header.Set("Content-Type", "application/json")
 	resp, err := client.Do(req)
+	if err != nil {
+		return nil, err
+	}
 	defer resp.Body.Close()
 	b, err := io.ReadAll(resp.Body)
 	fmt.Println("HttpPost:" + string(b))
+	if utils.RunMode == "debug" {
+		return b, err
+	}
 	str := string(b)
 	str = strings.Trim(str, `"`)
 	b = utils.DesBase64Decrypt([]byte(str), utils.ETA_MINI_DES_KEY)

+ 27 - 22
services/dw_mini/dw_mini.go

@@ -7,27 +7,41 @@ import (
 	"eta/eta_chart_lib/utils"
 )
 
+type MyChartIsCollect struct {
+	IsCollect bool
+}
+
+type BaseResponse struct {
+	Ret     int
+	Msg     string
+	ErrMsg  string
+	ErrCode string
+	Data    MyChartIsCollect
+}
+
+type MyChartIsCollectReq struct {
+	UniqueCode string
+}
+
+type MyChartCollectReq struct {
+	UniqueCode  string
+	ChartName   string
+	ChartImage  string
+	ChartInfoId int
+}
+
+type MyChartCollectCancelReq struct {
+	UniqueCode string
+}
+
 func GetMyChartIsCollect(token string, uniqueCode string) (isCollect bool, err error) {
 	url := utils.ETA_MINI_URL + "mychart/isCollect"
-	type MyChartIsCollectReq struct {
-		UniqueCode string
-	}
 	req := MyChartIsCollectReq{UniqueCode: uniqueCode}
 	reqBody, _ := json.Marshal(req)
 	result, err := HttpPost(url, string(reqBody), token)
 	if err != nil {
 		return
 	}
-	type MyChartIsCollect struct {
-		IsCollect bool
-	}
-	type BaseResponse struct {
-		Ret     int
-		Msg     string
-		ErrMsg  string
-		ErrCode string
-		Data    MyChartIsCollect
-	}
 	var resp BaseResponse
 	if err = json.Unmarshal(result, &resp); err != nil {
 		return
@@ -42,12 +56,6 @@ func GetMyChartIsCollect(token string, uniqueCode string) (isCollect bool, err e
 
 func MyChartCollect(token, uniqueCode, chartName, chartImage string, chartInfoId int) (resp *models.BaseResponse, err error) {
 	url := utils.ETA_MINI_URL + "mychart/collect"
-	type MyChartCollectReq struct {
-		UniqueCode  string
-		ChartName   string
-		ChartImage  string
-		ChartInfoId int
-	}
 	req := MyChartCollectReq{
 		UniqueCode:  uniqueCode,
 		ChartName:   chartName,
@@ -70,9 +78,6 @@ func MyChartCollect(token, uniqueCode, chartName, chartImage string, chartInfoId
 
 func MyChartCollectCancel(token string, uniqueCode string) (resp *models.BaseResponse, err error) {
 	url := utils.ETA_MINI_URL + "mychart/collectCancel"
-	type MyChartCollectCancelReq struct {
-		UniqueCode string
-	}
 	req := MyChartCollectCancelReq{UniqueCode: uniqueCode}
 	reqBody, _ := json.Marshal(req)
 	result, err := HttpPost(url, string(reqBody), token)

+ 4 - 0
utils/config.go

@@ -62,6 +62,10 @@ var (
 	LogMaxDays int //日志最大保留天数
 )
 
+var (
+	UseMongo bool // 是否使用mongo
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {

+ 3 - 2
utils/constants.go

@@ -210,8 +210,9 @@ var DataSourceEnMap = map[int]string{
 
 // 子数据来源渠道
 const (
-	DATA_SUB_SOURCE_EDB  = iota //经济数据库
-	DATA_SUB_SOURCE_DATE        //日期序列
+	DATA_SUB_SOURCE_EDB            = iota //经济数据库
+	DATA_SUB_SOURCE_DATE                  //日期序列
+	DATA_SUB_SOURCE_HIGH_FREQUENCY        //高频数据
 )
 
 const (