Browse Source

feat:新增跨品种分析图表

Roc 1 năm trước cách đây
mục cha
commit
c0bd07e675

+ 100 - 0
controller/chart/chart_common.go

@@ -19,6 +19,7 @@ import (
 	"hongze/hongze_yb/services/alarm_msg"
 	"hongze/hongze_yb/services/chart"
 	"hongze/hongze_yb/services/chart/correlation"
+	"hongze/hongze_yb/services/chart/cross_variety"
 	future_goodServ "hongze/hongze_yb/services/chart/future_good"
 	"hongze/hongze_yb/services/chart/line_equation"
 	"hongze/hongze_yb/services/chart/line_feature"
@@ -81,6 +82,8 @@ func CommonChartInfoDetailFromUniqueCode(c *gin.Context) {
 		resp, isOk, msg, errMsg = getChartInfoDetailFromUniqueCode(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	case utils.CHART_SOURCE_LINE_FEATURE_STANDARD_DEVIATION, utils.CHART_SOURCE_LINE_FEATURE_PERCENTILE, utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		resp, isOk, msg, errMsg = getLineFeatureChartInfoDetailFromUniqueCode(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
+	case utils.CHART_SOURCE_CROSS_HEDGING:
+		resp, isOk, msg, errMsg = GetCrossVarietyChartInfoDetailFromUniqueCode(chartInfo, myChartClassifyId, user.GetInfoByClaims(c))
 	default:
 		msg := "错误的图表"
 		errMsg := "错误的图表"
@@ -573,6 +576,103 @@ func getLineFeatureChartInfoDetailFromUniqueCode(chartInfo *chartInfoModel.Chart
 	return
 }
 
+// GetCrossVarietyChartInfoDetailFromUniqueCode
+// @Description: 获取跨品种分析图表
+// @author: Roc
+// @datetime 2023-11-29 09:38:23
+// @param chartInfo *chartInfoModel.ChartInfoView
+// @param myChartClassifyId int
+// @param userInfo user.UserInfo
+// @return resp *chart_info.ChartInfoDetailResp
+// @return isOk bool
+// @return msg string
+// @return errMsg string
+func GetCrossVarietyChartInfoDetailFromUniqueCode(chartInfo *chartInfoModel.ChartInfoView, myChartClassifyId int, userInfo user.UserInfo) (resp *chart_info.ChartInfoDetailResp, isOk bool, msg, errMsg string) {
+	resp = new(chart_info.ChartInfoDetailResp)
+	// 获取图表信息
+	var err error
+	if chartInfo.ExtraConfig == `` {
+		msg = "图表配置信息异常"
+		errMsg = "图表配置信息异常"
+		return
+	}
+	var config request.ChartConfigReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &config)
+	if err != nil {
+		msg = "解析跨品种分析配置失败"
+		errMsg = "解析跨品种分析配置失败,Err:" + err.Error()
+		return
+	}
+
+	var edbList []*chartEdbMappingModel.ChartEdbInfoMappingList
+	var resultResp interface{}
+	sourceArr := make([]string, 0)
+
+	// 获取图表x轴y轴
+	edbList, resultResp, sourceArr, err, msg, _ = cross_variety.GetChartData(0, config)
+	if err != nil {
+		errMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	if err != nil {
+		if msg == `` {
+			msg = "获取失败"
+		}
+		errMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	sourceArr = append(sourceArr, "弘则研究")
+	chartInfo.ChartSource = strings.Join(sourceArr, ",")
+
+	//baseEdbInfo := edbList[0] //现货指标
+	//chartInfo.UnitEn = baseEdbInfo.UnitEn
+
+	// 访问记录-仅普通用户记录
+	ok, _, _ := user.GetAdminByUserInfo(userInfo)
+	if !ok {
+		go chart.SaveChartVisitLog(userInfo, chartInfo, myChartClassifyId)
+	}
+
+	// 用户是否有收藏该图表
+	{
+		ob := new(yb_my_chart.YbMyChart)
+		cond := `user_id = ? AND chart_info_id = ?`
+		pars := make([]interface{}, 0)
+		pars = append(pars, userInfo.UserID, chartInfo.ChartInfoId)
+		exists, e := ob.FetchByCondition(cond, pars)
+		if e != nil && e != utils.ErrNoRow {
+			msg = `操作失败`
+			errMsg = "获取用户图表失败, Err: " + e.Error()
+			return
+		}
+		myChartInfo := new(responseModel.MyChartItem)
+		if exists != nil && exists.MyChartID > 0 {
+			myChartInfo.MyChartID = exists.MyChartID
+			myChartInfo.MyChartClassifyID = exists.MyChartClassifyID
+			myChartInfo.ChartInfoID = exists.ChartInfoID
+			myChartInfo.ChartName = exists.ChartName
+			myChartInfo.UniqueCode = exists.UniqueCode
+			myChartInfo.ChartImage = exists.ChartImage
+			myChartInfo.UserID = exists.UserID
+			myChartInfo.ReportID = exists.ReportID
+			myChartInfo.ReportChapterID = exists.ReportChapterID
+			myChartInfo.CreateTime = utils.TimeTransferString(utils.FormatDateTime, exists.CreateTime)
+		}
+
+		resp.MyChartInfo = myChartInfo
+	}
+
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.DataResp = resultResp
+
+	isOk = true
+
+	return
+}
+
 // RefreshFutureGoodChartInfo 刷新商品价格曲线图表信息
 // @Tags 图库模块
 // @Summary  刷新图表信息

+ 18 - 0
models/request/chart.go

@@ -174,3 +174,21 @@ type FrequencyDistribution struct {
 	EndDate        string `description:"自定义结束日期"`
 	FrequencyValue int    `description:"频段数,10/20"`
 }
+
+// ChartConfigReq
+// @Description: 跨品种分析的图表配置
+type ChartConfigReq struct {
+	TagX           int               `description:"X轴的标签ID"`
+	TagY           int               `description:"Y轴的标签ID"`
+	CalculateValue int               `description:"计算窗口"`
+	CalculateUnit  string            `description:"计算频度"`
+	DateConfigList []ChartConfigDate `description:"日期配置列表"`
+	VarietyList    []int             `description:"品种id列表"`
+}
+
+// ChartConfigDate
+// @Description: 跨品种分析的日期配置
+type ChartConfigDate struct {
+	DateType int `description:"日期类型,,1:最新日期;2:N天前"`
+	Num      int
+}

+ 38 - 0
models/tables/chart_tag/chart_tag.go

@@ -0,0 +1,38 @@
+package chart_tag
+
+import "time"
+
+// ChartTag 图表标签表
+type ChartTag struct {
+	ChartTagID      int       `gorm:"primaryKey;column:chart_tag_id" json:"-"`
+	ChartTagName    string    `gorm:"column:chart_tag_name" json:"chartTagName"`        // 标签名称
+	ChartTagNameEn  string    `gorm:"column:chart_tag_name_en" json:"chartTagNameEn"`   // 标签名称(英文)
+	SysUserID       int       `gorm:"column:sys_user_id" json:"sysUserId"`              // 操作人id
+	SysUserRealName string    `gorm:"column:sys_user_real_name" json:"sysUserRealName"` // 操作人真实姓名
+	ModifyTime      time.Time `gorm:"column:modify_time" json:"modifyTime"`             // 最近一次操作时间
+	CreateTime      time.Time `gorm:"column:create_time" json:"createTime"`             // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *ChartTag) TableName() string {
+	return "chart_tag"
+}
+
+// ChartTagColumns get sql column name.获取数据库列名
+var ChartTagColumns = struct {
+	ChartTagID      string
+	ChartTagName    string
+	ChartTagNameEn  string
+	SysUserID       string
+	SysUserRealName string
+	ModifyTime      string
+	CreateTime      string
+}{
+	ChartTagID:      "chart_tag_id",
+	ChartTagName:    "chart_tag_name",
+	ChartTagNameEn:  "chart_tag_name_en",
+	SysUserID:       "sys_user_id",
+	SysUserRealName: "sys_user_real_name",
+	ModifyTime:      "modify_time",
+	CreateTime:      "create_time",
+}

+ 25 - 0
models/tables/chart_tag/query.go

@@ -0,0 +1,25 @@
+package chart_tag
+
+import (
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/utils"
+)
+
+// GetTagListByIdList
+// @Description: 根据ID列表获取标签列表
+// @author: Roc
+// @datetime 2023-11-23 17:56:39
+// @param idList []int
+// @return items []*ChartTag
+// @return err error
+func GetTagListByIdList(idList []int) (items []*ChartTag, err error) {
+	num := len(idList)
+	if num <= 0 {
+		return
+	}
+
+	sql := `SELECT * FROM chart_tag WHERE 1 = 1 AND chart_tag_id in (` + utils.GetOrmInReplace(num) + `)`
+	err = global.MYSQL["data"].Raw(sql, idList).Find(&items).Error
+
+	return
+}

+ 41 - 0
models/tables/chart_tag_variety/chart_tag_variety.go

@@ -0,0 +1,41 @@
+package chart_tag_variety
+
+import "time"
+
+// ChartTagVariety 图表的标签品种关系表
+type ChartTagVariety struct {
+	ID                        uint64    `gorm:"primaryKey;column:id" json:"-"`
+	ChartTagID                uint64    `gorm:"column:chart_tag_id" json:"chartTagId"`                                  // 标签id
+	ChartVarietyID            uint64    `gorm:"column:chart_variety_id" json:"chartVarietyId"`                          // 品种id
+	EdbInfoID                 int64     `gorm:"column:edb_info_id" json:"edbInfoId"`                                    // 指标id
+	LastUpdateSysUserID       int       `gorm:"column:last_update_sys_user_id" json:"lastUpdateSysUserId"`              // 最后一次操作人
+	LastUpdateSysUserRealName string    `gorm:"column:last_update_sys_user_real_name" json:"lastUpdateSysUserRealName"` // 最后一次操作人真实姓名
+	ModifyTime                time.Time `gorm:"column:modify_time" json:"modifyTime"`                                   // 最近一次更新时间
+	CreateTime                time.Time `gorm:"column:create_time" json:"createTime"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *ChartTagVariety) TableName() string {
+	return "chart_tag_variety"
+}
+
+// ChartTagVarietyColumns get sql column name.获取数据库列名
+var ChartTagVarietyColumns = struct {
+	ID                        string
+	ChartTagID                string
+	ChartVarietyID            string
+	EdbInfoID                 string
+	LastUpdateSysUserID       string
+	LastUpdateSysUserRealName string
+	ModifyTime                string
+	CreateTime                string
+}{
+	ID:                        "id",
+	ChartTagID:                "chart_tag_id",
+	ChartVarietyID:            "chart_variety_id",
+	EdbInfoID:                 "edb_info_id",
+	LastUpdateSysUserID:       "last_update_sys_user_id",
+	LastUpdateSysUserRealName: "last_update_sys_user_real_name",
+	ModifyTime:                "modify_time",
+	CreateTime:                "create_time",
+}

+ 25 - 0
models/tables/chart_tag_variety/query.go

@@ -0,0 +1,25 @@
+package chart_tag_variety
+
+import (
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/utils"
+)
+
+// GetChartTagVarietyListByTagAndVariety
+// @Description: 根据标签id和品种id列表获取所绑定的品种列表
+// @author: Roc
+// @datetime 2023-11-23 15:04:20
+// @param chartTagId int
+// @param varietyIdList []int
+// @return items []*ChartTagVariety
+// @return err error
+func GetChartTagVarietyListByTagAndVariety(chartTagId int, varietyIdList []int) (items []*ChartTagVariety, err error) {
+	num := len(varietyIdList)
+	if num <= 0 {
+		return
+	}
+	sql := `SELECT * FROM chart_tag_variety WHERE chart_tag_id = ? AND chart_variety_id in (` + utils.GetOrmInReplace(num) + `) `
+	err = global.MYSQL["data"].Raw(sql, chartTagId, varietyIdList).Find(&items).Error
+
+	return
+}

+ 40 - 0
models/tables/chart_variety/chart_variety.go

@@ -0,0 +1,40 @@
+package chart_variety
+
+import (
+	"time"
+)
+
+// ChartVariety 图表品种表
+type ChartVariety struct {
+	ChartVarietyID     int       `gorm:"primaryKey;column:chart_variety_id" json:"-"`
+	ChartVarietyName   string    `gorm:"column:chart_variety_name" json:"chartVarietyName"`      // 品种名称
+	ChartVarietyNameEn string    `gorm:"column:chart_variety_name_en" json:"chartVarietyNameEn"` // 品种名称(英文)
+	SysUserID          int       `gorm:"column:sys_user_id" json:"sysUserId"`                    // 操作人id
+	SysUserRealName    string    `gorm:"column:sys_user_real_name" json:"sysUserRealName"`       // 操作人真实姓名
+	ModifyTime         time.Time `gorm:"column:modify_time" json:"modifyTime"`                   // 最近一次操作时间
+	CreateTime         time.Time `gorm:"column:create_time" json:"createTime"`                   // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *ChartVariety) TableName() string {
+	return "chart_variety"
+}
+
+// ChartVarietyColumns get sql column name.获取数据库列名
+var ChartVarietyColumns = struct {
+	ChartVarietyID     string
+	ChartVarietyName   string
+	ChartVarietyNameEn string
+	SysUserID          string
+	SysUserRealName    string
+	ModifyTime         string
+	CreateTime         string
+}{
+	ChartVarietyID:     "chart_variety_id",
+	ChartVarietyName:   "chart_variety_name",
+	ChartVarietyNameEn: "chart_variety_name_en",
+	SysUserID:          "sys_user_id",
+	SysUserRealName:    "sys_user_real_name",
+	ModifyTime:         "modify_time",
+	CreateTime:         "create_time",
+}

+ 24 - 0
models/tables/chart_variety/query.go

@@ -0,0 +1,24 @@
+package chart_variety
+
+import (
+	"hongze/hongze_yb/global"
+	"hongze/hongze_yb/utils"
+)
+
+// GetVarietyListByIdList
+// @Description: 根据ID列表获取品种列表
+// @author: Roc
+// @datetime 2023-11-23 17:56:39
+// @param idList []int
+// @return items []*ChartVariety
+// @return err error
+func GetVarietyListByIdList(idList []int) (items []*ChartVariety, err error) {
+	num := len(idList)
+	if num <= 0 {
+		return
+	}
+	sql := ` SELECT * FROM chart_variety WHERE 1 = 1 AND chart_variety_id in (` + utils.GetOrmInReplace(num) + `)`
+	err = global.MYSQL["data"].Raw(sql, idList).Find(&items).Error
+
+	return
+}

+ 411 - 0
services/chart/cross_variety/chart.go

@@ -0,0 +1,411 @@
+package cross_variety
+
+import (
+	"errors"
+	"fmt"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_yb/models/request"
+	chartEdbMappingModel "hongze/hongze_yb/models/tables/chart_edb_mapping"
+	chart_tagModel "hongze/hongze_yb/models/tables/chart_tag"
+	chart_tag_varietyModel "hongze/hongze_yb/models/tables/chart_tag_variety"
+	chart_varietyModel "hongze/hongze_yb/models/tables/chart_variety"
+	"hongze/hongze_yb/services/chart"
+	"hongze/hongze_yb/utils"
+	"time"
+)
+
+// ChartInfoResp 截面散点图数据
+type ChartInfoResp struct {
+	XName       string                         `description:"x轴名称"`
+	XNameEn     string                         `description:"x轴名称(英文)"`
+	XUnitName   string                         `description:"x轴单位名称"`
+	XUnitNameEn string                         `description:"x轴单位名称(英文)"`
+	YName       string                         `description:"y轴名称"`
+	YNameEn     string                         `description:"y轴名称(英文)"`
+	YUnitName   string                         `description:"y轴单位名称"`
+	YUnitNameEn string                         `description:"y轴单位名称(英文)"`
+	XMinValue   string                         `description:"X轴的最小值"`
+	XMaxValue   string                         `description:"X轴的最大值"`
+	YMinValue   string                         `description:"Y轴的最小值"`
+	YMaxValue   string                         `description:"Y轴的最大值"`
+	DataList    []SectionScatterSeriesItemResp `description:"数据列"`
+}
+
+// SectionScatterSeriesItemResp 系列的返回
+type SectionScatterSeriesItemResp struct {
+	Name                string            `description:"系列名"`
+	NameEn              string            `description:"系列名(英文)"`
+	Color               string            `description:"颜色"`
+	CoordinatePointData []CoordinatePoint `description:"趋势线的前后坐标点"`
+}
+
+// CoordinatePoint 坐标点
+type CoordinatePoint struct {
+	X          float64
+	Y          float64
+	XEdbInfoId int
+	YEdbInfoId int
+	XDate      string
+	YDate      string
+}
+
+// GetChartData
+// @Description: 获取跨品种分析图表数据
+// @author: Roc
+// @datetime 2023-11-24 09:42:59
+// @param chartInfoId int
+// @param config request.ChartConfigReq
+// @return edbList []*data_manage.ChartEdbInfoMapping
+// @return dataResp ChartInfoResp
+// @return err error
+// @return errMsg string
+// @return isSendEmail bool
+func GetChartData(chartInfoId int, config request.ChartConfigReq) (edbList []*chartEdbMappingModel.ChartEdbInfoMappingList, dataResp ChartInfoResp, sourceArr []string, err error, errMsg string, isSendEmail bool) {
+	moveUnitDays, ok := utils.FrequencyDaysMap[config.CalculateUnit]
+	if !ok {
+		errMsg = "错误的分析周期"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	isSendEmail = true
+
+	// 品种map
+	varietyMap := make(map[int]*chart_varietyModel.ChartVariety)
+	{
+		varietyList, tmpErr := chart_varietyModel.GetVarietyListByIdList(config.VarietyList)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range varietyList {
+			varietyMap[v.ChartVarietyID] = v
+		}
+	}
+
+	// 标签m
+	var xTagInfo, yTagInfo *chart_tagModel.ChartTag
+	{
+		tagList, tmpErr := chart_tagModel.GetTagListByIdList([]int{config.TagX, config.TagY})
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range tagList {
+			if v.ChartTagID == config.TagX {
+				xTagInfo = v
+			} else if v.ChartTagID == config.TagY {
+				yTagInfo = v
+			}
+		}
+	}
+	if xTagInfo == nil {
+		errMsg = "找不到对应的X轴标签"
+		err = errors.New(errMsg)
+		return
+	}
+	if yTagInfo == nil {
+		errMsg = "找不到对应的Y轴标签"
+		err = errors.New(errMsg)
+		return
+	}
+
+	xVarietyEdbMap, yVarietyEdbMap, edbInfoIdList, err := GetXYEdbIdList(config.TagX, config.TagY, config.VarietyList)
+	if err != nil {
+		return
+	}
+
+	if len(edbInfoIdList) <= 0 {
+		errMsg = "品种未配置指标"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+	mappingList, err := chartEdbMappingModel.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+	if err != nil {
+		errMsg = "获取指标信息失败"
+		err = errors.New("获取指标信息失败,ERR:" + err.Error())
+		return
+	}
+
+	// 指标对应的所有数据
+	chartType := 1 //1:普通图,2:季节性图
+	calendar := "公历"
+	edbDataListMap, edbList, sourceArr, err := chart.GetEdbDataMapList(chartInfoId, chartType, calendar, "", "", mappingList, "")
+	if err != nil {
+		return
+	}
+
+	currDay := time.Now()
+	currDay = time.Date(currDay.Year(), currDay.Month(), currDay.Day(), 0, 0, 0, 0, time.Local)
+
+	dataMap := make(map[string]float64)
+	dateMap := make(map[string]string)
+	for dateIndex, dateConfig := range config.DateConfigList {
+		for _, edbInfoMapping := range mappingList {
+			// 数据会是正序的
+			dataList, ok := edbDataListMap[edbInfoMapping.EdbInfoId]
+			if !ok {
+				continue
+			}
+
+			lenData := len(dataList)
+			if lenData <= 0 {
+				continue
+			}
+
+			// 数据开始日期
+			endDateStr := ``
+			var endDate time.Time
+			// 数据的开始索引
+			k := lenData - 1
+			var currVal float64
+			switch dateConfig.DateType {
+			case 1: // 1:最新日期;
+				endDateStr = dataList[k].DataTime
+				tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				endDate = tmpDate
+				currVal = dataList[k].Value
+			case 2: // 2:N天前
+				tmpEndDate := currDay.AddDate(0, 0, -dateConfig.Num)
+				tmpEndDateStr := tmpEndDate.Format(utils.FormatDate)
+
+				for i := k; i >= 0; i-- {
+					tmpDateStr := dataList[i].DataTime
+					// 如果正好是这一天,那么就直接break了
+					if tmpEndDateStr == tmpDateStr {
+						k = i
+						endDateStr = tmpDateStr
+						currVal = dataList[i].Value
+						break
+					}
+					tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					// 如果这期的日期晚于选择的日期,那么继续遍历
+					if tmpDate.After(tmpEndDate) {
+						continue
+					}
+					k = i
+					endDateStr = tmpDateStr
+					endDate = tmpDate
+					currVal = dataList[i].Value
+					break
+				}
+			}
+
+			// 没有找到日期,那么就不处理
+			if endDateStr == `` || endDate.IsZero() {
+				continue
+			}
+
+			// 最早的日期
+			earliestDate := endDate.AddDate(0, 0, -config.CalculateValue*moveUnitDays)
+			earliestDateStr := earliestDate.Format(utils.FormatDate)
+
+			var minVal, maxVal float64
+			var isNotFirst bool // 是否是第一条数据
+			for i := k; i >= 0; i-- {
+				tmpData := dataList[i]
+				if !isNotFirst {
+					maxVal = tmpData.Value
+					minVal = tmpData.Value
+					isNotFirst = true
+					continue
+				}
+
+				tmpDateStr := dataList[i].DataTime
+				// 如果正好是这一天,那么就直接break了
+				if earliestDateStr == tmpDateStr {
+					break
+				}
+				tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				// 如果这期的日期早于选择的日期,那么继续停止遍历
+				if tmpDate.Before(earliestDate) {
+					continue
+				}
+
+				if tmpData.Value > maxVal {
+					maxVal = tmpData.Value
+				}
+				if tmpData.Value < minVal {
+					minVal = tmpData.Value
+				}
+			}
+
+			// 最大值等于最小值,说明计算结果无效
+			if maxVal == minVal {
+				continue
+			}
+			//百分位=(现值-Min)/(Max-Min)
+			tmpV := (currVal - minVal) / (maxVal - minVal) * 100
+			tmpV, _ = decimal.NewFromFloat(tmpV).Round(4).Float64()
+
+			// key的生成(日期配置下标+指标id)
+			key := fmt.Sprint(dateIndex, "_", edbInfoMapping.EdbInfoId)
+			dataMap[key] = tmpV
+			dateMap[key] = endDateStr
+		}
+	}
+
+	// 返回数据处理
+	dataList := make([]SectionScatterSeriesItemResp, 0)
+	var xMinVal, xMaxVal, yMinVal, yMaxVal float64
+	var isNotFirst bool
+
+	for _, varietyId := range config.VarietyList {
+		xEdbInfoId, ok1 := xVarietyEdbMap[varietyId]
+		if !ok1 {
+			continue
+		}
+		yEdbInfoId, ok2 := yVarietyEdbMap[varietyId]
+		if !ok2 {
+			continue
+		}
+		variety, ok := varietyMap[varietyId]
+		if !ok {
+			continue
+		}
+
+		coordinatePointList := make([]CoordinatePoint, 0)
+
+		for dateIndex := range config.DateConfigList {
+			key1 := fmt.Sprint(dateIndex, "_", xEdbInfoId)
+			xVal, ok1 := dataMap[key1]
+			if !ok1 {
+				continue
+			}
+			key2 := fmt.Sprint(dateIndex, "_", yEdbInfoId)
+			yVal, ok2 := dataMap[key2]
+			if !ok2 {
+				continue
+			}
+			if !isNotFirst {
+				xMinVal = xVal
+				xMaxVal = xVal
+				yMinVal = yVal
+				yMaxVal = yVal
+				isNotFirst = true
+			} else {
+				if xVal < xMinVal {
+					xMinVal = xVal
+				}
+				if xVal > xMaxVal {
+					xMaxVal = xVal
+				}
+				if yVal < yMinVal {
+					yMinVal = yVal
+				}
+				if yVal > yMaxVal {
+					yMaxVal = yVal
+				}
+			}
+			coordinatePointList = append(coordinatePointList, CoordinatePoint{
+				X:          xVal,
+				Y:          yVal,
+				XEdbInfoId: xEdbInfoId,
+				YEdbInfoId: yEdbInfoId,
+				XDate:      dateMap[key1],
+				YDate:      dateMap[key2],
+			})
+		}
+
+		dataList = append(dataList, SectionScatterSeriesItemResp{
+			Name:                variety.ChartVarietyName,
+			NameEn:              variety.ChartVarietyNameEn,
+			Color:               "",
+			CoordinatePointData: coordinatePointList,
+		})
+	}
+
+	dataResp = ChartInfoResp{
+		XName:       xTagInfo.ChartTagName,
+		XNameEn:     xTagInfo.ChartTagNameEn,
+		XUnitName:   "%",
+		XUnitNameEn: "%",
+		YName:       yTagInfo.ChartTagName,
+		YNameEn:     yTagInfo.ChartTagNameEn,
+		YUnitName:   "%",
+		YUnitNameEn: "%",
+		XMinValue:   fmt.Sprint(xMinVal),
+		XMaxValue:   fmt.Sprint(xMaxVal),
+		YMinValue:   fmt.Sprint(yMinVal),
+		YMaxValue:   fmt.Sprint(yMaxVal),
+		DataList:    dataList,
+	}
+
+	// 去除返回指标中的数据信息,避免没必要的数据传输
+	for k := range edbList {
+		edbList[k].DataList = nil
+	}
+
+	return
+}
+
+// GetXYEdbIdList
+// @Description: 根据标签id和品种获取指标列表信息
+// @author: Roc
+// @datetime 2023-11-27 14:31:23
+// @param tagX int
+// @param tagY int
+// @param varietyList []int
+// @return xVarietyEdbMap map[int]int
+// @return yVarietyEdbMap map[int]int
+// @return edbInfoIdList []int
+// @return errMsg string
+// @return err error
+func GetXYEdbIdList(tagX, tagY int, varietyList []int) (xVarietyEdbMap, yVarietyEdbMap map[int]int, edbInfoIdList []int, err error) {
+	edbInfoIdList = make([]int, 0)
+	xVarietyEdbMap = make(map[int]int)
+	yVarietyEdbMap = make(map[int]int)
+	xList, err := chart_tag_varietyModel.GetChartTagVarietyListByTagAndVariety(tagX, varietyList)
+	if err != nil {
+		err = errors.New("获取X轴的品种指标配置信息失败,Err:" + err.Error())
+		return
+	}
+	yList, err := chart_tag_varietyModel.GetChartTagVarietyListByTagAndVariety(tagY, varietyList)
+	if err != nil {
+		err = errors.New("获取Y轴的品种指标配置信息失败,Err:" + err.Error())
+		return
+	}
+
+	baseVarietyIdMap := make(map[int]int)
+	for _, v := range xList {
+		baseVarietyIdMap[int(v.ChartVarietyID)] = int(v.ChartVarietyID)
+	}
+
+	// 两个标签里面的品种并集
+	needVarietyIdMap := make(map[int]int)
+	for _, v := range yList {
+		if val, ok := baseVarietyIdMap[int(v.ChartVarietyID)]; ok {
+			// 如果在 map2 中存在相同的键,则将键和值添加到结果中
+			needVarietyIdMap[int(v.ChartVarietyID)] = val
+		}
+	}
+
+	for _, v := range xList {
+		if _, ok := needVarietyIdMap[int(v.ChartVarietyID)]; ok {
+			xVarietyEdbMap[int(v.ChartVarietyID)] = int(v.EdbInfoID)
+			edbInfoIdList = append(edbInfoIdList, int(v.EdbInfoID))
+		}
+	}
+	for _, v := range yList {
+		if _, ok := needVarietyIdMap[int(v.ChartVarietyID)]; ok {
+			yVarietyEdbMap[int(v.ChartVarietyID)] = int(v.EdbInfoID)
+			edbInfoIdList = append(edbInfoIdList, int(v.EdbInfoID))
+		}
+	}
+
+	return
+}

+ 8 - 7
utils/constants.go

@@ -281,13 +281,14 @@ const ALIYUN_OSS_HOST = "https://hzstatic.hzinsights.com"
 const (
 	CHART_SOURCE_DEFAULT                         = 1
 	CHART_SOURCE_FUTURE_GOOD                     = 2
-	CHART_SOURCE_CORRELATION                     = 3 // 相关性图表
-	CHART_SOURCE_ROLLING_CORRELATION             = 4 // 滚动相关性图表
-	CHART_SOURCE_FUTURE_GOOD_PROFIT              = 5 // 商品利润曲线
-	CHART_SOURCE_LINE_EQUATION                   = 6 // 拟合方程图表
-	CHART_SOURCE_LINE_FEATURE_STANDARD_DEVIATION = 7 // 统计特征-标准差图表
-	CHART_SOURCE_LINE_FEATURE_PERCENTILE         = 8 // 统计特征-百分位图表
-	CHART_SOURCE_LINE_FEATURE_FREQUENCY          = 9 // 统计特征-频率分布图表
+	CHART_SOURCE_CORRELATION                     = 3  // 相关性图表
+	CHART_SOURCE_ROLLING_CORRELATION             = 4  // 滚动相关性图表
+	CHART_SOURCE_FUTURE_GOOD_PROFIT              = 5  // 商品利润曲线
+	CHART_SOURCE_LINE_EQUATION                   = 6  // 拟合方程图表
+	CHART_SOURCE_LINE_FEATURE_STANDARD_DEVIATION = 7  // 统计特征-标准差图表
+	CHART_SOURCE_LINE_FEATURE_PERCENTILE         = 8  // 统计特征-百分位图表
+	CHART_SOURCE_LINE_FEATURE_FREQUENCY          = 9  // 统计特征-频率分布图表
+	CHART_SOURCE_CROSS_HEDGING                   = 10 // 跨品种分析图表
 )
 
 // 图表类型