Browse Source

Merge remote-tracking branch 'origin/master'

zwxi 7 months ago
parent
commit
f036bcd049

+ 11 - 0
controllers/data_manage/correlation/correlation_chart_classify.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/data"
+	correlationServ "eta/eta_api/services/data/correlation"
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
 	"fmt"
@@ -544,6 +545,15 @@ func (this *CorrelationChartClassifyController) DeleteChartClassify() {
 				}
 			}
 		}
+
+		// 删除图表关联
+		e = correlationServ.RemoveCorrelationRelate(chartInfo.ChartInfoId)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = fmt.Sprintf("删除相关性图表关联失败, %v", e)
+			return
+		}
+
 		//新增操作日志
 		{
 			chartLog := new(data_manage.ChartInfoLog)
@@ -560,6 +570,7 @@ func (this *CorrelationChartClassifyController) DeleteChartClassify() {
 			go data_manage.AddChartInfoLog(chartLog)
 		}
 	}
+
 	br.Ret = 200
 	br.Msg = "删除成功"
 	br.Success = true

+ 106 - 32
controllers/data_manage/correlation/correlation_chart_info.go

@@ -1390,8 +1390,23 @@ func (this *CorrelationChartInfoController) Copy() {
 			originEdbSeriesMapping = list
 		}
 
+		seriesData := make([]*data_manage.FactorEdbSeriesCalculateData, 0)
+		{
+			dataOb := new(data_manage.FactorEdbSeriesCalculateData)
+			cond := fmt.Sprintf(" AND %s IN (%s)", dataOb.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+			pars := make([]interface{}, 0)
+			pars = append(pars, seriesIds)
+			list, e := dataOb.GetItemsByCondition(cond, pars, []string{}, "")
+			if e != nil {
+				br.Msg = "保存失败"
+				br.ErrMsg = fmt.Sprintf("获取系列计算数据失败, %v", e)
+				return
+			}
+			seriesData = list
+		}
+
 		// 新增图表/相关性图表/图表指标关联/指标系列图表关联
-		chartInfoId, seriesIdMap, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, originChartMappings, true, originSeries, originEdbSeriesMapping)
+		chartInfoId, seriesIdMap, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, originChartMappings, true, originSeries, originEdbSeriesMapping, seriesData)
 		if e != nil {
 			br.Msg = "保存失败"
 			br.ErrMsg = fmt.Sprintf("新增多因子相关性图表失败, Err: %v", e)
@@ -2354,25 +2369,43 @@ func (this *CorrelationChartInfoController) MultiFactorAdd() {
 		edbUsed[k] = true
 	}
 
-	// 指标系列-图表关联
-	chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
-	{
-		ob := new(data_manage.FactorEdbSeriesChartMapping)
-		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
-		pars := make([]interface{}, 0)
-		pars = append(pars, seriesIds)
-		items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
-		if e != nil {
-			br.Msg = "保存失败"
-			br.ErrMsg = fmt.Sprintf("获取指标系列图表关联失败, Err: %v", e)
-			return
-		}
-		chartMappings = items
+	// TODO:图表关联-生成相关性矩阵
+	var calculatePars data_manage.CalculateCorrelationMatrixPars
+	calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
+	calculatePars.SeriesIds = req.FactorCorrelation.SeriesIds
+	var correlationConf data_manage.CorrelationConfig
+	correlationConf.LeadUnit = req.FactorCorrelation.LeadUnit
+	correlationConf.LeadValue = req.FactorCorrelation.LeadValue
+	correlationConf.CalculateUnit = req.FactorCorrelation.CalculateUnit
+	correlationConf.CalculateValue = req.FactorCorrelation.CalculateValue
+	calculatePars.Correlation = correlationConf
+	_, chartMappings, e := correlationServ.CalculateCorrelationMatrix(calculatePars)
+	if e != nil {
+		br.Msg = "计算矩阵失败"
+		br.ErrMsg = fmt.Sprintf("计算相关性矩阵失败, %v", e)
+		return
 	}
+
+	// 指标系列-图表关联
+	//chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	//{
+	//	ob := new(data_manage.FactorEdbSeriesChartMapping)
+	//	cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+	//	pars := make([]interface{}, 0)
+	//	pars = append(pars, seriesIds)
+	//	items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
+	//	if e != nil {
+	//		br.Msg = "保存失败"
+	//		br.ErrMsg = fmt.Sprintf("获取指标系列图表关联失败, Err: %v", e)
+	//		return
+	//	}
+	//	chartMappings = items
+	//}
+
 	for _, v := range chartMappings {
 		v.Source = chartSource
 		k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
-		v.EdbUsed = 0 // 先重置一下
+		//v.EdbUsed = 0 // 先重置一下
 		if edbUsed[k] {
 			v.EdbUsed = 1
 		}
@@ -2382,6 +2415,7 @@ func (this *CorrelationChartInfoController) MultiFactorAdd() {
 	// 另存为
 	originSeries := make([]*data_manage.FactorEdbSeries, 0)
 	originEdbSeriesMapping := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	seriesData := make([]*data_manage.FactorEdbSeriesCalculateData, 0)
 	if req.SaveAs {
 		// 注意此处要复制一份系列及系列关联指标, 不可共用被复制图表的系列
 		{
@@ -2410,10 +2444,23 @@ func (this *CorrelationChartInfoController) MultiFactorAdd() {
 			}
 			originEdbSeriesMapping = list
 		}
+		{
+			dataOb := new(data_manage.FactorEdbSeriesCalculateData)
+			cond := fmt.Sprintf(" AND %s IN (%s)", dataOb.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+			pars := make([]interface{}, 0)
+			pars = append(pars, seriesIds)
+			list, e := dataOb.GetItemsByCondition(cond, pars, []string{}, "")
+			if e != nil {
+				br.Msg = "保存失败"
+				br.ErrMsg = fmt.Sprintf("获取系列计算数据失败, %v", e)
+				return
+			}
+			seriesData = list
+		}
 	}
 
 	// 新增图表/相关性图表/图表指标关联/指标系列图表关联
-	chartInfoId, seriesIdMap, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, chartMappings, req.SaveAs, originSeries, originEdbSeriesMapping)
+	chartInfoId, seriesIdMap, e := data_manage.CreateMultiFactorCorrelationChartAndEdb(chartInfo, edbMappings, chartCorrelate, chartMappings, req.SaveAs, originSeries, originEdbSeriesMapping, seriesData)
 	if e != nil {
 		br.Msg = "保存失败"
 		br.ErrMsg = fmt.Sprintf("新增多因子相关性图表失败, Err: %v", e)
@@ -2710,34 +2757,61 @@ func (this *CorrelationChartInfoController) MultiFactorEdit() {
 		edbMappings = append(edbMappings, m)
 	}
 
-	seriesIds := req.FactorCorrelation.SeriesIds
+	//seriesIds := req.FactorCorrelation.SeriesIds
 	edbUsed := make(map[string]bool)
 	for _, v := range req.FactorCorrelation.SeriesEdb {
 		k := fmt.Sprintf("%d-%d", v.SeriesId, v.EdbInfoId)
 		edbUsed[k] = true
 	}
-	// 指标系列-图表关联
-	chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
-	{
-		ob := new(data_manage.FactorEdbSeriesChartMapping)
-		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
-		pars := make([]interface{}, 0)
-		pars = append(pars, seriesIds)
-		items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
-		if e != nil {
-			br.Msg = "保存失败"
-			br.ErrMsg = fmt.Sprintf("获取指标系列图表关联失败, Err: %v", e)
-			return
-		}
-		chartMappings = items
+
+	var calculatePars data_manage.CalculateCorrelationMatrixPars
+	calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
+	calculatePars.SeriesIds = req.FactorCorrelation.SeriesIds
+	var correlationConf data_manage.CorrelationConfig
+	correlationConf.LeadUnit = req.FactorCorrelation.LeadUnit
+	correlationConf.LeadValue = req.FactorCorrelation.LeadValue
+	correlationConf.CalculateUnit = req.FactorCorrelation.CalculateUnit
+	correlationConf.CalculateValue = req.FactorCorrelation.CalculateValue
+	calculatePars.Correlation = correlationConf
+	_, chartMappings, e := correlationServ.CalculateCorrelationMatrix(calculatePars)
+	if e != nil {
+		br.Msg = "计算矩阵失败"
+		br.ErrMsg = fmt.Sprintf("计算相关性矩阵失败, %v", e)
+		return
 	}
+
+	// 指标系列-图表关联
+	//chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	//{
+	//	ob := new(data_manage.FactorEdbSeriesChartMapping)
+	//	cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+	//	pars := make([]interface{}, 0)
+	//	pars = append(pars, seriesIds)
+	//	items, e := ob.GetItemsByCondition(cond, pars, []string{}, "")
+	//	if e != nil {
+	//		br.Msg = "保存失败"
+	//		br.ErrMsg = fmt.Sprintf("获取指标系列图表关联失败, Err: %v", e)
+	//		return
+	//	}
+	//	chartMappings = items
+	//}
+	//existChartMappingIds := make([]int, 0) // 之前加的需要删除掉
+	//updateChartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
 	for _, v := range chartMappings {
+		//if v.ChartInfoId == req.ChartInfoId {
+		//	existChartMappingIds = append(existChartMappingIds, v.FactorEdbSeriesChartMappingId)
+		//	continue
+		//}
+
 		k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
 		v.EdbUsed = 0
 		if edbUsed[k] {
 			v.EdbUsed = 1
 		}
+		v.ChartInfoId = chartInfo.ChartInfoId
+		v.Source = chartSource
 		v.ModifyTime = time.Now().Local()
+		//updateChartMappings = append(updateChartMappings, v)
 	}
 
 	// 更新图表/相关性图表/图表指标关联/指标系列图表关联

+ 274 - 258
controllers/data_manage/factor_edb_series.go

@@ -10,10 +10,8 @@ import (
 	correlationServ "eta/eta_api/services/data/correlation"
 	"eta/eta_api/utils"
 	"fmt"
-	"sort"
 	"strconv"
 	"strings"
-	"sync"
 	"time"
 )
 
@@ -338,6 +336,7 @@ func (this *FactorEdbSeriesController) Edit() {
 		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
 		return
 	}
+	originCalculateState := seriesItem.CalculateState
 
 	edbArr, e := data_manage.GetEdbInfoByIdList(req.EdbInfoIds)
 	if e != nil {
@@ -379,6 +378,7 @@ func (this *FactorEdbSeriesController) Edit() {
 	}
 
 	// 更新系列信息和指标关联
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculateNone
 	if calculateLen > 0 {
 		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
 		seriesItem.CalculateStep = calculatesJson
@@ -406,15 +406,19 @@ func (this *FactorEdbSeriesController) Edit() {
 		br.ErrMsg = "计算因子指标失败, Err: " + e.Error()
 		return
 	}
+	if seriesItem.CalculateState == data_manage.FactorEdbSeriesCalculating {
+		seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
+	}
 
-	// 更新系列计算状态
-	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
-	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
-	seriesItem.ModifyTime = time.Now().Local()
-	if e = seriesItem.Update(cols); e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
-		return
+	// 若原状态不一致, 更新状态
+	if originCalculateState != seriesItem.CalculateState {
+		cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
+		seriesItem.ModifyTime = time.Now().Local()
+		if e = seriesItem.Update(cols); e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新因子指标系列计算状态失败, Err: " + e.Error()
+			return
+		}
 	}
 
 	br.Data = calculateResp
@@ -556,258 +560,270 @@ func (this *FactorEdbSeriesController) CorrelationMatrix() {
 		return
 	}
 
-	// 获取标的指标信息及数据
-	baseEdb, e := data_manage.GetEdbInfoById(req.BaseEdbInfoId)
-	if e != nil {
-		if e.Error() == utils.ErrNoRow() {
-			br.Msg = "标的指标不存在"
-			return
-		}
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取标的指标信息失败, Err: " + e.Error()
-		return
-	}
-	dataListA := make([]*data_manage.EdbDataList, 0)
-	{
-		// 标的指标数据日期区间
-		startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
-		endDate := time.Now().Format(utils.FormatDate)
-		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
-		startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate) // 不包含第一天
-		switch baseEdb.EdbInfoType {
-		case 0:
-			dataListA, e = data_manage.GetEdbDataList(baseEdb.Source, baseEdb.SubSource, baseEdb.EdbInfoId, startDate, endDate)
-		case 1:
-			_, dataListA, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdb.EdbInfoId, startDate, endDate, false)
-		default:
-			br.Msg = "获取失败"
-			br.ErrMsg = fmt.Sprintf("标的指标类型异常: %d", baseEdb.EdbInfoType)
-			return
-		}
-		if e != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取标的指标数据失败, Err:" + e.Error()
-			return
-		}
-	}
-
-	// 获取因子系列
-	seriesIdItem := make(map[int]*data_manage.FactorEdbSeries)
-	{
-		ob := new(data_manage.FactorEdbSeries)
-		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().PrimaryId, utils.GetOrmInReplace(len(req.SeriesIds)))
-		pars := make([]interface{}, 0)
-		pars = append(pars, req.SeriesIds)
-		items, e := ob.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", ob.Cols().PrimaryId))
-		if e != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
-			return
-		}
-		if len(items) != len(req.SeriesIds) {
-			br.Msg = "获取失败"
-			br.ErrMsg = "因子指标系列数量有误"
-			return
-		}
-		for _, v := range items {
-			seriesIdItem[v.FactorEdbSeriesId] = v
-		}
-	}
-
-	// 获取因子指标
-	edbMappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
-	edbInfoIds := make([]int, 0)
-	{
-		ob := new(data_manage.FactorEdbSeriesMapping)
-		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(req.SeriesIds)))
-		pars := make([]interface{}, 0)
-		pars = append(pars, req.SeriesIds)
-		order := fmt.Sprintf("%s ASC, %s ASC", ob.Cols().FactorEdbSeriesId, ob.Cols().EdbInfoId)
-		items, e := ob.GetItemsByCondition(cond, pars, []string{}, order)
-		if e != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取因子指标关联失败, Err: " + e.Error()
-			return
-		}
-		for _, v := range items {
-			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
-		}
-		edbMappings = items
-	}
-	edbIdItem := make(map[int]*data_manage.EdbInfo)
-	edbItems, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	// 矩阵计算
+	var calculatePars data_manage.CalculateCorrelationMatrixPars
+	calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
+	calculatePars.SeriesIds = req.SeriesIds
+	calculatePars.Correlation = req.Correlation
+	resp, _, e := correlationServ.CalculateCorrelationMatrix(calculatePars)
 	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取因子指标失败, Err: " + e.Error()
+		br.Msg = "计算失败"
+		br.ErrMsg = fmt.Sprintf("计算相关性矩阵失败, %v", e)
 		return
 	}
-	for _, v := range edbItems {
-		edbIdItem[v.EdbInfoId] = v
-	}
-
-	// 获取因子指标数据, 计算相关性
-	resp := new(data_manage.FactorEdbSeriesCorrelationMatrixResp)
-	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)
-
-	calculateWorkers := make(chan struct{}, 10)
-	wg := sync.WaitGroup{}
-	edbExists := make(map[string]bool)
-	chartKeyMap := make(map[string]*data_manage.FactorEdbSeriesChartMapping)
-	for _, v := range edbMappings {
-		existsKey := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
-		if edbExists[existsKey] {
-			continue
-		}
-		edbExists[existsKey] = true
-
-		edbItem := edbIdItem[v.EdbInfoId]
-		if edbItem == nil {
-			continue
-		}
-		seriesItem := seriesIdItem[v.FactorEdbSeriesId]
-		if seriesItem == nil {
-			continue
-		}
-
-		wg.Add(1)
-		go func(mapping *data_manage.FactorEdbSeriesMapping, edb *data_manage.EdbInfo, series *data_manage.FactorEdbSeries) {
-			defer func() {
-				wg.Done()
-				<-calculateWorkers
-			}()
-			calculateWorkers <- struct{}{}
-
-			var item data_manage.FactorEdbSeriesCorrelationMatrixItem
-			item.SeriesId = series.FactorEdbSeriesId
-			item.EdbInfoId = edb.EdbInfoId
-			item.EdbCode = edb.EdbCode
-			item.EdbName = edb.EdbName
-
-			// 指标来源
-			edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
-			edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
-				EdbInfoId:           edb.EdbInfoId,
-				EdbInfoCategoryType: edb.EdbInfoType,
-				EdbType:             edb.EdbType,
-				Source:              edb.Source,
-				SourceName:          edb.SourceName,
-			})
-			sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
-			item.SourceName = strings.Join(sourceNameList, ",")
-			item.SourceNameEn = strings.Join(sourceNameEnList, ",")
-
-			// 获取指标数据
-			dataListB := make([]*data_manage.EdbDataList, 0)
-			if series.CalculateState == data_manage.FactorEdbSeriesCalculated {
-				cond := fmt.Sprintf(" AND %s = ? AND %s = ?", calculateDataOb.Cols().FactorEdbSeriesId, calculateDataOb.Cols().EdbInfoId)
-				pars := make([]interface{}, 0)
-				pars = append(pars, mapping.FactorEdbSeriesId, mapping.EdbInfoId)
-				dataItems, e := calculateDataOb.GetItemsByCondition(cond, pars, []string{calculateDataOb.Cols().DataTime, calculateDataOb.Cols().Value}, fmt.Sprintf("%s ASC", calculateDataOb.Cols().DataTime))
-				if e != nil {
-					item.Msg = fmt.Sprintf("计算失败")
-					item.ErrMsg = fmt.Sprintf("获取计算数据失败, err: %v", e)
-					resp.Fail = append(resp.Fail, item)
-					return
-				}
-				dataListB = data_manage.TransEdbSeriesCalculateData2EdbDataList(dataItems)
-			} else {
-				switch edb.EdbInfoType {
-				case 0:
-					dataListB, e = data_manage.GetEdbDataList(edb.Source, edb.SubSource, edb.EdbInfoId, "", "")
-				case 1:
-					_, dataListB, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(edb.EdbInfoId, "", "", false)
-				default:
-					item.Msg = fmt.Sprintf("计算失败")
-					item.ErrMsg = fmt.Sprintf("指标类型异常, edbType: %d", edb.EdbInfoType)
-					resp.Fail = append(resp.Fail, item)
-					return
-				}
-			}
 
-			// 计算相关性
-			xEdbIdValue, yDataList, e := correlationServ.CalculateCorrelation(req.Correlation.LeadValue, req.Correlation.LeadUnit, baseEdb.Frequency, edb.Frequency, dataListA, dataListB)
-			if e != nil {
-				item.Msg = fmt.Sprintf("计算失败")
-				item.ErrMsg = fmt.Sprintf("相关性计算失败, err: %v", e)
-				resp.Fail = append(resp.Fail, item)
-				return
-			}
-
-			// X及Y轴数据
-			yData := yDataList[0].Value
-			yLen := len(yData)
-			values := make([]data_manage.FactorEdbSeriesCorrelationMatrixValues, len(xEdbIdValue))
-			for k, x := range xEdbIdValue {
-				var y float64
-				if k >= 0 && k < yLen {
-					y = yData[k]
-				}
-				y = utils.SubFloatToFloat(y, 2)
-				values[k] = data_manage.FactorEdbSeriesCorrelationMatrixValues{
-					XData: x, YData: y,
-				}
-			}
-
-			// 图表关联-此处添加的chart_info_id=0
-			newMapping := new(data_manage.FactorEdbSeriesChartMapping)
-			newMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeCorrelation
-
-			// 计算参数
-			var calculatePars data_manage.FactorEdbSeriesChartCalculateCorrelationReq
-			calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
-			calculatePars.LeadValue = req.Correlation.LeadValue
-			calculatePars.LeadUnit = req.Correlation.LeadUnit
-			calculatePars.CalculateValue = req.Correlation.CalculateValue
-			calculatePars.CalculateUnit = req.Correlation.CalculateUnit
-			bc, e := json.Marshal(calculatePars)
-			if e != nil {
-				item.Msg = fmt.Sprintf("计算失败")
-				item.ErrMsg = fmt.Sprintf("计算参数JSON格式化失败, err: %v", e)
-				resp.Fail = append(resp.Fail, item)
-				return
-			}
-			newMapping.CalculatePars = string(bc)
-
-			// 计算结果, 注此处保存的是排序前的顺序
-			bv, e := json.Marshal(values)
-			if e != nil {
-				item.Msg = fmt.Sprintf("计算失败")
-				item.ErrMsg = fmt.Sprintf("计算结果JSON格式化失败, err: %v", e)
-				resp.Fail = append(resp.Fail, item)
-				return
-			}
-			newMapping.CalculateData = string(bv)
-			newMapping.FactorEdbSeriesId = mapping.FactorEdbSeriesId
-			newMapping.EdbInfoId = mapping.EdbInfoId
-			newMapping.CreateTime = time.Now().Local()
-			newMapping.ModifyTime = time.Now().Local()
-			chartKeyMap[existsKey] = newMapping
-
-			// 按照固定规则排期数[0 1 2 3 -1 -2 -3], 仅矩阵展示为此顺序
-			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
-			item.Msg = "计算成功"
-			item.Values = values
-			resp.Success = append(resp.Success, item)
-		}(v, edbItem, seriesItem)
-	}
-	wg.Wait()
-
-	// 新增图表关联, 此处按照顺序添加
-	chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
-	for _, v := range edbMappings {
-		k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
-		item := chartKeyMap[k]
-		if item == nil {
-			continue
-		}
-		chartMappings = append(chartMappings, item)
-	}
-	chartMappingOb := new(data_manage.FactorEdbSeriesChartMapping)
-	if e = chartMappingOb.ClearAndCreateMapping(req.SeriesIds, chartMappings); e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = fmt.Sprintf("新增图表关联失败, Err: %v", e)
-		return
-	}
+	// 获取标的指标信息及数据
+	//baseEdb, e := data_manage.GetEdbInfoById(req.BaseEdbInfoId)
+	//if e != nil {
+	//	if e.Error() == utils.ErrNoRow() {
+	//		br.Msg = "标的指标不存在"
+	//		return
+	//	}
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取标的指标信息失败, Err: " + e.Error()
+	//	return
+	//}
+	//dataListA := make([]*data_manage.EdbDataList, 0)
+	//{
+	//	// 标的指标数据日期区间
+	//	startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
+	//	endDate := time.Now().Format(utils.FormatDate)
+	//	startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+	//	startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate) // 不包含第一天
+	//	switch baseEdb.EdbInfoType {
+	//	case 0:
+	//		dataListA, e = data_manage.GetEdbDataList(baseEdb.Source, baseEdb.SubSource, baseEdb.EdbInfoId, startDate, endDate)
+	//	case 1:
+	//		_, dataListA, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdb.EdbInfoId, startDate, endDate, false)
+	//	default:
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = fmt.Sprintf("标的指标类型异常: %d", baseEdb.EdbInfoType)
+	//		return
+	//	}
+	//	if e != nil {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取标的指标数据失败, Err:" + e.Error()
+	//		return
+	//	}
+	//}
+	//
+	//// 获取因子系列
+	//seriesIdItem := make(map[int]*data_manage.FactorEdbSeries)
+	//{
+	//	ob := new(data_manage.FactorEdbSeries)
+	//	cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().PrimaryId, utils.GetOrmInReplace(len(req.SeriesIds)))
+	//	pars := make([]interface{}, 0)
+	//	pars = append(pars, req.SeriesIds)
+	//	items, e := ob.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", ob.Cols().PrimaryId))
+	//	if e != nil {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取因子指标系列失败, Err: " + e.Error()
+	//		return
+	//	}
+	//	if len(items) != len(req.SeriesIds) {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "因子指标系列数量有误"
+	//		return
+	//	}
+	//	for _, v := range items {
+	//		seriesIdItem[v.FactorEdbSeriesId] = v
+	//	}
+	//}
+	//
+	//// 获取因子指标
+	//edbMappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	//edbInfoIds := make([]int, 0)
+	//{
+	//	ob := new(data_manage.FactorEdbSeriesMapping)
+	//	cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(req.SeriesIds)))
+	//	pars := make([]interface{}, 0)
+	//	pars = append(pars, req.SeriesIds)
+	//	order := fmt.Sprintf("%s ASC, %s ASC", ob.Cols().FactorEdbSeriesId, ob.Cols().EdbInfoId)
+	//	items, e := ob.GetItemsByCondition(cond, pars, []string{}, order)
+	//	if e != nil {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取因子指标关联失败, Err: " + e.Error()
+	//		return
+	//	}
+	//	for _, v := range items {
+	//		edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+	//	}
+	//	edbMappings = items
+	//}
+	//edbIdItem := make(map[int]*data_manage.EdbInfo)
+	//edbItems, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	//if e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取因子指标失败, Err: " + e.Error()
+	//	return
+	//}
+	//for _, v := range edbItems {
+	//	edbIdItem[v.EdbInfoId] = v
+	//}
+	//
+	//// 获取因子指标数据, 计算相关性
+	//resp := new(data_manage.FactorEdbSeriesCorrelationMatrixResp)
+	//calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)
+	//
+	//calculateWorkers := make(chan struct{}, 10)
+	//wg := sync.WaitGroup{}
+	//edbExists := make(map[string]bool)
+	//chartKeyMap := make(map[string]*data_manage.FactorEdbSeriesChartMapping)
+	//for _, v := range edbMappings {
+	//	existsKey := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
+	//	if edbExists[existsKey] {
+	//		continue
+	//	}
+	//	edbExists[existsKey] = true
+	//
+	//	edbItem := edbIdItem[v.EdbInfoId]
+	//	if edbItem == nil {
+	//		continue
+	//	}
+	//	seriesItem := seriesIdItem[v.FactorEdbSeriesId]
+	//	if seriesItem == nil {
+	//		continue
+	//	}
+	//
+	//	wg.Add(1)
+	//	go func(mapping *data_manage.FactorEdbSeriesMapping, edb *data_manage.EdbInfo, series *data_manage.FactorEdbSeries) {
+	//		defer func() {
+	//			wg.Done()
+	//			<-calculateWorkers
+	//		}()
+	//		calculateWorkers <- struct{}{}
+	//
+	//		var item data_manage.FactorEdbSeriesCorrelationMatrixItem
+	//		item.SeriesId = series.FactorEdbSeriesId
+	//		item.EdbInfoId = edb.EdbInfoId
+	//		item.EdbCode = edb.EdbCode
+	//		item.EdbName = edb.EdbName
+	//
+	//		// 指标来源
+	//		edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	//		edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
+	//			EdbInfoId:           edb.EdbInfoId,
+	//			EdbInfoCategoryType: edb.EdbInfoType,
+	//			EdbType:             edb.EdbType,
+	//			Source:              edb.Source,
+	//			SourceName:          edb.SourceName,
+	//		})
+	//		sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	//		item.SourceName = strings.Join(sourceNameList, ",")
+	//		item.SourceNameEn = strings.Join(sourceNameEnList, ",")
+	//
+	//		// 获取指标数据
+	//		dataListB := make([]*data_manage.EdbDataList, 0)
+	//		if series.CalculateState == data_manage.FactorEdbSeriesCalculated {
+	//			cond := fmt.Sprintf(" AND %s = ? AND %s = ?", calculateDataOb.Cols().FactorEdbSeriesId, calculateDataOb.Cols().EdbInfoId)
+	//			pars := make([]interface{}, 0)
+	//			pars = append(pars, mapping.FactorEdbSeriesId, mapping.EdbInfoId)
+	//			dataItems, e := calculateDataOb.GetItemsByCondition(cond, pars, []string{calculateDataOb.Cols().DataTime, calculateDataOb.Cols().Value}, fmt.Sprintf("%s ASC", calculateDataOb.Cols().DataTime))
+	//			if e != nil {
+	//				item.Msg = fmt.Sprintf("计算失败")
+	//				item.ErrMsg = fmt.Sprintf("获取计算数据失败, err: %v", e)
+	//				resp.Fail = append(resp.Fail, item)
+	//				return
+	//			}
+	//			dataListB = data_manage.TransEdbSeriesCalculateData2EdbDataList(dataItems)
+	//		} else {
+	//			switch edb.EdbInfoType {
+	//			case 0:
+	//				dataListB, e = data_manage.GetEdbDataList(edb.Source, edb.SubSource, edb.EdbInfoId, "", "")
+	//			case 1:
+	//				_, dataListB, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(edb.EdbInfoId, "", "", false)
+	//			default:
+	//				item.Msg = fmt.Sprintf("计算失败")
+	//				item.ErrMsg = fmt.Sprintf("指标类型异常, edbType: %d", edb.EdbInfoType)
+	//				resp.Fail = append(resp.Fail, item)
+	//				return
+	//			}
+	//		}
+	//
+	//		// 计算相关性
+	//		xEdbIdValue, yDataList, e := correlationServ.CalculateCorrelation(req.Correlation.LeadValue, req.Correlation.LeadUnit, baseEdb.Frequency, edb.Frequency, dataListA, dataListB)
+	//		if e != nil {
+	//			item.Msg = fmt.Sprintf("计算失败")
+	//			item.ErrMsg = fmt.Sprintf("相关性计算失败, err: %v", e)
+	//			resp.Fail = append(resp.Fail, item)
+	//			return
+	//		}
+	//
+	//		// X及Y轴数据
+	//		yData := yDataList[0].Value
+	//		yLen := len(yData)
+	//		values := make([]data_manage.FactorEdbSeriesCorrelationMatrixValues, len(xEdbIdValue))
+	//		for k, x := range xEdbIdValue {
+	//			var y float64
+	//			if k >= 0 && k < yLen {
+	//				y = yData[k]
+	//			}
+	//			y = utils.SubFloatToFloat(y, 2)
+	//			values[k] = data_manage.FactorEdbSeriesCorrelationMatrixValues{
+	//				XData: x, YData: y,
+	//			}
+	//		}
+	//
+	//		// 图表关联-此处添加的chart_info_id=0
+	//		newMapping := new(data_manage.FactorEdbSeriesChartMapping)
+	//		newMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeCorrelation
+	//
+	//		// 计算参数
+	//		var calculatePars data_manage.FactorEdbSeriesChartCalculateCorrelationReq
+	//		calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
+	//		calculatePars.LeadValue = req.Correlation.LeadValue
+	//		calculatePars.LeadUnit = req.Correlation.LeadUnit
+	//		calculatePars.CalculateValue = req.Correlation.CalculateValue
+	//		calculatePars.CalculateUnit = req.Correlation.CalculateUnit
+	//		bc, e := json.Marshal(calculatePars)
+	//		if e != nil {
+	//			item.Msg = fmt.Sprintf("计算失败")
+	//			item.ErrMsg = fmt.Sprintf("计算参数JSON格式化失败, err: %v", e)
+	//			resp.Fail = append(resp.Fail, item)
+	//			return
+	//		}
+	//		newMapping.CalculatePars = string(bc)
+	//
+	//		// 计算结果, 注此处保存的是排序前的顺序
+	//		bv, e := json.Marshal(values)
+	//		if e != nil {
+	//			item.Msg = fmt.Sprintf("计算失败")
+	//			item.ErrMsg = fmt.Sprintf("计算结果JSON格式化失败, err: %v", e)
+	//			resp.Fail = append(resp.Fail, item)
+	//			return
+	//		}
+	//		newMapping.CalculateData = string(bv)
+	//		newMapping.FactorEdbSeriesId = mapping.FactorEdbSeriesId
+	//		newMapping.EdbInfoId = mapping.EdbInfoId
+	//		newMapping.CreateTime = time.Now().Local()
+	//		newMapping.ModifyTime = time.Now().Local()
+	//		chartKeyMap[existsKey] = newMapping
+	//
+	//		// 按照固定规则排期数[0 1 2 3 -1 -2 -3], 仅矩阵展示为此顺序
+	//		sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
+	//		item.Msg = "计算成功"
+	//		item.Values = values
+	//		resp.Success = append(resp.Success, item)
+	//	}(v, edbItem, seriesItem)
+	//}
+	//wg.Wait()
+	//
+	//// 新增图表关联, 此处按照顺序添加
+	//chartMappings := make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	//for _, v := range edbMappings {
+	//	k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
+	//	item := chartKeyMap[k]
+	//	if item == nil {
+	//		continue
+	//	}
+	//	chartMappings = append(chartMappings, item)
+	//}
+	//chartMappingOb := new(data_manage.FactorEdbSeriesChartMapping)
+	//if e = chartMappingOb.ClearAndCreateMapping(req.SeriesIds, chartMappings); e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = fmt.Sprintf("新增图表关联失败, Err: %v", e)
+	//	return
+	//}
 
 	br.Data = resp
 	br.Ret = 200

+ 320 - 61
controllers/data_manage/future_good/future_good_chart_info.go

@@ -324,7 +324,7 @@ func (this *FutureGoodChartInfoController) ChartInfoAdd() {
 		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(this.Ctx.Input.RequestBody)
 		return
 	}
-	var req data_manage.AddChartInfoReq
+	var req data_manage.AddFutureGoodChartInfoReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"
@@ -510,7 +510,12 @@ func (this *FutureGoodChartInfoController) ChartInfoAdd() {
 		return
 	}
 	mapList := make([]*data_manage.ChartEdbMapping, 0)
+	hasAddMap := make(map[int]struct{})
 	for _, v := range barChartConfReq.EdbInfoIdList {
+		if _, ok := hasAddMap[v.EdbInfoId]; ok {
+			continue
+		}
+		hasAddMap[v.EdbInfoId] = struct{}{}
 		mapItem := new(data_manage.ChartEdbMapping)
 		mapItem.ChartInfoId = int(newId)
 		mapItem.EdbInfoId = v.EdbInfoId
@@ -609,7 +614,7 @@ func (this *FutureGoodChartInfoController) ChartInfoEdit() {
 		return
 	}
 
-	var req data_manage.EditChartInfoReq
+	var req data_manage.EditFutureGoodChartInfoReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"
@@ -1295,8 +1300,8 @@ func (this *FutureGoodChartInfoController) ChartInfoDetail() {
 func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dateType, startYear int, startDate, endDate string, sysUser *system.Admin, br *models.BaseResponse) {
 	chartInfoId := chartInfo.ChartInfoId
 
-	var edbInfoMapping, futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfoId)
+	var futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping
+	edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -1304,12 +1309,16 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 	}
 	futureGoodEdbInfoMapping, err = data_manage.GetFutureGoodEdbChartEdbMapping(chartInfoId)
 	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "期货指标不存在"
+			return
+		}
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
 
-	if edbInfoMapping == nil {
+	if len(edbInfoMappingList) == 0 {
 		br.Msg = "请选择ETA指标"
 		br.ErrMsg = "请选择ETA指标"
 		br.IsSendEmail = false
@@ -1323,16 +1332,18 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 	}
 
 	maxYear := 0
-	if edbInfoMapping.LatestDate != "" {
-		latestDateT, _ := time.Parse(utils.FormatDate, edbInfoMapping.LatestDate)
-		maxYear = latestDateT.Year()
+	for _, v := range edbInfoMappingList {
+		if v.LatestDate != "" {
+			latestDateT, _ := time.Parse(utils.FormatDate, v.LatestDate)
+			if maxYear < latestDateT.Year() {
+				maxYear = latestDateT.Year()
+			}
+		}
 	}
 	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
 
 	// 商品价格曲线图的一些配置
-	var barConfig data_manage.BarChartInfoReq
-	barChartInfoDateList := make([]data_manage.BarChartInfoDateReq, 0)
-
+	var barConfig data_manage.FutureGoodBarChartInfoReq
 	if chartInfo.BarConfig == `` {
 		br.Msg = "商品价格曲线图未配置"
 		br.ErrMsg = "商品价格曲线图未配置"
@@ -1345,10 +1356,24 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 		return
 	}
 
-	barChartInfoDateList = barConfig.DateList
+	baseEdbInfoId := barConfig.BaseEdbInfoId
+	var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+
+	if baseEdbInfoId == 0 {
+		// 默认取第一个现货指标
+		baseEdbInfoId = edbInfoMappingList[0].EdbInfoId
+		baseEdbInfoMapping = edbInfoMappingList[0]
+	} else {
+		baseEdbInfoMapping, err = data_manage.GetChartEdbMappingByEdbInfoId(baseEdbInfoId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	// 获取图表中的指标数据
-	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfoId, startDate, endDate, edbInfoMapping, futureGoodEdbInfoMapping, barChartInfoDateList, true)
+	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfoId, startDate, endDate, baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoMapping, barConfig, true)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -1416,7 +1441,7 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
 	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
 
-	resp := new(data_manage.ChartInfoDetailResp)
+	resp := new(data_manage.FutureGoodChartInfoDetailResp)
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList
 	resp.XEdbIdValue = xEdbIdValue
@@ -1498,8 +1523,8 @@ func (this *FutureGoodChartInfoController) ChartInfoDetailFromUniqueCode() {
 }
 
 // GetChartInfoDetailFromUniqueCode 根据编码获取图表详情
-func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
-	resp = new(data_manage.ChartInfoDetailFromUniqueCodeResp)
+func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.FutureChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	resp = new(data_manage.FutureChartInfoDetailFromUniqueCodeResp)
 
 	adminId := sysUser.AdminId
 	// 指标数据map
@@ -1633,7 +1658,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		}
 	}
 
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
 		errMsg = "获取图表,现货指标信息失败,Err:" + err.Error()
@@ -1647,8 +1672,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 	}
 
 	// 商品价格曲线图的一些配置
-	var barConfig data_manage.BarChartInfoReq
-	barChartInfoDateList := make([]data_manage.BarChartInfoDateReq, 0)
+	var barConfig data_manage.FutureGoodBarChartInfoReq
 
 	if chartInfo.BarConfig == `` {
 		msg = "商品价格曲线图未配置"
@@ -1662,10 +1686,25 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		return
 	}
 
-	barChartInfoDateList = barConfig.DateList
+	baseEdbInfoId := barConfig.BaseEdbInfoId
+	var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+
+	if baseEdbInfoId == 0 {
+		// 默认取第一个现货指标
+		baseEdbInfoId = edbInfoMappingList[0].EdbInfoId
+		baseEdbInfoMapping = edbInfoMappingList[0]
+		barConfig.BaseEdbInfoId = baseEdbInfoId
+	} else {
+		baseEdbInfoMapping, err = data_manage.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, true)
+	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()
@@ -1677,7 +1716,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		errMsg = "商品价格曲线图表异常"
 		return
 	}
-	baseEdbInfo := edbList[0] //现货指标
+	baseEdbInfo := baseEdbInfoMapping //现货指标
 
 	for _, v := range edbList {
 		if v.IsNullData {
@@ -2079,16 +2118,13 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 	switch chartInfo.Source {
 	case utils.CHART_SOURCE_FUTURE_GOOD, utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
 		// 现货指标
-		edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfo.ChartInfoId)
+		edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfo.ChartInfoId)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取图表,现货指标信息失败,Err:" + err.Error()
 			return
 		}
-		edbList := []*data_manage.ChartEdbInfoMapping{
-			edbInfoMapping,
-		}
-
+		edbList := edbInfoMappingList
 		// 期货指标
 		futureGoodEdbInfoMapping, err := data_manage.GetFutureGoodEdbChartEdbMapping(chartInfo.ChartInfoId)
 		if err != nil {
@@ -2099,8 +2135,7 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 		edbList = append(edbList, futureGoodEdbInfoMapping)
 
 		// 商品价格曲线图的一些配置
-		var barConfig data_manage.BarChartInfoReq
-		barChartInfoDateList := make([]data_manage.BarChartInfoDateReq, 0)
+		var barConfig data_manage.FutureGoodBarChartInfoReq
 
 		if chartInfo.BarConfig == `` {
 			br.Msg = "商品价格曲线图未配置"
@@ -2114,8 +2149,6 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			return
 		}
 
-		barChartInfoDateList = barConfig.DateList
-
 		startDate := chartInfo.StartDate
 		endDate := chartInfo.EndDate
 
@@ -2129,8 +2162,23 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			}
 		}
 
+		baseEdbInfoId := barConfig.BaseEdbInfoId
+		var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+		if baseEdbInfoId == 0 {
+			// 默认取第一个现货指标
+			baseEdbInfoId = edbInfoMappingList[0].EdbInfoId
+			baseEdbInfoMapping = edbInfoMappingList[0]
+		} else {
+			baseEdbInfoMapping, err = data_manage.GetChartEdbMappingByEdbInfoId(baseEdbInfoId)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+				return
+			}
+		}
+
 		// 获取图表中的指标数据
-		barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfo.ChartInfoId, startDate, endDate, edbInfoMapping, futureGoodEdbInfoMapping, barChartInfoDateList, false)
+		barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(chartInfo.ChartInfoId, startDate, endDate, baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoMapping, barConfig, false)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -2142,7 +2190,7 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			br.ErrMsg = "商品价格曲线图表异常"
 			return
 		}
-		baseEdbInfo := edbList[0] //现货指标
+		baseEdbInfo := baseEdbInfoMapping //现货指标
 
 		for _, v := range edbList {
 			if v.IsNullData {
@@ -2188,10 +2236,12 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 		chartInfo.Button.IsEdit = chartInfo.IsEdit
 		chartInfo.Button.IsCopy = true
 		//判断是否需要展示英文标识
-		chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
+		edbListTmp := make([]*data_manage.ChartEdbInfoMapping, 0)
+		edbListTmp = append(edbListTmp, baseEdbInfo)
+		chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbListTmp, chartInfo.Source, chartInfo.ChartType)
 		chartInfo.UnitEn = baseEdbInfo.UnitEn
 
-		resp := data_manage.ChartInfoDetailFromUniqueCodeResp{}
+		resp := data_manage.FutureChartInfoDetailFromUniqueCodeResp{}
 		resp.ChartInfo = chartInfo
 		resp.EdbInfoList = edbList
 		resp.XEdbIdValue = xEdbIdValue
@@ -2901,7 +2951,7 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 		this.ServeJSON()
 	}()
 
-	var req data_manage.BarChartInfoReq
+	var req data_manage.FutureGoodBarChartInfoReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"
@@ -2925,21 +2975,43 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 		br.Msg = "请选择日期"
 		return
 	}
+	if req.BaseEdbInfoId == 0 {
+		br.Msg = "请选择日期基准指标"
+		return
+	}
 	chartInfo := new(data_manage.ChartInfoView)
 
-	if len(req.EdbInfoIdList) != 2 {
-		br.Msg = "指标数量异常"
+	var futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping
+	edbInfoMappingList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	edbIds := make([]int, 0)
+	goodEdbIds := make([]int, 0)
+	for _, v := range req.EdbInfoIdList {
+		if v.Source == utils.CHART_SOURCE_DEFAULT {
+			edbIds = append(edbIds, v.EdbInfoId)
+		} else if v.Source == utils.CHART_SOURCE_FUTURE_GOOD {
+			goodEdbIds = append(goodEdbIds, v.EdbInfoId)
+		}
+	}
+	edbInfoMappingListTmp, err := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbIds)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
-	var edbInfoMapping, futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping
+	edbInfoMappingListMap := make(map[int]*data_manage.ChartEdbInfoMapping)
+	for _, v := range edbInfoMappingListTmp {
+		edbInfoMappingListMap[v.EdbInfoId] = v
+	}
+
 	for _, v := range req.EdbInfoIdList {
 		if v.Source == utils.CHART_SOURCE_DEFAULT {
-			edbInfoMapping, err = data_manage.GetChartEdbMappingByEdbInfoId(v.EdbInfoId)
-			if err != nil {
+			edbInfoMapping, ok := edbInfoMappingListMap[v.EdbInfoId]
+			if !ok {
 				br.Msg = "获取失败"
-				br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+				br.ErrMsg = "获取图表,指标信息失败 "
 				return
 			}
+			edbInfoMappingList = append(edbInfoMappingList, edbInfoMapping)
 		} else if v.Source == utils.CHART_SOURCE_FUTURE_GOOD {
 			futureGoodEdbInfoMapping, err = data_manage.GetChartEdbMappingByFutureGoodEdbInfoId(v.EdbInfoId)
 			if err != nil {
@@ -2955,7 +3027,7 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 		}
 	}
 
-	if edbInfoMapping == nil {
+	if len(edbInfoMappingList) == 0 {
 		br.Msg = "请选择ETA指标"
 		br.ErrMsg = "请选择ETA指标"
 		br.IsSendEmail = false
@@ -2968,8 +3040,17 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 		return
 	}
 
+	baseEdbInfoId := req.BaseEdbInfoId
+
+	baseEdbInfoMapping, err := data_manage.GetChartEdbMappingByEdbInfoId(baseEdbInfoId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+
 	// 获取图表中的指标数据
-	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(0, "", "", edbInfoMapping, futureGoodEdbInfoMapping, req.DateList, true)
+	barConfigEdbInfoIdList, edbList, xEdbIdValue, xDataList, yDataList, err := future_goodServ.GetChartEdbData(0, "", "", baseEdbInfoMapping, edbInfoMappingList, futureGoodEdbInfoMapping, req, true)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -2998,7 +3079,7 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 	//判断是否需要展示英文标识
 	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList, chartInfo.Source, chartInfo.ChartType)
 
-	resp := new(data_manage.ChartInfoDetailResp)
+	resp := new(data_manage.FutureGoodChartInfoDetailResp)
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList
 	resp.XEdbIdValue = xEdbIdValue
@@ -3031,7 +3112,7 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 		return
 	}
 
-	var req request.EditChartInfoBaseReq
+	var req data_manage.EditFutureGoodChartInfoBaseReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"
@@ -3071,19 +3152,22 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 	//	return
 	//}
 
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartItem.ChartInfoId)
+	edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(req.ChartInfoId)
 	if err != nil {
-		br.Msg = "修改失败"
-		br.ErrMsg = "获取图表现货价格指标信息失败,指标信息失败,Err:" + err.Error()
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
-
+	edbIds := make([]int, 0)
+	for _, edbInfoMapping := range edbInfoMappingList {
+		edbIds = append(edbIds, edbInfoMapping.EdbInfoId)
+	}
 	//校验指标信息是否存在
-	edbInfo, err := data_manage.GetEdbInfoById(edbInfoMapping.EdbInfoId)
+	edbInfoList, err := data_manage.GetEdbInfoByIdList(edbIds)
 	if err != nil {
 		if err.Error() == utils.ErrNoRow() {
 			br.Msg = "图表不存在!"
-			br.ErrMsg = "图表指标不存在,ChartInfoId:" + strconv.Itoa(edbInfoMapping.EdbInfoId)
+			br.ErrMsg = "图表指标不存在,ChartInfoId:" + strconv.Itoa(req.ChartInfoId)
 			return
 		} else {
 			br.Msg = "获取图表信息失败!"
@@ -3091,10 +3175,53 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			return
 		}
 	}
-	if edbInfo == nil {
-		br.Msg = "指标不存在!"
-		br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(edbInfoMapping.EdbInfoId)
-		return
+	edbInfoListMap := make(map[int]*data_manage.EdbInfo)
+	for _, v := range edbInfoList {
+		edbInfoListMap[v.EdbInfoId] = v
+	}
+	var edbCondition string
+	var edbPars []interface{}
+	for _, v := range req.ChartEdbInfoList {
+		_, ok := edbInfoListMap[v.EdbInfoId]
+		if !ok {
+			br.Msg = "指标不存在!"
+			br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(v.EdbInfoId)
+			return
+		}
+		//校验指标名称是否已存在
+		//判断指标名称是否重复
+		if v.EdbName != "" {
+			edbCondition = ""
+			edbPars = make([]interface{}, 0)
+
+			edbCondition += " AND edb_info_id<>? "
+			edbPars = append(edbPars, v.EdbInfoId)
+
+			switch this.Lang {
+			case utils.EnLangVersion:
+				edbCondition += " AND edb_name_en =? "
+			default:
+				edbCondition += " AND edb_name =? "
+			}
+
+			edbPars = append(edbPars, v.EdbName)
+
+			edbExist, e := data_manage.GetEdbInfoByCondition(edbCondition, edbPars)
+			if e != nil {
+				if e.Error() != utils.ErrNoRow() {
+					br.Msg = "判断英文指标名称是否存在失败"
+					br.ErrMsg = "判断英文指标名称是否存在失败,Err:" + e.Error()
+					return
+				}
+			}
+
+			if e == nil && edbExist.EdbInfoId > 0 {
+				br.Msg = edbExist.EdbName + ":" + v.EdbName + "指标名称已存在"
+				br.ErrMsg = "指标名称已存在,请重新填写"
+				br.IsSendEmail = false
+				return
+			}
+		}
 	}
 
 	if req.ChartName != "" {
@@ -3128,7 +3255,59 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 
 	switch chartItem.Source {
 	case utils.CHART_SOURCE_FUTURE_GOOD:
-		err = data_manage.EditBaseFutureGoodChartInfoAndEdbEnInfo(chartItem, req.ChartName, edbInfo.EdbInfoId, req.EdbName, req.Unit, this.Lang)
+		if len(req.XDataList) > 0 {
+			// 处理横轴名称
+			// 商品价格曲线图的一些配置
+			var barConfig data_manage.FutureGoodBarChartInfoReq
+			if chartItem.BarConfig == `` {
+				br.Msg = "商品价格曲线图未配置"
+				br.ErrMsg = "商品价格曲线图未配置"
+				return
+			}
+			err = json.Unmarshal([]byte(chartItem.BarConfig), &barConfig)
+			if err != nil {
+				br.Msg = "商品价格曲线图配置异常"
+				br.ErrMsg = "商品价格曲线图配置异常"
+				return
+			}
+			xDataList := barConfig.XDataList
+			length := len(xDataList)
+			switch this.Lang {
+			case utils.EnLangVersion:
+				for k, v := range req.XDataList {
+					v = strings.TrimPrefix(v, " ")
+					if v != `` {
+						if length-1 >= k {
+							xDataList[k].NameEn = v
+						} else {
+							tmp := data_manage.XData{Name: v, NameEn: v}
+							xDataList = append(xDataList, tmp)
+						}
+					}
+				}
+			default:
+				for k, v := range req.XDataList {
+					v = strings.TrimPrefix(v, " ")
+					if v != `` {
+						if length-1 >= k {
+							xDataList[k].Name = v
+						} else {
+							tmp := data_manage.XData{Name: v, NameEn: v}
+							xDataList = append(xDataList, tmp)
+						}
+					}
+				}
+			}
+			barConfig.XDataList = xDataList
+			barConfigByte, e := json.Marshal(barConfig)
+			if e != nil {
+				br.Msg = "商品价格曲线图配置异常"
+				br.ErrMsg = "商品价格曲线图配置异常 Err:" + e.Error()
+				return
+			}
+			chartItem.BarConfig = string(barConfigByte)
+		}
+		err = data_manage.EditBaseFutureGoodChartInfoAndEdbEnInfo(chartItem, &req, this.Lang)
 		if req.FutureGoodName != `` {
 			futureGoodEdbInfoMapping, err := data_manage.GetFutureGoodEdbChartEdbMapping(chartItem.ChartInfoId)
 			if err != nil {
@@ -3140,7 +3319,7 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			if err != nil {
 				if err.Error() == utils.ErrNoRow() {
 					br.Msg = "图表不存在!"
-					br.ErrMsg = "图表指标不存在,ChartInfoId:" + strconv.Itoa(edbInfoMapping.EdbInfoId)
+					br.ErrMsg = "图表指标不存在,futureGoodEdbInfo:" + strconv.Itoa(futureGoodEdbInfo.FutureGoodEdbInfoId)
 					return
 				} else {
 					br.Msg = "获取图表信息失败!"
@@ -3150,7 +3329,7 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			}
 			if futureGoodEdbInfo == nil {
 				br.Msg = "期货商品指标不存在!"
-				br.ErrMsg = "期货商品指标不存在,ChartInfoId:" + strconv.Itoa(edbInfoMapping.EdbInfoId)
+				br.ErrMsg = "期货商品指标不存在,futureGoodEdbInfo:" + strconv.Itoa(futureGoodEdbInfo.FutureGoodEdbInfoId)
 				return
 			}
 
@@ -3179,7 +3358,85 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			}
 		}
 	case utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
-		err = data_manage.EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartItem, req.ChartName, edbInfo.EdbInfoId, req.EdbName, req.Unit, req.ProfitName, this.Lang)
+		if len(req.XDataList) > 0 {
+			// 处理横轴名称
+			// 商品价格曲线图的一些配置
+			var barConfig request.ChartInfoReq
+			if chartItem.ExtraConfig == `` {
+				br.Msg = "商品价格曲线图未配置"
+				br.ErrMsg = "商品价格曲线图未配置"
+				return
+			}
+			err = json.Unmarshal([]byte(chartItem.ExtraConfig), &barConfig)
+			if err != nil {
+				br.Msg = "商品价格曲线图配置异常"
+				br.ErrMsg = "商品价格曲线图配置异常"
+				return
+			}
+			xDataList := barConfig.XDataList
+			length := len(xDataList)
+			switch this.Lang {
+			case utils.EnLangVersion:
+				for k, v := range req.XDataList {
+					v = strings.TrimPrefix(v, " ")
+					if v != `` {
+						if length-1 >= k {
+							xDataList[k].NameEn = v
+						} else {
+							tmp := data_manage.XData{Name: v, NameEn: v}
+							xDataList = append(xDataList, tmp)
+						}
+					}
+				}
+			default:
+				for k, v := range req.XDataList {
+					v = strings.TrimPrefix(v, " ")
+					if v != `` {
+						if length-1 >= k {
+							xDataList[k].Name = v
+						} else {
+							tmp := data_manage.XData{Name: v, NameEn: v}
+							xDataList = append(xDataList, tmp)
+						}
+					}
+				}
+			}
+			barConfig.XDataList = xDataList
+			barConfigByte, e := json.Marshal(barConfig)
+			if e != nil {
+				br.Msg = "商品价格曲线图配置异常"
+				br.ErrMsg = "商品价格曲线图配置异常 Err:" + e.Error()
+				return
+			}
+			chartItem.ExtraConfig = string(barConfigByte)
+
+			xDataByte, e := json.Marshal(xDataList)
+			if e != nil {
+				br.Msg = "商品价格曲线图配置异常"
+				br.ErrMsg = "商品价格曲线图配置异常 Err:" + e.Error()
+				return
+			}
+			//同步修改利润表扩展表
+			chartInfoFutureGoodProfit := new(future_good.ChartInfoFutureGoodProfit)
+			if e = chartInfoFutureGoodProfit.GetItemById(chartItem.ChartInfoId); e != nil {
+				br.Msg = "商品利润曲线图不存在"
+				br.ErrMsg = "商品利润曲线图查询出错 Err:" + e.Error()
+				return
+			}
+			chartInfoFutureGoodProfit.XValue = string(xDataByte)
+			// 更改扩展图表信息
+			// 查找商品利润图表的扩展信息
+			chartInfoFutureGoodProfit.ModifyTime = time.Now()
+			updateStr := []string{"ModifyTime", "XValue"}
+			err = chartInfoFutureGoodProfit.Update(updateStr)
+			if err != nil {
+				br.Msg = "商品利润曲线图更新失败"
+				br.ErrMsg = "商品利润曲线图更新失败 Err:" + e.Error()
+				return
+			}
+
+		}
+		err = data_manage.EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartItem, &req, this.Lang)
 	default:
 		br.Msg = "错误的图表类型"
 		br.ErrMsg = "错误的图表类型"
@@ -3198,7 +3455,9 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 	go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
 
 	//指标 修改es信息
-	go data.AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+	for _, v := range edbIds {
+		go data.AddOrEditEdbInfoToEs(v)
+	}
 
 	//新增操作日志
 	{

+ 163 - 105
controllers/data_manage/future_good/future_good_profit_chart_info.go

@@ -99,6 +99,11 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoAdd() {
 		br.IsSendEmail = false
 		return
 	}
+	if len(extraReq.EdbInfoIdList) == 0 {
+		br.Msg = "请选择ETA指标"
+		br.IsSendEmail = false
+		return
+	}
 	if len(extraReq.FutureGoodEdbInfoIdList) <= 0 {
 		br.Msg = "请选择期货商品指标"
 		br.IsSendEmail = false
@@ -113,34 +118,41 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoAdd() {
 	extraConf := string(extraConfByte)
 
 	var edbInfoIdArr []int
+	baseEdbInfo := new(data_manage.EdbInfo)
 	// ETA指标
-	edbInfo, err := data_manage.GetEdbInfoById(extraReq.BaseEdbInfoId)
+	edbInfoListTmp, err := data_manage.GetEdbInfoByIdList(extraReq.EdbInfoIdList)
 	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "指标不存在!"
-			br.ErrMsg = "指标不存在,edbInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
-			return
-		} else {
-			br.Msg = "获取指标信息失败!"
-			br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
-			return
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
+		return
+	}
+	//按照请求顺序排序
+	edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	for _, v := range edbInfoListTmp {
+		edbInfoMap[v.EdbInfoId] = v
+	}
+	edbInfoList := make([]*data_manage.EdbInfo, 0)
+	for _, v := range extraReq.EdbInfoIdList {
+		edbInfoList = append(edbInfoList, edbInfoMap[v])
+	}
+
+	edbInfoListMap := make(map[int]*data_manage.EdbInfo)
+	for k, v := range edbInfoList {
+		edbInfoList[k].EdbNameSource = v.EdbName
+		edbInfoListMap[v.EdbInfoId] = v
+		edbInfoIdArr = append(edbInfoIdArr, v.EdbInfoId)
+		if v.EdbInfoId == extraReq.BaseEdbInfoId {
+			baseEdbInfo = v
 		}
 	}
-	if edbInfo == nil {
-		br.Msg = "指标已被删除,请重新选择!"
-		br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
-		return
-	} else {
-		if edbInfo.EdbInfoId <= 0 {
+	for _, v := range extraReq.EdbInfoIdList {
+		if _, ok := edbInfoListMap[v]; !ok {
 			br.Msg = "指标已被删除,请重新选择!"
-			br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
+			br.ErrMsg = "指标不存在,edbInfoId:" + strconv.Itoa(v)
 			return
 		}
 	}
 
-	edbInfoIdArr = append(edbInfoIdArr, extraReq.BaseEdbInfoId)
-	edbInfo.EdbNameSource = edbInfo.EdbName
-
 	// 期货商品指标(主力合约)
 	futureGoodEdbInfoMap := make(map[int]*future_good.FutureGoodEdbInfo)
 	zlFutureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
@@ -234,25 +246,27 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoAdd() {
 	// 关联指标
 	mapList := make([]*data_manage.ChartEdbMapping, 0)
 	{
-		mapList = append(mapList, &data_manage.ChartEdbMapping{
-			ChartEdbMappingId: 0,
-			EdbInfoId:         extraReq.BaseEdbInfoId,
-			CreateTime:        time.Now(),
-			ModifyTime:        time.Now(),
-			UniqueCode:        utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + strconv.Itoa(extraReq.BaseEdbInfoId)),
-			//MaxData:           0,
-			//MinData:           0,
-			IsOrder:     true,
-			IsAxis:      1,
-			EdbInfoType: 1,
-			//LeadValue:         0,
-			//LeadUnit:          "",
-			//ChartStyle:        "",
-			//ChartColor:        "",
-			//PredictChartColor: "",
-			//ChartWidth:        0,
-			Source: 1,
-		})
+		for _, v := range edbInfoList {
+			mapList = append(mapList, &data_manage.ChartEdbMapping{
+				ChartEdbMappingId: 0,
+				EdbInfoId:         v.EdbInfoId,
+				CreateTime:        time.Now(),
+				ModifyTime:        time.Now(),
+				UniqueCode:        utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + strconv.Itoa(v.EdbInfoId)),
+				//MaxData:           0,
+				//MinData:           0,
+				IsOrder:     true,
+				IsAxis:      1,
+				EdbInfoType: 1,
+				//LeadValue:         0,
+				//LeadUnit:          "",
+				//ChartStyle:        "",
+				//ChartColor:        "",
+				//PredictChartColor: "",
+				//ChartWidth:        0,
+				Source: 1,
+			})
+		}
 
 		for _, v := range futureGoodEdbInfoMap {
 			mapList = append(mapList, &data_manage.ChartEdbMapping{
@@ -278,7 +292,7 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoAdd() {
 	}
 
 	// 获取图表中的指标数据
-	_, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(edbInfo, zlFutureGoodEdbInfoList, extraReq.DateList, extraReq.CalculateFormula, extraReq.FutureGoodEdbInfoIdList)
+	_, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(baseEdbInfo, edbInfoList, zlFutureGoodEdbInfoList, extraReq.DateList, extraReq.CalculateFormula, extraReq.FutureGoodEdbInfoIdList, extraReq.XDataList)
 	if err != nil {
 		br.Msg = "保存失败"
 		br.ErrMsg = "保存商品利润失败,指标信息失败,Err:" + err.Error()
@@ -447,6 +461,9 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoEdit() {
 		br.IsSendEmail = false
 		return
 	}
+	if len(extraReq.EdbInfoIdList) == 0 {
+		extraReq.EdbInfoIdList = append(extraReq.EdbInfoIdList, extraReq.BaseEdbInfoId)
+	}
 	extraConfByte, err := json.Marshal(extraReq)
 	if err != nil {
 		br.Msg = "商品利润曲线图信息异常"
@@ -456,34 +473,41 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoEdit() {
 	extraConf := string(extraConfByte)
 
 	var edbInfoIdArr []int
+	baseEdbInfo := new(data_manage.EdbInfo)
 	// ETA指标
-	edbInfo, err := data_manage.GetEdbInfoById(extraReq.BaseEdbInfoId)
+	edbInfoListTmp, err := data_manage.GetEdbInfoByIdList(extraReq.EdbInfoIdList)
 	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "指标不存在!"
-			br.ErrMsg = "指标不存在,edbInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
-			return
-		} else {
-			br.Msg = "获取指标信息失败!"
-			br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
-			return
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
+		return
+	}
+	//按照请求顺序排序
+	edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	for _, v := range edbInfoListTmp {
+		edbInfoMap[v.EdbInfoId] = v
+	}
+	edbInfoList := make([]*data_manage.EdbInfo, 0)
+	for _, v := range extraReq.EdbInfoIdList {
+		edbInfoList = append(edbInfoList, edbInfoMap[v])
+	}
+	edbInfoListMap := make(map[int]*data_manage.EdbInfo)
+	for k, v := range edbInfoList {
+		edbInfoList[k].EdbNameSource = v.EdbName
+		edbInfoListMap[v.EdbInfoId] = v
+		edbInfoIdArr = append(edbInfoIdArr, v.EdbInfoId)
+		if v.EdbInfoId == extraReq.BaseEdbInfoId {
+			baseEdbInfo = v
 		}
 	}
-	if edbInfo == nil {
-		br.Msg = "指标已被删除,请重新选择!"
-		br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
-		return
-	} else {
-		if edbInfo.EdbInfoId <= 0 {
+
+	for _, v := range extraReq.EdbInfoIdList {
+		if _, ok := edbInfoListMap[v]; !ok {
 			br.Msg = "指标已被删除,请重新选择!"
-			br.ErrMsg = "指标不存在,ChartInfoId:" + strconv.Itoa(extraReq.BaseEdbInfoId)
+			br.ErrMsg = "指标不存在,edbInfoId:" + strconv.Itoa(v)
 			return
 		}
 	}
 
-	edbInfoIdArr = append(edbInfoIdArr, extraReq.BaseEdbInfoId)
-	edbInfo.EdbNameSource = edbInfo.EdbName
-
 	// 期货商品指标(主力合约)
 	futureGoodEdbInfoMap := make(map[int]*future_good.FutureGoodEdbInfo)
 	zlFutureGoodEdbInfoList := make([]*future_good.FutureGoodEdbInfo, 0)
@@ -551,26 +575,27 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoEdit() {
 	// 关联指标
 	mapList := make([]*data_manage.ChartEdbMapping, 0)
 	{
-		mapList = append(mapList, &data_manage.ChartEdbMapping{
-			ChartEdbMappingId: 0,
-			EdbInfoId:         extraReq.BaseEdbInfoId,
-			CreateTime:        time.Now(),
-			ModifyTime:        time.Now(),
-			UniqueCode:        utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + strconv.Itoa(extraReq.BaseEdbInfoId)),
-			//MaxData:           0,
-			//MinData:           0,
-			IsOrder:     true,
-			IsAxis:      1,
-			EdbInfoType: 1,
-			//LeadValue:         0,
-			//LeadUnit:          "",
-			//ChartStyle:        "",
-			//ChartColor:        "",
-			//PredictChartColor: "",
-			//ChartWidth:        0,
-			Source: 1,
-		})
-
+		for _, v := range edbInfoList {
+			mapList = append(mapList, &data_manage.ChartEdbMapping{
+				ChartEdbMappingId: 0,
+				EdbInfoId:         v.EdbInfoId,
+				CreateTime:        time.Now(),
+				ModifyTime:        time.Now(),
+				UniqueCode:        utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + strconv.Itoa(v.EdbInfoId)),
+				//MaxData:           0,
+				//MinData:           0,
+				IsOrder:     true,
+				IsAxis:      1,
+				EdbInfoType: 1,
+				//LeadValue:         0,
+				//LeadUnit:          "",
+				//ChartStyle:        "",
+				//ChartColor:        "",
+				//PredictChartColor: "",
+				//ChartWidth:        0,
+				Source: 1,
+			})
+		}
 		for _, v := range futureGoodEdbInfoMap {
 			mapList = append(mapList, &data_manage.ChartEdbMapping{
 				ChartEdbMappingId: 0,
@@ -595,7 +620,7 @@ func (this *FutureGoodChartInfoController) ProfitChartInfoEdit() {
 	}
 
 	// 获取图表中的指标数据
-	_, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(edbInfo, zlFutureGoodEdbInfoList, extraReq.DateList, extraReq.CalculateFormula, extraReq.FutureGoodEdbInfoIdList)
+	_, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(baseEdbInfo, edbInfoList, zlFutureGoodEdbInfoList, extraReq.DateList, extraReq.CalculateFormula, extraReq.FutureGoodEdbInfoIdList, extraReq.XDataList)
 	if err != nil {
 		br.Msg = "保存失败"
 		br.ErrMsg = "保存商品利润失败,指标信息失败,Err:" + err.Error()
@@ -923,9 +948,29 @@ func (this *FutureGoodChartInfoController) PreviewProfitChartInfo() {
 		br.IsSendEmail = false
 		return
 	}
-
+	if len(req.EdbInfoIdList) == 0 {
+		br.Msg = "请选择ETA指标"
+		br.ErrMsg = "请选择ETA指标"
+		br.IsSendEmail = false
+		return
+	}
+	//查询基本指标信息
+	edbInfoListTmp, err := data_manage.GetEdbInfoByIdList(req.EdbInfoIdList)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	edbInfoMap := make(map[int]*data_manage.EdbInfo)
+	for _, v := range edbInfoListTmp {
+		edbInfoMap[v.EdbInfoId] = v
+	}
+	edbInfoList := make([]*data_manage.EdbInfo, 0)
+	for _, v := range req.EdbInfoIdList {
+		edbInfoList = append(edbInfoList, edbInfoMap[v])
+	}
 	// 获取图表中的指标数据
-	barConfigEdbInfoIdList, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(baseEdbInfo, zlFutureGoodEdbInfoList, req.DateList, req.CalculateFormula, req.FutureGoodEdbInfoIdList)
+	barConfigEdbInfoIdList, _, _, xDataList, yDataList, err := future_goodServ.GetProfitChartEdbData(baseEdbInfo, edbInfoList, zlFutureGoodEdbInfoList, req.DateList, req.CalculateFormula, req.FutureGoodEdbInfoIdList, req.XDataList)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
@@ -933,25 +978,27 @@ func (this *FutureGoodChartInfoController) PreviewProfitChartInfo() {
 	}
 
 	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
-	edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
-		EdbInfoId:      baseEdbInfo.EdbInfoId,
-		SourceName:     baseEdbInfo.SourceName,
-		Source:         baseEdbInfo.Source,
-		EdbCode:        baseEdbInfo.EdbCode,
-		EdbName:        baseEdbInfo.EdbName,
-		EdbAliasName:   baseEdbInfo.EdbName,
-		EdbNameEn:      baseEdbInfo.EdbNameEn,
-		EdbAliasNameEn: baseEdbInfo.EdbNameEn,
-		EdbType:        baseEdbInfo.EdbType,
-		Frequency:      baseEdbInfo.Frequency,
-		FrequencyEn:    data.GetFrequencyEn(baseEdbInfo.Frequency),
-		Unit:           baseEdbInfo.Unit,
-		UnitEn:         baseEdbInfo.UnitEn,
-		StartDate:      baseEdbInfo.StartDate,
-		EndDate:        baseEdbInfo.EndDate,
-		ModifyTime:     baseEdbInfo.ModifyTime.Format(utils.FormatDateTime),
-		MappingSource:  1,
-	})
+	for _, v := range edbInfoList {
+		edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
+			EdbInfoId:      v.EdbInfoId,
+			SourceName:     v.SourceName,
+			Source:         v.Source,
+			EdbCode:        v.EdbCode,
+			EdbName:        v.EdbName,
+			EdbAliasName:   v.EdbName,
+			EdbNameEn:      v.EdbNameEn,
+			EdbAliasNameEn: v.EdbNameEn,
+			EdbType:        v.EdbType,
+			Frequency:      v.Frequency,
+			FrequencyEn:    data.GetFrequencyEn(v.Frequency),
+			Unit:           v.Unit,
+			UnitEn:         v.UnitEn,
+			StartDate:      v.StartDate,
+			EndDate:        v.EndDate,
+			ModifyTime:     v.ModifyTime.Format(utils.FormatDateTime),
+			MappingSource:  1,
+		})
+	}
 
 	warnEdbList := make([]string, 0)
 	for _, v := range edbList {
@@ -1003,15 +1050,18 @@ func getFutureGoodProfitChartInfo(chartInfo *data_manage.ChartInfoView, sysUser
 		br.ErrMsg = "商品利润曲线图配置异常"
 		return
 	}
+	if len(extraConf.EdbInfoIdList) == 0 {
+		extraConf.EdbInfoIdList = append(extraConf.EdbInfoIdList, extraConf.BaseEdbInfoId)
+	}
 
 	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取商品利润图表,基础指标信息失败,Err:" + err.Error()
 		return
 	}
-	edbList = append(edbList, edbInfoMapping)
+	edbList = edbInfoMappingList
 	futureGoodEdbInfoMappingList, err := data_manage.GetFutureGoodEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		br.Msg = "获取失败"
@@ -1247,15 +1297,24 @@ func GetFutureGoodProfitChartInfoDetailFromUniqueCode(chartInfo *data_manage.Cha
 		errMsg = "商品利润曲线图配置异常,Err:" + err.Error()
 		return
 	}
+	if len(extraConf.EdbInfoIdList) == 0 {
+		extraConf.EdbInfoIdList = append(extraConf.EdbInfoIdList, extraConf.BaseEdbInfoId)
+	}
 
 	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := data_manage.GetEtaEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
 		errMsg = "获取商品利润图表,基础指标信息失败,Err:" + err.Error()
 		return
 	}
-	edbList = append(edbList, edbInfoMapping)
+	baseEdbInfo := new(data_manage.ChartEdbInfoMapping)
+	for _, v := range edbInfoMappingList {
+		if v.EdbInfoId == extraConf.BaseEdbInfoId {
+			baseEdbInfo = v
+		}
+	}
+	edbList = edbInfoMappingList
 	futureGoodEdbInfoMappingList, err := data_manage.GetFutureGoodEdbChartEdbMappingList(chartInfoId)
 	if err != nil {
 		msg = "获取失败"
@@ -1295,7 +1354,6 @@ func GetFutureGoodProfitChartInfoDetailFromUniqueCode(chartInfo *data_manage.Cha
 	}
 
 	warnEdbList := make([]string, 0)
-	baseEdbInfo := edbList[0] //现货指标
 
 	for _, v := range edbList {
 		if v.IsNullData {

+ 7 - 1
controllers/report_chapter.go

@@ -255,6 +255,7 @@ func (this *ReportController) EditChapterBaseInfoAndPermission() {
 	if reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 
@@ -370,6 +371,7 @@ func (this *ReportController) EditDayWeekChapter() {
 	if reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 	// 报告的最后编辑人
@@ -558,6 +560,7 @@ func (this *ReportController) DelChapter() {
 	if reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 
@@ -1228,8 +1231,9 @@ func (this *ReportController) VoiceUpload() {
 		reportChapterInfo.VideoKind = 1
 		reportChapterInfo.LastModifyAdminId = this.SysUser.AdminId
 		reportChapterInfo.LastModifyAdminName = this.SysUser.RealName
+		reportInfo.VoiceGenerateType = 1
 		reportChapterInfo.ModifyTime = time.Now()
-		err = reportChapterInfo.UpdateChapter([]string{"VideoUrl", "VideoName", "VideoPlaySeconds", "VideoSize", "VideoKind", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"})
+		err = reportChapterInfo.UpdateChapter([]string{"VideoUrl", "VideoName", "VideoPlaySeconds", "VideoSize", "VideoKind", "LastModifyAdminId", "LastModifyAdminName", "VoiceGenerateType", "ModifyTime"})
 		if err != nil {
 			br.Msg = "上传失败"
 			br.ErrMsg = "修改报告章节的音频信息失败,Err:" + err.Error()
@@ -1310,6 +1314,7 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 	if reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 
@@ -1577,6 +1582,7 @@ func (this *ReportController) EditChapterTitle() {
 	if reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 	// 报告的最后编辑人

+ 3 - 0
controllers/report_v2.go

@@ -567,6 +567,7 @@ func (this *ReportController) Edit() {
 	if reportInfo.State == models.ReportStatePublished || reportInfo.State == models.ReportStatePass {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 
@@ -736,6 +737,7 @@ func (this *ReportController) SaveReportContent() {
 	if reportInfo != nil && reportInfo.State == 2 {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 
@@ -1144,6 +1146,7 @@ func (this *ReportController) EditLayoutImg() {
 	if reportInfo.State == models.ReportStatePublished || reportInfo.State == models.ReportStatePass {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
+		br.IsSendEmail = false
 		return
 	}
 

+ 2 - 1
controllers/voice.go

@@ -150,8 +150,9 @@ func (this *VoiceController) Upload() {
 		reportInfo.VideoSize = sizeStr
 		reportInfo.LastModifyAdminId = this.SysUser.AdminId
 		reportInfo.LastModifyAdminName = this.SysUser.RealName
+		reportInfo.VoiceGenerateType = 1
 		reportInfo.ModifyTime = time.Now()
-		err = reportInfo.UpdateReport([]string{"VideoUrl", "VideoName", "VideoPlaySeconds", "VideoSize", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"})
+		err = reportInfo.UpdateReport([]string{"VideoUrl", "VideoName", "VideoPlaySeconds", "VideoSize", "LastModifyAdminId", "LastModifyAdminName", "VoiceGenerateType", "ModifyTime"})
 		if err != nil {
 			br.Msg = "上传失败"
 			br.ErrMsg = "修改报告的音频信息失败,Err:" + err.Error()

+ 35 - 34
models/classify.go

@@ -9,40 +9,41 @@ import (
 )
 
 type Classify struct {
-	Id                int       `orm:"column(id);pk"`
-	ClassifyName      string    `description:"分类名称"`
-	Sort              int       `json:"-"`
-	ParentId          int       `description:"父级分类id"`
-	CreateTime        time.Time `description:"创建时间"`
-	ModifyTime        time.Time `description:"修改时间"`
-	Abstract          string    `description:"栏目简介"`
-	Descript          string    `description:"分享描述"`
-	ReportAuthor      string    `description:"栏目作者"`
-	AuthorDescript    string    `description:"作者简介"`
-	ColumnImgUrl      string    `description:"栏目配图"`
-	HeadImgUrl        string    `description:"头部banner"`
-	AvatarImgUrl      string    `description:"头像"`
-	ReportImgUrl      string    `description:"报告配图"`
-	HomeImgUrl        string    `description:"首页配图"`
-	ClassifyLabel     string    `description:"分类标签"`
-	ShowType          int       `description:"展示类型:1-列表 2-专栏"`
-	HasTeleconference int       `description:"是否有电话会:0-否 1-是"`
-	VipTitle          string    `description:"研究员头衔"`
-	IsShow            int       `description:"是否在小程序显示:1-显示 0-隐藏"`
-	YbFiccSort        int       `description:"小程序FICC页排序"`
-	YbFiccIcon        string    `description:"小程序FICC页icon"`
-	YbFiccPcIcon      string    `description:"小程序PC端FICC页背景图"`
-	YbIconUrl         string    `description:"小程序已购页icon"`
-	YbBgUrl           string    `description:"小程序已购详情背景图"`
-	YbListImg         string    `description:"小程序研报列表封面图"`
-	YbShareBgImg      string    `description:"小程序研报详情分享背景图"`
-	YbRightBanner     string    `description:"Pc端详情页,右侧,报告合集背景图"`
-	RelateTel         int       `description:"是否在电话会中可选: 0-否; 1-是"`
-	RelateVideo       int       `description:"是否在路演视频中可选: 0-否; 1-是"`
-	IsMassSend        int       `description:"1:群发,0:非群发"`
-	Enabled           int       `description:"是否可用,1可用,0禁用"`
-	Level             int       `description:"层级"`
-	HasChild          int       `description:"是否有子级别,0:下面没有子分类,1:下面有子分类;默认:0"`
+	Id                   int       `orm:"column(id);pk"`
+	ClassifyName         string    `description:"分类名称"`
+	Sort                 int       `json:"-"`
+	ParentId             int       `description:"父级分类id"`
+	CreateTime           time.Time `description:"创建时间"`
+	ModifyTime           time.Time `description:"修改时间"`
+	Abstract             string    `description:"栏目简介"`
+	Descript             string    `description:"分享描述"`
+	ReportAuthor         string    `description:"栏目作者"`
+	AuthorDescript       string    `description:"作者简介"`
+	ColumnImgUrl         string    `description:"栏目配图"`
+	HeadImgUrl           string    `description:"头部banner"`
+	AvatarImgUrl         string    `description:"头像"`
+	ReportImgUrl         string    `description:"报告配图"`
+	HomeImgUrl           string    `description:"首页配图"`
+	ClassifyLabel        string    `description:"分类标签"`
+	ShowType             int       `description:"展示类型:1-列表 2-专栏"`
+	HasTeleconference    int       `description:"是否有电话会:0-否 1-是"`
+	VipTitle             string    `description:"研究员头衔"`
+	IsShow               int       `description:"是否在小程序显示:1-显示 0-隐藏"`
+	YbFiccSort           int       `description:"小程序FICC页排序"`
+	YbFiccIcon           string    `description:"小程序FICC页icon"`
+	YbFiccPcIcon         string    `description:"小程序PC端FICC页背景图"`
+	YbIconUrl            string    `description:"小程序已购页icon"`
+	YbBgUrl              string    `description:"小程序已购详情背景图"`
+	YbListImg            string    `description:"小程序研报列表封面图"`
+	YbShareBgImg         string    `description:"小程序研报详情分享背景图"`
+	YbRightBanner        string    `description:"Pc端详情页,右侧,报告合集背景图"`
+	RelateTel            int       `description:"是否在电话会中可选: 0-否; 1-是"`
+	RelateVideo          int       `description:"是否在路演视频中可选: 0-否; 1-是"`
+	IsMassSend           int       `description:"1:群发,0:非群发"`
+	Enabled              int       `description:"是否可用,1可用,0禁用"`
+	Level                int       `description:"层级"`
+	HasChild             int       `description:"是否有子级别,0:下面没有子分类,1:下面有子分类;默认:0"`
+	ReportDetailShowType int       `description:"报告详情的展示类型:1-拼接;2:目录"`
 }
 
 type ClassifyAddReq struct {

+ 14 - 0
models/data_manage/chart_edb_mapping.go

@@ -164,6 +164,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")

+ 48 - 1
models/data_manage/chart_info.go

@@ -263,6 +263,11 @@ type EditChartInfoReq struct {
 	UnitEn               string                  `description:"英文单位名称"`
 }
 
+type EditFutureGoodChartInfoReq struct {
+	EditChartInfoReq
+	BarChartInfo FutureGoodBarChartInfoReq
+}
+
 type MarkersLine struct {
 	Axis             int             `json:"axis" description:"1左轴 2右轴 3横轴"`
 	AxisName         string          `json:"axisName" description:"轴的名称,例如'左轴'"`
@@ -757,6 +762,17 @@ type ChartInfoDetailResp struct {
 	ClassifyLevels       []string         `description:"图表分类的UniqueCode-从最顶级到当前分类(给前端回显定位用的=_=!)"`
 }
 
+type FutureGoodChartInfoDetailResp struct {
+	ChartInfo            *ChartInfoView
+	EdbInfoList          []*ChartEdbInfoMapping
+	XEdbIdValue          []int                     `description:"柱方图的x轴数据,指标id"`
+	YDataList            []YData                   `description:"柱方图的y轴数据"`
+	XDataList            []XData                   `description:"商品价格曲线的X轴数据"`
+	BarChartInfo         FutureGoodBarChartInfoReq `description:"柱方图的配置"`
+	CorrelationChartInfo *CorrelationInfo          `description:"相关性图表信息"`
+	DataResp             interface{}               `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
+}
+
 type BalanceTableChartListResp struct {
 	List []*BalanceChartInfoDetailResp
 }
@@ -777,6 +793,7 @@ type ExcelChartEdbView struct {
 type XData struct {
 	Name   string `description:"别名"`
 	NameEn string `description:"英文别名"`
+	IsHide int    `description:"是否隐藏,0不隐藏,1隐藏"`
 }
 
 // YData 柱方图的y轴数据
@@ -1134,7 +1151,7 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 }
 
 // EditFutureGoodChartInfoAndMapping 修改商品价格曲线的 图表与指标 的关系
-func EditFutureGoodChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calendar string, dateType, disabled int, barChartConf string) (err error) {
+func EditFutureGoodChartInfoAndMapping(req *EditFutureGoodChartInfoReq, edbInfoIdStr string, calendar string, dateType, disabled int, barChartConf string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -1213,7 +1230,12 @@ func EditFutureGoodChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr strin
 		return err
 	}
 	chartEdbMappingIdList := make([]string, 0)
+	hasAddMap := make(map[int]struct{})
 	for _, v := range req.BarChartInfo.EdbInfoIdList {
+		if _, ok := hasAddMap[v.EdbInfoId]; ok {
+			continue
+		}
+		hasAddMap[v.EdbInfoId] = struct{}{}
 		// 查询该指标是否存在,如果存在的话,那么就去修改,否则新增
 		var tmpChartEdbMapping *ChartEdbMapping
 		csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND edb_info_id=? AND source = ? `
@@ -1467,6 +1489,11 @@ type AddChartInfoReq struct {
 	UnitEn               string                  `description:"英文单位名称"`
 }
 
+type AddFutureGoodChartInfoReq struct {
+	AddChartInfoReq
+	BarChartInfo FutureGoodBarChartInfoReq
+}
+
 type PreviewChartInfoReq struct {
 	ChartEdbInfoList  []*ChartSaveItem `description:"指标及配置信息"`
 	DateType          int              `description:"日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间,6:起始日期至今 20:最近N年"`
@@ -1798,6 +1825,18 @@ type ChartInfoDetailFromUniqueCodeResp struct {
 	DataResp             interface{}      `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
 }
 
+type FutureChartInfoDetailFromUniqueCodeResp struct {
+	ChartInfo            *ChartInfoView
+	Status               bool `description:"true:图表存在,false:图表不存在"`
+	EdbInfoList          []*ChartEdbInfoMapping
+	XEdbIdValue          []int                     `description:"柱方图的x轴数据,指标id"`
+	YDataList            []YData                   `description:"柱方图的y轴数据"`
+	XDataList            []XData                   `description:"商品价格曲线的X轴数据"`
+	BarChartInfo         FutureGoodBarChartInfoReq `description:"柱方图的配置"`
+	CorrelationChartInfo *CorrelationInfo          `description:"相关性图表信息"`
+	DataResp             interface{}               `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
+}
+
 func GetChartInfoByUniqueCode(uniqueCode string) (item *ChartInfo, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM chart_info WHERE unique_code=? `
@@ -2101,6 +2140,13 @@ type BarChartInfoReq struct {
 	MarkersLines  string                   `description:"标识线"`
 }
 
+type FutureGoodBarChartInfoReq struct {
+	EdbInfoIdList []BarChartInfoEdbItemReq `description:"指标信息"`
+	DateList      []BarChartInfoDateReq    `description:"日期配置"`
+	XDataList     []XData                  `description:"横轴配置"`
+	BaseEdbInfoId int                      `description:"日期基准指标id"`
+}
+
 // BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
 type BarChartInfoEdbItemReq struct {
 	EdbInfoId     int     `description:"指标ID"`
@@ -2112,6 +2158,7 @@ type BarChartInfoEdbItemReq struct {
 	ConvertValue  float64 `description:"数据转换值"`
 	ConvertUnit   string  `description:"数据转换单位"`
 	ConvertEnUnit string  `description:"数据转换单位"`
+	IsHide        int     `description:"是否隐藏该项,0不隐藏,1隐藏"`
 }
 
 // BarChartInfoDateReq 柱方图预览请求数据(日期相关)

+ 75 - 30
models/data_manage/chart_info_correlation.go

@@ -168,7 +168,7 @@ type CorrelationChartInfoExtraConfig struct {
 }
 
 // CreateMultiFactorCorrelationChartAndEdb 新增多因子相关性图表
-func CreateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartEdbMapping, correlationInfo *ChartInfoCorrelation, chartMappings []*FactorEdbSeriesChartMapping, saveAs bool, copySeries []*FactorEdbSeries, copySeriesEdb []*FactorEdbSeriesMapping) (chartInfoId int, seriesIdMap map[int]int, err error) {
+func CreateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartEdbMapping, correlationInfo *ChartInfoCorrelation, chartMappings []*FactorEdbSeriesChartMapping, saveAs bool, copySeries []*FactorEdbSeries, copySeriesEdb []*FactorEdbSeriesMapping, copySeriesData []*FactorEdbSeriesCalculateData) (chartInfoId int, seriesIdMap map[int]int, err error) {
 	seriesIdMap = make(map[int]int) // 此处做一个原ID与新ID的映射, 另存为才用的到
 	o := orm.NewOrmUsingDB("data")
 	tx, e := o.Begin()
@@ -216,31 +216,44 @@ func CreateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingLis
 	if !saveAs {
 		// 指标系列-图表关联
 		if len(chartMappings) > 0 {
-			chartMappingOb := new(FactorEdbSeriesChartMapping)
-			sql := fmt.Sprintf(`UPDATE %s SET %s = ?, %s = ?, %s = ?, %s = ? WHERE %s = ?`, chartMappingOb.TableName(), chartMappingOb.Cols().ChartInfoId, chartMappingOb.Cols().Source, chartMappingOb.Cols().EdbUsed, chartMappingOb.Cols().ModifyTime, chartMappingOb.Cols().PrimaryId)
-			p, e := o.Raw(sql).Prepare()
-			if e != nil {
-				err = fmt.Errorf("sql prepare err: %v", e)
-				return
-			}
-			defer func() {
-				_ = p.Close()
-			}()
 			for _, v := range chartMappings {
+				//v.FactorEdbSeriesChartMappingId = 0
 				v.ChartInfoId = chartInfoId
-				_, e = p.Exec(v.ChartInfoId, v.Source, v.EdbUsed, v.ModifyTime, v.FactorEdbSeriesChartMappingId)
-				if e != nil {
-					err = fmt.Errorf("update exec err: %v", e)
-					return
-				}
+				//v.FactorEdbSeriesId = seriesIdMap[v.FactorEdbSeriesId]
 			}
+			_, e = tx.InsertMulti(200, chartMappings)
+			if e != nil {
+				err = fmt.Errorf("insert series chart mappings err: %v", e)
+				return
+			}
+
+			//chartMappingOb := new(FactorEdbSeriesChartMapping)
+			//sql := fmt.Sprintf(`UPDATE %s SET %s = ?, %s = ?, %s = ?, %s = ? WHERE %s = ?`, chartMappingOb.TableName(), chartMappingOb.Cols().ChartInfoId, chartMappingOb.Cols().Source, chartMappingOb.Cols().EdbUsed, chartMappingOb.Cols().ModifyTime, chartMappingOb.Cols().PrimaryId)
+			//p, e := o.Raw(sql).Prepare()
+			//if e != nil {
+			//	err = fmt.Errorf("sql prepare err: %v", e)
+			//	return
+			//}
+			//defer func() {
+			//	_ = p.Close()
+			//}()
+			//for _, v := range chartMappings {
+			//	v.ChartInfoId = chartInfoId
+			//	_, e = p.Exec(v.ChartInfoId, v.Source, v.EdbUsed, v.ModifyTime, v.FactorEdbSeriesChartMappingId)
+			//	if e != nil {
+			//		err = fmt.Errorf("update exec err: %v", e)
+			//		return
+			//	}
+			//}
 		}
 		return
 	}
 
 	// 另存为
+	originSeriesIds := make([]int, 0)
 	for _, v := range copySeries {
 		id := v.FactorEdbSeriesId
+		originSeriesIds = append(originSeriesIds, id)
 		v.FactorEdbSeriesId = 0
 		newId, e := tx.Insert(v)
 		if e != nil {
@@ -270,6 +283,22 @@ func CreateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingLis
 			return
 		}
 	}
+
+	// 系列指标计算
+	if len(copySeriesData) > 0 {
+		newCalculateData := make([]*FactorEdbSeriesCalculateData, 0)
+		for _, v := range copySeriesData {
+			t := v
+			t.FactorEdbSeriesCalculateDataId = 0
+			t.FactorEdbSeriesId = seriesIdMap[t.FactorEdbSeriesId]
+			newCalculateData = append(newCalculateData, t)
+		}
+		_, e = tx.InsertMulti(200, newCalculateData)
+		if e != nil {
+			err = fmt.Errorf("copy series calculate data err: %v", e)
+			return
+		}
+	}
 	return
 }
 
@@ -321,25 +350,41 @@ func UpdateMultiFactorCorrelationChartAndEdb(chartInfo *ChartInfo, edbMappingLis
 		return
 	}
 
+	// 删除原关联
+	chartMappingOb := new(FactorEdbSeriesChartMapping)
+	//if len(existsChartMappingIds) > 0 {
+	sql = fmt.Sprintf(`DELETE FROM %s WHERE %s = ?`, chartMappingOb.TableName(), chartMappingOb.Cols().ChartInfoId)
+	_, e = tx.Raw(sql, chartInfo.ChartInfoId).Exec()
+	if e != nil {
+		err = fmt.Errorf("clear chart mapping err: %v", e)
+		return
+	}
+	//}
+
 	// 指标系列-图表关联
 	if len(chartMappings) > 0 {
-		chartMappingOb := new(FactorEdbSeriesChartMapping)
-		sql = fmt.Sprintf(`UPDATE %s SET %s = ?, %s = ? WHERE %s = ?`, chartMappingOb.TableName(), chartMappingOb.Cols().EdbUsed, chartMappingOb.Cols().ModifyTime, chartMappingOb.Cols().PrimaryId)
-		p, e := o.Raw(sql).Prepare()
+		_, e = tx.InsertMulti(200, chartMappings)
 		if e != nil {
-			err = fmt.Errorf("sql prepare err: %v", e)
+			err = fmt.Errorf("insert series chart mappings err: %v", e)
 			return
 		}
-		defer func() {
-			_ = p.Close()
-		}()
-		for _, v := range chartMappings {
-			_, e = p.Exec(v.EdbUsed, v.ModifyTime, v.FactorEdbSeriesChartMappingId)
-			if e != nil {
-				err = fmt.Errorf("update exec err: %v", e)
-				return
-			}
-		}
+
+		//sql = fmt.Sprintf(`UPDATE %s SET %s = ?, %s = ?, %s = ?, %s = ? WHERE %s = ?`, chartMappingOb.TableName(), chartMappingOb.Cols().ChartInfoId, chartMappingOb.Cols().Source, chartMappingOb.Cols().EdbUsed, chartMappingOb.Cols().ModifyTime, chartMappingOb.Cols().PrimaryId)
+		//p, e := o.Raw(sql).Prepare()
+		//if e != nil {
+		//	err = fmt.Errorf("sql prepare err: %v", e)
+		//	return
+		//}
+		//defer func() {
+		//	_ = p.Close()
+		//}()
+		//for _, v := range chartMappings {
+		//	_, e = p.Exec(v.ChartInfoId, v.Source, v.EdbUsed, v.ModifyTime, v.FactorEdbSeriesChartMappingId)
+		//	if e != nil {
+		//		err = fmt.Errorf("update exec err: %v", e)
+		//		return
+		//	}
+		//}
 	}
 	return
 }

+ 21 - 0
models/data_manage/chart_info_future_good.go

@@ -0,0 +1,21 @@
+package data_manage
+
+// FutureGoodProfitChartInfoReq 图表预览请求数据
+type FutureGoodProfitChartInfoReq struct {
+	FutureGoodEdbInfoIdList []EdbInfoFromTag                   `description:"指标信息"`
+	CalculateFormula        string                             `description:"计算公式"`
+	BaseEdbInfoId           int                                `description:"基础的指标id"`
+	DateList                []FutureGoodProfitChartInfoDateReq `description:"日期配置"`
+	ProfitNameEn            string                             `description:"利润英文名称"`
+	EdbInfoIdList           []int                              `description:"现货指标ID列表"`
+	XDataList               []XData                            `description:"横轴配置"`
+}
+
+// FutureGoodProfitChartInfoDateReq 图表的日期数据(日期相关)
+type FutureGoodProfitChartInfoDateReq struct {
+	Type  int    `description:"配置类型"`
+	Date  string `description:"固定日期"`
+	Value int    `description:"N天的值"`
+	Color string `description:"颜色"`
+	Name  string `description:"别名"`
+}

+ 57 - 3
models/data_manage/edb_info.go

@@ -930,9 +930,63 @@ func ReplaceChartEdb(oldEdbInfo, newEdbInfo *EdbInfo) (relationEdbInfoIdList []i
 					chartInfo.EdbInfoIds = strings.Join(edbInfoIds, ",")
 					updateStr = append(updateStr, "EdbInfoIds")
 				}
-				if chartInfo.ExtraConfig != "" {
+				if chartInfo.ExtraConfig != "" || chartInfo.BarConfig != "" {
 					//判断是否是拟合方程或者散点图截面图
-					if chartInfo.Source == utils.CHART_SOURCE_LINE_EQUATION {
+					if chartInfo.Source == utils.CHART_SOURCE_FUTURE_GOOD {
+						// 商品价格曲线图的一些配置
+						var barConfig FutureGoodBarChartInfoReq
+						err = json.Unmarshal([]byte(chartInfo.BarConfig), &barConfig)
+						if err != nil {
+							errmsg = "商品价格曲线图配置异常 json.Unmarshal:Err:" + err.Error()
+							return
+						}
+						if barConfig.BaseEdbInfoId == oldEdbInfo.EdbInfoId {
+							barConfig.BaseEdbInfoId = newEdbInfo.EdbInfoId
+						}
+						for k, item := range barConfig.EdbInfoIdList {
+							if item.EdbInfoId == oldEdbInfo.EdbInfoId && item.Source == 1 {
+								barConfig.EdbInfoIdList[k].EdbInfoId = newEdbInfo.EdbInfoId
+							}
+						}
+						// 更新图表配置信息
+						// 重新序列化
+						configJson, e := json.Marshal(barConfig)
+						if e != nil {
+							err = e
+							errmsg = "图表配置信息序列化失败:json.Marshal Err: " + e.Error()
+							return
+						}
+						configStr := string(configJson)
+						chartInfo.BarConfig = configStr
+						updateStr = append(updateStr, "BarConfig")
+					} else if chartInfo.Source == utils.CHART_SOURCE_FUTURE_GOOD_PROFIT {
+						// 商品利润曲线图的一些配置
+						var extraConf FutureGoodProfitChartInfoReq
+						err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConf)
+						if err != nil {
+							errmsg = "商品利润曲线图配置异常 json.Unmarshal:Err:" + err.Error()
+							return
+						}
+						if extraConf.BaseEdbInfoId == oldEdbInfo.EdbInfoId {
+							extraConf.BaseEdbInfoId = newEdbInfo.EdbInfoId
+						}
+						for k, v := range extraConf.EdbInfoIdList {
+							if v == oldEdbInfo.EdbInfoId {
+								extraConf.EdbInfoIdList[k] = newEdbInfo.EdbInfoId
+							}
+						}
+						// 更新图表配置信息
+						// 重新序列化
+						configJson, e := json.Marshal(extraConf)
+						if e != nil {
+							err = e
+							errmsg = "图表配置信息序列化失败:json.Marshal Err: " + e.Error()
+							return
+						}
+						configStr := string(configJson)
+						chartInfo.ExtraConfig = configStr
+						updateStr = append(updateStr, "ExtraConfig")
+					} else if chartInfo.Source == utils.CHART_SOURCE_LINE_EQUATION {
 						//解析配置内容
 						var lineChartInfoConfig request.LineChartInfoReq
 						err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &lineChartInfoConfig)
@@ -1980,4 +2034,4 @@ func getThsHfAllDataByMongo(edbInfoId, source, subSource int, startDataTime stri
 	}
 
 	return
-}
+}

+ 17 - 0
models/data_manage/factor_edb_series.go

@@ -94,6 +94,16 @@ func (m *FactorEdbSeries) MultiRemove(ids []int) (err error) {
 	return
 }
 
+func (m *FactorEdbSeries) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
 func (m *FactorEdbSeries) GetItemById(id int) (item *FactorEdbSeries, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
@@ -349,3 +359,10 @@ func (a FactorEdbSeriesCorrelationMatrixOrder) Less(i, j int) bool {
 	// 负数按绝对值的降序排序(即数值的升序)
 	return a[i].XData > a[j].XData
 }
+
+// CalculateCorrelationMatrixPars 计算相关性矩阵参数
+type CalculateCorrelationMatrixPars struct {
+	BaseEdbInfoId int               `description:"标的指标ID"`
+	SeriesIds     []int             `description:"系列IDs"`
+	Correlation   CorrelationConfig `description:"相关性配置"`
+}

+ 10 - 0
models/data_manage/factor_edb_series_chart_mapping.go

@@ -103,6 +103,16 @@ func (m *FactorEdbSeriesChartMapping) MultiRemove(ids []int) (err error) {
 	return
 }
 
+func (m *FactorEdbSeriesChartMapping) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
 func (m *FactorEdbSeriesChartMapping) GetItemById(id int) (item *FactorEdbSeriesChartMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)

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

@@ -1,6 +1,7 @@
 package future_good
 
 import (
+	"eta/eta_api/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
+}

+ 5 - 12
models/data_manage/future_good/request/future_good_chart.go

@@ -1,6 +1,8 @@
 package request
 
-import "eta/eta_api/models/data_manage"
+import (
+	"eta/eta_api/models/data_manage"
+)
 
 type EditChartEnInfoReq struct {
 	ChartInfoId      int    `description:"图表ID"`
@@ -56,6 +58,8 @@ type ChartInfoReq struct {
 	BaseEdbInfoId           int                          `description:"基础的指标id"`
 	DateList                []ChartInfoDateReq           `description:"日期配置"`
 	ProfitNameEn            string                       `description:"利润英文名称"`
+	EdbInfoIdList           []int                        `description:"现货指标ID列表"`
+	XDataList               []data_manage.XData          `description:"横轴配置"`
 }
 
 // ChartInfoDateReq 图表的日期数据(日期相关)
@@ -110,14 +114,3 @@ type SectionScatterEdbItemReq struct {
 	YDateValue int    `description:"Y轴的日期N天的值"`
 	IsShow     bool   `description:"是否展示"`
 }
-
-// EditChartInfoBaseReq
-// @Description: 修改商品图表的基础信息
-type EditChartInfoBaseReq struct {
-	ChartInfoId    int    `description:"图表ID"`
-	ChartName      string `description:"图表名称(根据当前语言版本不同而不同)"`
-	EdbName        string `description:"指标名称(根据当前语言版本不同而不同)"`
-	Unit           string `description:"指标单位(根据当前语言版本不同而不同)"`
-	ProfitName     string `description:"利润名称(根据当前语言版本不同而不同)"`
-	FutureGoodName string `description:"期货合约名称(根据当前语言版本不同而不同)"`
-}

+ 65 - 40
models/data_manage/future_good_chart_info.go

@@ -56,6 +56,17 @@ func EditFutureGoodChartEnInfoAndEdbEnInfo(chartInfoId int, chartNameEn string,
 	return
 }
 
+type EditFutureGoodChartInfoBaseReq struct {
+	ChartInfoId int    `description:"图表ID"`
+	ChartName   string `description:"图表名称(根据当前语言版本不同而不同)"`
+	/*	EdbName        string `description:"指标名称(根据当前语言版本不同而不同)"`
+		Unit           string `description:"指标单位(根据当前语言版本不同而不同)"`*/
+	ProfitName       string                      `description:"利润名称(根据当前语言版本不同而不同)"`
+	FutureGoodName   string                      `description:"期货合约名称(根据当前语言版本不同而不同)"`
+	ChartEdbInfoList []*EditChartInfoEdbBaseItem `description:"指标及配置信息"`
+	XDataList        []string                    `description:"商品价格曲线的X轴数据"`
+}
+
 // EditBaseFutureGoodChartInfoAndEdbEnInfo
 // @Description:  编辑期货商品基础的图表信息及指标信息
 // @author: Roc
@@ -67,7 +78,7 @@ func EditFutureGoodChartEnInfoAndEdbEnInfo(chartInfoId int, chartNameEn string,
 // @param edbUnit string
 // @param lang string
 // @return err error
-func EditBaseFutureGoodChartInfoAndEdbEnInfo(chartInfo *ChartInfo, chartName string, edbInfoId int, edbName, edbUnit, lang string) (err error) {
+func EditBaseFutureGoodChartInfoAndEdbEnInfo(chartInfo *ChartInfo, req *EditFutureGoodChartInfoBaseReq, lang string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -85,63 +96,54 @@ func EditBaseFutureGoodChartInfoAndEdbEnInfo(chartInfo *ChartInfo, chartName str
 	updateChartCols := make([]string, 0)
 	switch lang {
 	case utils.EnLangVersion:
-		chartInfo.ChartNameEn = chartName
+		chartInfo.ChartNameEn = req.ChartName
 		updateChartCols = append(updateChartCols, "ChartNameEn")
 	default:
-		chartInfo.ChartName = chartName
+		chartInfo.ChartName = req.ChartName
 		updateChartCols = append(updateChartCols, "ChartName")
 	}
 	chartInfo.ModifyTime = time.Now()
-	updateChartCols = append(updateChartCols, "ModifyTime")
+	updateChartCols = append(updateChartCols, "ModifyTime", "BarConfig")
 	_, err = to.Update(chartInfo, updateChartCols...)
 	if err != nil {
 		fmt.Println("UPDATE  chart_info Err:", err.Error())
 		return err
 	}
-
-	var count int
-	csql := `SELECT COUNT(1) AS count FROM chart_edb_mapping WHERE chart_info_id=? AND edb_info_id=? AND source = 1 `
-	err = to.Raw(csql, chartInfo.ChartInfoId, edbInfoId).QueryRow(&count)
-	if err != nil {
-		fmt.Println("QueryRow Err:", err.Error())
-		return err
-	}
-	if count > 0 {
+	for _, v := range req.ChartEdbInfoList {
 		msql := ` UPDATE edb_info SET modify_time = NOW()  `
 		pars := make([]interface{}, 0)
 		switch lang {
 		case utils.EnLangVersion:
-			if edbName != `` {
+			if v.EdbName != `` {
 				msql += ` ,edb_name_en = ? `
-				pars = append(pars, edbName)
+				pars = append(pars, v.EdbName)
 			}
 
-			if edbUnit != `` {
+			if v.Unit != `` {
 				msql += ` ,unit_en = ? `
-				pars = append(pars, edbUnit)
+				pars = append(pars, v.Unit)
 			}
 
 		default:
 
-			if edbName != `` {
+			if v.EdbName != `` {
 				msql += ` ,edb_name = ? `
-				pars = append(pars, edbName)
+				pars = append(pars, v.EdbName)
 			}
 
-			if edbUnit != `` {
+			if v.Unit != `` {
 				msql += ` ,unit = ? `
-				pars = append(pars, edbUnit)
+				pars = append(pars, v.Unit)
 			}
 		}
 		msql += ` WHERE edb_info_id = ? `
-		pars = append(pars, edbInfoId)
+		pars = append(pars, v.EdbInfoId)
 		_, err = to.Raw(msql, pars...).Exec()
 		if err != nil {
 			fmt.Println("edb_info Err:" + err.Error())
 			return err
 		}
 	}
-
 	return
 }
 
@@ -205,7 +207,7 @@ func EditFutureGoodProfitChartEnInfoAndEdbEnInfo(chartInfoId int, chartNameEn st
 // @param profitName string
 // @param lang string
 // @return err error
-func EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartInfo *ChartInfo, chartName string, edbInfoId int, edbName, edbUnit, profitName, lang string) (err error) {
+func EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartInfo *ChartInfo, req *EditFutureGoodChartInfoBaseReq, lang string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -223,32 +225,55 @@ func EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartInfo *ChartInfo, chartNa
 	updateChartCols := make([]string, 0)
 	switch lang {
 	case utils.EnLangVersion:
-		chartInfo.ChartNameEn = chartName
+		chartInfo.ChartNameEn = req.ChartName
 		updateChartCols = append(updateChartCols, "ChartNameEn")
 	default:
-		chartInfo.ChartName = chartName
+		chartInfo.ChartName = req.ChartName
 		updateChartCols = append(updateChartCols, "ChartName")
 	}
 	chartInfo.ModifyTime = time.Now()
-	updateChartCols = append(updateChartCols, "ModifyTime")
+	updateChartCols = append(updateChartCols, "ModifyTime", "ExtraConfig")
 	_, err = to.Update(chartInfo, updateChartCols...)
 	if err != nil {
 		fmt.Println("UPDATE  chart_info Err:", err.Error())
 		return err
 	}
-
-	// 更改指标英文信息
 	var sql string
-	switch lang {
-	case utils.EnLangVersion:
-		sql = ` UPDATE  edb_info SET edb_name_en = ?,unit_en = ?,modify_time = NOW() WHERE edb_info_id = ? `
-	default:
-		sql = ` UPDATE  edb_info SET edb_name = ?,unit = ?,modify_time = NOW() WHERE edb_info_id = ? `
-	}
-	_, err = to.Raw(sql, edbName, edbUnit, edbInfoId).Exec()
-	if err != nil {
-		fmt.Println("edb_info Err:" + err.Error())
-		return
+	// 更改指标英文信息
+	for _, v := range req.ChartEdbInfoList {
+		msql := ` UPDATE edb_info SET modify_time = NOW()  `
+		pars := make([]interface{}, 0)
+		switch lang {
+		case utils.EnLangVersion:
+			if v.EdbName != `` {
+				msql += ` ,edb_name_en = ? `
+				pars = append(pars, v.EdbName)
+			}
+
+			if v.Unit != `` {
+				msql += ` ,unit_en = ? `
+				pars = append(pars, v.Unit)
+			}
+
+		default:
+
+			if v.EdbName != `` {
+				msql += ` ,edb_name = ? `
+				pars = append(pars, v.EdbName)
+			}
+
+			if v.Unit != `` {
+				msql += ` ,unit = ? `
+				pars = append(pars, v.Unit)
+			}
+		}
+		msql += ` WHERE edb_info_id = ? `
+		pars = append(pars, v.EdbInfoId)
+		_, err = to.Raw(msql, pars...).Exec()
+		if err != nil {
+			fmt.Println("edb_info Err:" + err.Error())
+			return err
+		}
 	}
 
 	// 更改指标英文信息
@@ -259,7 +284,7 @@ func EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartInfo *ChartInfo, chartNa
 	default:
 		sql = ` UPDATE  chart_info_future_good_profit SET profit_name = ?,modify_time = NOW() WHERE chart_info_id = ? `
 	}
-	_, err = to.Raw(sql, profitName, chartInfo.ChartInfoId).Exec()
+	_, err = to.Raw(sql, req.ProfitName, chartInfo.ChartInfoId).Exec()
 	if err != nil {
 		fmt.Println("chart_info_future_good_profit Err:" + err.Error())
 		return

+ 19 - 1
models/report.go

@@ -86,6 +86,7 @@ type Report struct {
 	IsPublicPublish     int8      `description:"是否公开发布,1:是,2:否"`
 	ReportCreateTime    time.Time `description:"报告时间创建时间"`
 	InheritReportId     int       `description:"待继承的报告ID"`
+	VoiceGenerateType   int       `description:"音频生成方式,0:系统生成,1:人工上传"`
 }
 
 type ReportList struct {
@@ -650,6 +651,23 @@ func ModifyReportVideo(reportId int, videoUrl, videoName, videoSize string, play
 	return
 }
 
+// ModifyReportVideoByNoVideo
+// @Description: 修改无音频的报告音频信息
+// @author: Roc
+// @datetime 2024-07-25 18:03:05
+// @param reportId int
+// @param videoUrl string
+// @param videoName string
+// @param videoSize string
+// @param playSeconds float64
+// @return err error
+func ModifyReportVideoByNoVideo(reportId int, videoUrl, videoName, videoSize string, playSeconds float64) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE report SET video_url=?,video_name=?,video_play_seconds=?,video_size=? WHERE id=? AND video_url=""`
+	_, err = o.Raw(sql, videoUrl, videoName, playSeconds, videoSize, reportId).Exec()
+	return
+}
+
 type ReportItem struct {
 	Id                 int       `orm:"column(id)" description:"报告Id"`
 	AddType            int       `description:"新增方式:1:新增报告,2:继承报告"`
@@ -705,7 +723,7 @@ func EditReportContent(reportId int, content, contentSub string) (err error) {
 
 func AddReportSaveLog(reportId, adminId int, content, contentSub, contentStruct, canvasColor, adminName string, headResourceId, endResourceId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ` INSERT INTO report_save_log(report_id, content,content_sub,content_struct,canvas_color,head_resource_id,end_resource_id,admin_id,admin_name) VALUES (?,?,?,?,?) `
+	sql := ` INSERT INTO report_save_log(report_id, content,content_sub,content_struct,canvas_color,head_resource_id,end_resource_id,admin_id,admin_name) VALUES (?,?,?,?,?,?,?,?,?) `
 	_, err = o.Raw(sql, reportId, content, contentSub, contentStruct, canvasColor, headResourceId, endResourceId, adminId, adminName).Exec()
 	return
 }

+ 1 - 0
models/report_chapter.go

@@ -42,6 +42,7 @@ type ReportChapter struct {
 	ContentModifyTime   time.Time `description:"内容更新时间"`
 	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
 	ReportCreateTime    time.Time `description:"报告时间创建时间"`
+	VoiceGenerateType   int       `description:"音频生成方式,0:系统生成,1:人工上传"`
 }
 
 // ReportChapterItem 报告章节详情

+ 2 - 1
services/classify.go

@@ -265,7 +265,8 @@ func AddReportClassify(classifyName string, parentId int, chartPermissionIdList
 	classify.ModifyTime = nowTime
 	classify.Sort = maxSort + 1
 	classify.Enabled = 1
-	classify.ShowType = 1 //默认列表格式
+	classify.ShowType = 1             //默认列表格式
+	classify.ReportDetailShowType = 1 //默认列表格式
 	classify.IsShow = 1
 	classify.Level = level
 	/*classify.Abstract = req.Abstract

+ 347 - 23
services/data/correlation/chart_info.go

@@ -14,6 +14,7 @@ import (
 	"sort"
 	"strconv"
 	"strings"
+	"sync"
 	"time"
 )
 
@@ -1550,34 +1551,357 @@ func GetFactorChartDataByChartId(chartInfoId int, extraConfig string) (xEdbIdVal
 	return
 }
 
-// FormatChartEdbInfoMappings 补充指标信息
-func FormatChartEdbInfoMappings(chartInfoId int, mappings []*data_manage.ChartEdbInfoMapping) (edbList []*data_manage.ChartEdbInfoMapping, err error) {
-	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
-	if len(mappings) == 0 {
+// RemoveCorrelationRelate 删除相关性图表关联信息
+func RemoveCorrelationRelate(chartInfoId int) (err error) {
+	if chartInfoId <= 0 {
+		return
+	}
+	// 相关性图表
+	chartCorrelate := new(data_manage.ChartInfoCorrelation)
+	if e := chartCorrelate.GetItemById(chartInfoId); e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("获取相关性图表信息失败, %v", e)
+		return
+	}
+	if chartCorrelate == nil {
 		return
 	}
 
-	for _, v := range mappings {
-		if chartInfoId <= 0 {
-			v.IsAxis = 1
-			v.LeadValue = 0
-			v.LeadUnit = ""
-			v.ChartEdbMappingId = 0
-			v.ChartInfoId = 0
-			v.IsOrder = false
-			v.EdbInfoType = 1
-			v.ChartStyle = ""
-			v.ChartColor = ""
-			v.ChartWidth = 0
-		} else {
-			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
-			v.LeadUnitEn = data.GetLeadUnitEn(v.LeadUnit)
+	// 删除相关性图
+	if e := chartCorrelate.Delete(); e != nil {
+		err = fmt.Errorf("删除相关性图表失败, %v", e)
+		return
+	}
+
+	// 多因子
+	if chartCorrelate.AnalysisMode != 1 {
+		return
+	}
+	seriesIds := make([]int, 0)
+
+	// 删除图表关联
+	chartMappingOb := new(data_manage.FactorEdbSeriesChartMapping)
+	{
+		cond := fmt.Sprintf(" AND %s = ?", chartMappingOb.Cols().ChartInfoId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, chartCorrelate.CorrelationChartInfoId)
+		items, e := chartMappingOb.GetItemsByCondition(cond, pars, []string{}, "")
+		if e != nil {
+			err = fmt.Errorf("获取图表关联指标系列失败, %v", e)
+			return
+		}
+		for _, v := range items {
+			if !utils.InArrayByInt(seriesIds, v.FactorEdbSeriesId) {
+				seriesIds = append(seriesIds, v.FactorEdbSeriesId)
+			}
+		}
+		removeCond := fmt.Sprintf(" %s = ?", chartMappingOb.Cols().ChartInfoId)
+		if e = chartMappingOb.RemoveByCondition(removeCond, pars); e != nil {
+			err = fmt.Errorf("删除图表关联指标系列失败, %v", e)
+			return
+		}
+	}
+
+	// 删除系列
+	if len(seriesIds) == 0 {
+		return
+	}
+	seriesOb := new(data_manage.FactorEdbSeries)
+	if e := seriesOb.MultiRemove(seriesIds); e != nil {
+		err = fmt.Errorf("删除系列失败, %v", e)
+		return
+	}
+
+	edbMappingOb := new(data_manage.FactorEdbSeriesMapping)
+	{
+		cond := fmt.Sprintf(" %s IN (%s)", edbMappingOb.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, seriesIds)
+		if e := edbMappingOb.RemoveByCondition(cond, pars); e != nil {
+			err = fmt.Errorf("删除系列指标失败, %v", e)
+			return
+		}
+	}
+	calculateOb := new(data_manage.FactorEdbSeriesCalculateData)
+	{
+		cond := fmt.Sprintf(" %s IN (%s)", calculateOb.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(seriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, seriesIds)
+		if e := calculateOb.RemoveByCondition(cond, pars); e != nil {
+			err = fmt.Errorf("删除系列指标计算失败, %v", e)
+			return
+		}
+	}
+	return
+}
+
+// CalculateCorrelationMatrix 计算相关性矩阵
+func CalculateCorrelationMatrix(req data_manage.CalculateCorrelationMatrixPars) (resp data_manage.FactorEdbSeriesCorrelationMatrixResp, chartMappings []*data_manage.FactorEdbSeriesChartMapping, err error) {
+	if req.BaseEdbInfoId <= 0 {
+		err = fmt.Errorf("请选择标的指标")
+		return
+	}
+	if len(req.SeriesIds) == 0 {
+		err = fmt.Errorf("请选择因子指标系列")
+		return
+	}
+	if req.Correlation.LeadValue <= 0 {
+		err = fmt.Errorf("分析周期不允许设置为负数或0")
+		return
+	}
+	if req.Correlation.LeadUnit == "" {
+		err = fmt.Errorf("请选择分析周期频度")
+		return
+	}
+	leadUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.LeadUnit]
+	if !ok {
+		err = fmt.Errorf("错误的分析周期频度: %s", req.Correlation.LeadUnit)
+		return
+	}
+
+	if req.Correlation.CalculateUnit == "" {
+		err = fmt.Errorf("请选择计算窗口频度")
+		return
+	}
+	calculateUnitDays, ok := utils.FrequencyDaysMap[req.Correlation.CalculateUnit]
+	if !ok {
+		err = fmt.Errorf("计算窗口频度有误: %s", req.Correlation.CalculateUnit)
+		return
+	}
+	leadDays := 2 * req.Correlation.LeadValue * leadUnitDays
+	calculateDays := req.Correlation.CalculateValue * calculateUnitDays
+	if calculateDays < leadDays {
+		err = fmt.Errorf("计算窗口必须≥2*分析周期")
+		return
+	}
+
+	// 获取标的指标信息及数据
+	baseEdb, e := data_manage.GetEdbInfoById(req.BaseEdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("获取标的指标失败, %v", e)
+		return
+	}
+	dataListA := make([]*data_manage.EdbDataList, 0)
+	{
+		// 标的指标数据日期区间
+		startDate := time.Now().AddDate(0, 0, -calculateDays).Format(utils.FormatDate)
+		endDate := time.Now().Format(utils.FormatDate)
+		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		startDate = startDateTime.AddDate(0, 0, 1).Format(utils.FormatDate) // 不包含第一天
+		switch baseEdb.EdbInfoType {
+		case 0:
+			dataListA, e = data_manage.GetEdbDataList(baseEdb.Source, baseEdb.SubSource, baseEdb.EdbInfoId, startDate, endDate)
+		case 1:
+			_, dataListA, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdb.EdbInfoId, startDate, endDate, false)
+		default:
+			err = fmt.Errorf("标的指标类型异常: %d", baseEdb.EdbInfoType)
+			return
+		}
+		if e != nil {
+			err = fmt.Errorf("获取标的指标数据失败, %v", e)
+			return
+		}
+	}
+
+	// 获取因子系列
+	seriesIdItem := make(map[int]*data_manage.FactorEdbSeries)
+	{
+		ob := new(data_manage.FactorEdbSeries)
+		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().PrimaryId, utils.GetOrmInReplace(len(req.SeriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.SeriesIds)
+		items, e := ob.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", ob.Cols().PrimaryId))
+		if e != nil {
+			err = fmt.Errorf("获取因子指标系列失败, %v", e)
+			return
+		}
+		for _, v := range items {
+			seriesIdItem[v.FactorEdbSeriesId] = v
 		}
-		v.FrequencyEn = data.GetFrequencyEn(v.Frequency)
-		if v.Unit == `无` {
-			v.Unit = ``
+	}
+
+	// 获取因子指标
+	edbMappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	edbInfoIds := make([]int, 0)
+	{
+		ob := new(data_manage.FactorEdbSeriesMapping)
+		cond := fmt.Sprintf(" AND %s IN (%s)", ob.Cols().FactorEdbSeriesId, utils.GetOrmInReplace(len(req.SeriesIds)))
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.SeriesIds)
+		order := fmt.Sprintf("%s ASC, %s ASC", ob.Cols().FactorEdbSeriesId, ob.Cols().EdbInfoId)
+		items, e := ob.GetItemsByCondition(cond, pars, []string{}, order)
+		if e != nil {
+			err = fmt.Errorf("获取系列指标失败, %v", e)
+			return
+		}
+		for _, v := range items {
+			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+		}
+		edbMappings = items
+	}
+	edbIdItem := make(map[int]*data_manage.EdbInfo)
+	edbItems, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		err = fmt.Errorf("获取因子指标信息失败, %v", e)
+		return
+	}
+	for _, v := range edbItems {
+		edbIdItem[v.EdbInfoId] = v
+	}
+
+	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateData)
+
+	calculateWorkers := make(chan struct{}, 10)
+	wg := sync.WaitGroup{}
+	edbExists := make(map[string]bool)
+	chartKeyMap := make(map[string]*data_manage.FactorEdbSeriesChartMapping)
+	for _, v := range edbMappings {
+		existsKey := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
+		if edbExists[existsKey] {
+			continue
+		}
+		edbExists[existsKey] = true
+
+		edbItem := edbIdItem[v.EdbInfoId]
+		if edbItem == nil {
+			continue
+		}
+		seriesItem := seriesIdItem[v.FactorEdbSeriesId]
+		if seriesItem == nil {
+			continue
+		}
+
+		wg.Add(1)
+		go func(mapping *data_manage.FactorEdbSeriesMapping, edb *data_manage.EdbInfo, series *data_manage.FactorEdbSeries) {
+			defer func() {
+				wg.Done()
+				<-calculateWorkers
+			}()
+			calculateWorkers <- struct{}{}
+
+			var item data_manage.FactorEdbSeriesCorrelationMatrixItem
+			item.SeriesId = series.FactorEdbSeriesId
+			item.EdbInfoId = edb.EdbInfoId
+			item.EdbCode = edb.EdbCode
+			item.EdbName = edb.EdbName
+
+			// 指标来源
+			edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+			edbList = append(edbList, &data_manage.ChartEdbInfoMapping{
+				EdbInfoId:           edb.EdbInfoId,
+				EdbInfoCategoryType: edb.EdbInfoType,
+				EdbType:             edb.EdbType,
+				Source:              edb.Source,
+				SourceName:          edb.SourceName,
+			})
+			sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+			item.SourceName = strings.Join(sourceNameList, ",")
+			item.SourceNameEn = strings.Join(sourceNameEnList, ",")
+
+			// 获取指标数据
+			dataListB := make([]*data_manage.EdbDataList, 0)
+			if series.CalculateState == data_manage.FactorEdbSeriesCalculated {
+				cond := fmt.Sprintf(" AND %s = ? AND %s = ?", calculateDataOb.Cols().FactorEdbSeriesId, calculateDataOb.Cols().EdbInfoId)
+				pars := make([]interface{}, 0)
+				pars = append(pars, mapping.FactorEdbSeriesId, mapping.EdbInfoId)
+				dataItems, e := calculateDataOb.GetItemsByCondition(cond, pars, []string{calculateDataOb.Cols().DataTime, calculateDataOb.Cols().Value}, fmt.Sprintf("%s ASC", calculateDataOb.Cols().DataTime))
+				if e != nil {
+					item.Msg = fmt.Sprintf("计算失败")
+					item.ErrMsg = fmt.Sprintf("获取计算数据失败, err: %v", e)
+					resp.Fail = append(resp.Fail, item)
+					return
+				}
+				dataListB = data_manage.TransEdbSeriesCalculateData2EdbDataList(dataItems)
+			} else {
+				switch edb.EdbInfoType {
+				case 0:
+					dataListB, e = data_manage.GetEdbDataList(edb.Source, edb.SubSource, edb.EdbInfoId, "", "")
+				case 1:
+					_, dataListB, _, _, e, _ = data.GetPredictDataListByPredictEdbInfoId(edb.EdbInfoId, "", "", false)
+				default:
+					item.Msg = fmt.Sprintf("计算失败")
+					item.ErrMsg = fmt.Sprintf("指标类型异常, edbType: %d", edb.EdbInfoType)
+					resp.Fail = append(resp.Fail, item)
+					return
+				}
+			}
+
+			// 计算相关性
+			xEdbIdValue, yDataList, e := CalculateCorrelation(req.Correlation.LeadValue, req.Correlation.LeadUnit, baseEdb.Frequency, edb.Frequency, dataListA, dataListB)
+			if e != nil {
+				item.Msg = fmt.Sprintf("计算失败")
+				item.ErrMsg = fmt.Sprintf("相关性计算失败, err: %v", e)
+				resp.Fail = append(resp.Fail, item)
+				return
+			}
+
+			// X及Y轴数据
+			yData := yDataList[0].Value
+			yLen := len(yData)
+			values := make([]data_manage.FactorEdbSeriesCorrelationMatrixValues, len(xEdbIdValue))
+			for k, x := range xEdbIdValue {
+				var y float64
+				if k >= 0 && k < yLen {
+					y = yData[k]
+				}
+				y = utils.SubFloatToFloat(y, 2)
+				values[k] = data_manage.FactorEdbSeriesCorrelationMatrixValues{
+					XData: x, YData: y,
+				}
+			}
+
+			// 图表关联
+			newMapping := new(data_manage.FactorEdbSeriesChartMapping)
+			newMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeCorrelation
+
+			// 计算参数
+			var calculatePars data_manage.FactorEdbSeriesChartCalculateCorrelationReq
+			calculatePars.BaseEdbInfoId = req.BaseEdbInfoId
+			calculatePars.LeadValue = req.Correlation.LeadValue
+			calculatePars.LeadUnit = req.Correlation.LeadUnit
+			calculatePars.CalculateValue = req.Correlation.CalculateValue
+			calculatePars.CalculateUnit = req.Correlation.CalculateUnit
+			bc, e := json.Marshal(calculatePars)
+			if e != nil {
+				item.Msg = fmt.Sprintf("计算失败")
+				item.ErrMsg = fmt.Sprintf("计算参数JSON格式化失败, err: %v", e)
+				resp.Fail = append(resp.Fail, item)
+				return
+			}
+			newMapping.CalculatePars = string(bc)
+
+			// 计算结果, 注此处保存的是排序前的顺序
+			bv, e := json.Marshal(values)
+			if e != nil {
+				item.Msg = fmt.Sprintf("计算失败")
+				item.ErrMsg = fmt.Sprintf("计算结果JSON格式化失败, err: %v", e)
+				resp.Fail = append(resp.Fail, item)
+				return
+			}
+			newMapping.CalculateData = string(bv)
+			newMapping.FactorEdbSeriesId = mapping.FactorEdbSeriesId
+			newMapping.EdbInfoId = mapping.EdbInfoId
+			newMapping.CreateTime = time.Now().Local()
+			newMapping.ModifyTime = time.Now().Local()
+			chartKeyMap[existsKey] = newMapping
+
+			// 按照固定规则排期数[0 1 2 3 -1 -2 -3], 仅矩阵展示为此顺序
+			sort.Sort(data_manage.FactorEdbSeriesCorrelationMatrixOrder(values))
+			item.Msg = "计算成功"
+			item.Values = values
+			resp.Success = append(resp.Success, item)
+		}(v, edbItem, seriesItem)
+	}
+	wg.Wait()
+
+	// 新增图表关联, 此处按照顺序添加
+	chartMappings = make([]*data_manage.FactorEdbSeriesChartMapping, 0)
+	for _, v := range edbMappings {
+		k := fmt.Sprintf("%d-%d", v.FactorEdbSeriesId, v.EdbInfoId)
+		item := chartKeyMap[k]
+		if item == nil {
+			continue
 		}
-		edbList = append(edbList, v)
+		chartMappings = append(chartMappings, item)
 	}
 	return
 }

+ 3 - 1
services/data/edb_info.go

@@ -1870,7 +1870,7 @@ func EdbInfoAdd(source, subSource, classifyId int, edbCode, edbName, frequency,
 	edbInfo.EdbNameSource = edbName
 	edbInfo.Frequency = frequency
 	edbInfo.Unit = unit
-	edbInfo.UnitEn = frequency
+	edbInfo.UnitEn = unit
 	edbInfo.StartDate = startDate
 	edbInfo.EndDate = endDate
 	edbInfo.ClassifyId = classifyId
@@ -2569,8 +2569,10 @@ func EdbInfoWsdAdd(item *data_manage.EdbInfo) (edbInfo *data_manage.EdbInfo, err
 	edbInfo.EdbCode = item.EdbCode
 	edbInfo.EdbName = item.EdbName
 	edbInfo.EdbNameSource = item.EdbName
+	edbInfo.EdbNameEn = item.EdbNameEn
 	edbInfo.Frequency = item.Frequency
 	edbInfo.Unit = item.Unit
+	edbInfo.UnitEn = item.UnitEn
 	edbInfo.ClassifyId = item.ClassifyId
 	edbInfo.SysUserId = item.SysUserId
 	edbInfo.SysUserRealName = item.SysUserRealName

+ 263 - 127
services/data/future_good/chart_info.go

@@ -15,42 +15,46 @@ import (
 )
 
 // GetChartEdbData 获取图表的指标数据
-func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping, futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping, barChartInfoDateList []data_manage.BarChartInfoDateReq, needData bool) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) {
+func GetChartEdbData(chartInfoId int, startDate, endDate string, baseEdbInfoMapping *data_manage.ChartEdbInfoMapping, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, futureGoodEdbInfoMapping *data_manage.ChartEdbInfoMapping, barChartInfoConf data_manage.FutureGoodBarChartInfoReq, needData bool) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) {
 	edbList = make([]*data_manage.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][]*data_manage.EdbDataList)
 
-	item := new(data_manage.ChartEdbInfoMapping)
-	edbInfoMapping.FrequencyEn = data.GetFrequencyEn(edbInfoMapping.Frequency)
+	// todo item
+	//item := new(data_manage.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 = ""
@@ -62,21 +66,43 @@ 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
+	}
+
 	// 普通的指标数据
 	{
-		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)
+		}
 	}
 
 	// 获取主力合约和最新日期
@@ -132,30 +158,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,
+			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),
@@ -166,12 +192,21 @@ 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 == `海外` {
@@ -183,30 +218,30 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 			EdbName:             zlFutureGoodEdbInfo.FutureGoodEdbName,
 			EdbAliasName:        zlFutureGoodEdbInfo.FutureGoodEdbName,
 			EdbNameEn:           zlFutureGoodEdbInfo.FutureGoodEdbNameEn,
-			EdbType:             edbInfoMapping.EdbType,
-			Frequency:           edbInfoMapping.Frequency,
-			FrequencyEn:         edbInfoMapping.FrequencyEn,
-			Unit:                edbInfoMapping.Unit,
-			UnitEn:              edbInfoMapping.UnitEn,
+			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:         edbInfoMapping.ChartInfoId,
+			ChartInfoId:         baseEdbInfoMapping.ChartInfoId,
 			MaxData:             zlFutureGoodEdbInfo.MaxValue,
 			MinData:             zlFutureGoodEdbInfo.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:          zlFutureGoodEdbInfo.LatestDate.Format(utils.FormatDateTime),
 			LatestValue:         zlFutureGoodEdbInfo.LatestValue,
 			UniqueCode:          futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(0),
@@ -228,24 +263,45 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 	// 获取数据
 
 	// 现货数据
-	{
+	for _, edbInfoMapping := range edbInfoMappingList {
 		dataList := make([]*data_manage.EdbDataList, 0)
 		dataList, err = data_manage.GetEdbDataList(edbInfoMapping.Source, edbInfoMapping.SubSource, edbInfoMapping.EdbInfoId, startDate, endDate)
 		if err != nil {
 			return
 		}
 		edbDataListMap[edbInfoMapping.EdbInfoId] = dataList
-		item.DataList = dataList
+		// todo item
+		//item.DataList = dataList
 	}
-
-	// 期货数据
+	futureEdbInfoIds := make([]int, 0)
 	for _, v := range futureGoodMappingList {
-		dataList := make([]*data_manage.EdbDataList, 0)
-
-		tmpDataList, tmpErr := future_good2.GetFutureGoodEdbDataListByDate(v.EdbInfoId, startDate, endDate)
+		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([]*data_manage.EdbDataList, 0)
+		tmpDataList, ok := tmpDataListMap[v.EdbInfoId]
+		if !ok {
+			/*err = fmt.Errorf("期货数据不存在 FutureGoodEdbInfoId: %d", v.EdbInfoId)
+			return*/
+			continue
+		}
 		for _, tmpData := range tmpDataList {
 			dataList = append(dataList, &data_manage.EdbDataList{
 				EdbDataId:     tmpData.FutureGoodEdbDataId,
@@ -259,14 +315,20 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		v.DataList = dataList
 	}
 
-	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 = []data_manage.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{
 	//	Date:           "",
@@ -296,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
 			}
 		}
 
@@ -326,8 +389,8 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 
 		for i := lenEdbId - 1; i >= 0; i-- {
 			// 如果没有在无数据的指标列表中找到,那么就找到了最大x轴的下标
-			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok {
-				// 如果最大x轴的下标 小于 当前下标,那么就重新赋值
+			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok || utils.InArrayByInt(baseEdbIds, edbInfoIdList[i]) { //以往的逻辑是碰到第一个无数据的期货指标,那后续的月份都是无数据的,因此需要特殊处理,改成多个现货指标之后需要排除无值的现货指标
+				// 如果最大x轴的下标 小于 当前下标,那么就重新赋值
 				if maxIndex < i-1 {
 					maxIndex = i - 1
 				}
@@ -362,22 +425,44 @@ 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 *data_manage.ChartEdbInfoMapping, futureGoodMappingList []*future_good2.FutureGoodEdbInfo, edbDataListMap map[int][]*data_manage.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []data_manage.YData, err error) {
+func BarChartData(baseEdbInfoMapping *data_manage.ChartEdbInfoMapping, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, futureGoodMappingList []*future_good2.FutureGoodEdbInfo, edbDataListMap map[int][]*data_manage.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []data_manage.YData, err error) {
 	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
+	// 现货指标数据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
+		}
+	}
+
 	edbDataMap := 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
@@ -387,7 +472,10 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 
 	// 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)
 	}
@@ -428,23 +516,43 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 		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], edbDataMap)
 		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 == `国内` {
@@ -564,10 +672,9 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 }
 
 // handleResultData 处理成最终的结果数据
-func handleResultData(regionType string, futureGoodEdbType int, yDataList []data_manage.YData, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, maxIndex int) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) {
+func handleResultData(regionType string, futureGoodEdbType, baseEdbLen int, yDataList []data_manage.YData, futureGoodEdbInfoList []*future_good2.FutureGoodEdbInfo, maxIndex int) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) {
 	xDataList = make([]data_manage.XData, 0)
 	newYDataList = yDataList
-
 	if regionType == `国内` {
 		for i := 1; i < 12; i++ {
 			if i > maxIndex {
@@ -601,11 +708,11 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []data
 			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 {
@@ -677,8 +784,8 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []data
 		currYear := findDateTime.Year()   // 当前年份
 		//v.XEdbInfoIdList
 		for edbInfoIndex, edbInfoId := range v.XEdbInfoIdList {
-			// 第一个不处理
-			if edbInfoIndex == 0 {
+			// 现货指标不处理
+			if edbInfoIndex <= baseEdbLen-1 {
 				continue
 			}
 
@@ -717,12 +824,12 @@ func handleResultData(regionType string, futureGoodEdbType int, yDataList []data
 		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 {
@@ -860,7 +967,7 @@ func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList
 }
 
 // GetNeedDateData 获取合约内需要的日期数据
-func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList, edbDataMap map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
+func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.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
@@ -873,18 +980,43 @@ func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList
 		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)
-		if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据,那么就返回
-			// 数据为0,也直接返回,做无值处理
-			if tmpValue == 0 {
-				return
+		tmpValue, ok := edbDataMap[tmpDate]
+		if !ok {
+			continue
+		}
+
+		// 该日期存在数据的指标数量
+		count := 0
+
+		for _, currEdbDataMap := range allEdbDataMap {
+			_, tmpIsFind := currEdbDataMap[tmpDate]
+			if tmpIsFind {
+				count++
+				if count >= maxCount {
+					continue
+				}
 			}
-			findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
-			findDataValue = tmpValue
-			isFind = true
+		}
+
+		// 该日期存在数据的期货指标数量小于2个,那么要继续往前找
+		if count < maxCount {
+			continue
+		}
+
+		//如果能找到数据,那么就返回
+		// 数据为0,也直接返回,做无值处理
+		if tmpValue == 0 {
 			return
 		}
+		findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+		findDataValue = tmpValue
+		isFind = true
+		return
 	}
 
 	return
@@ -903,11 +1035,15 @@ func FutureGoodChartInfoRefresh(chartInfoId int) (err error) {
 		}
 	}()
 
-	edbInfoMapping, err := data_manage.GetEtaEdbChartEdbMapping(chartInfoId)
+	edbInfoMappingList, err := data_manage.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 := data_manage.GetFutureGoodEdbChartEdbMapping(chartInfoId)
 	if err != nil {
@@ -922,7 +1058,7 @@ func FutureGoodChartInfoRefresh(chartInfoId int) (err error) {
 	}
 
 	// 批量刷新ETA指标
-	err, _ = data.EdbInfoRefreshAllFromBaseV3([]int{edbInfoMapping.EdbInfoId}, false, true, false)
+	err, _ = data.EdbInfoRefreshAllFromBaseV3(edbInfoIds, false, true, false)
 	if err != nil {
 		return
 	}

+ 137 - 43
services/data/future_good/profit_chart_info.go

@@ -17,13 +17,16 @@ import (
 )
 
 // GetProfitChartEdbData 获取利润图表的指标数据
-func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, zlFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, chartInfoDateList []request.ChartInfoDateReq, formulaStr string, edbInfoFromTagList []data_manage.EdbInfoFromTag) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) {
+func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, edbInfoList []*data_manage.EdbInfo, zlFutureGoodEdbInfoList []*future_good.FutureGoodEdbInfo, chartInfoDateList []request.ChartInfoDateReq, formulaStr string, edbInfoFromTagList []data_manage.EdbInfoFromTag, reqXDataList []data_manage.XData) (barConfigEdbInfoIdList []data_manage.BarChartInfoEdbItemReq, edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, xDataList []data_manage.XData, yDataList []data_manage.YData, err error) {
 	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
 
 	if baseEdbInfo == nil {
 		err = errors.New("ETA指标未选取")
 		return
 	}
+	if len(edbInfoList) == 0 {
+		edbInfoList = append(edbInfoList, baseEdbInfo)
+	}
 	if len(zlFutureGoodEdbInfoList) <= 0 {
 		err = errors.New("商品指标未选取")
 		return
@@ -55,10 +58,14 @@ func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, zlFutureGoodEdbInfo
 	}
 
 	// 普通的指标数据
-	baseDataList := make([]*data_manage.EdbDataList, 0)
-	baseDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.SubSource, baseEdbInfo.EdbInfoId, "", "")
-	if err != nil {
-		return
+	baseDataListMap := make(map[int][]*data_manage.EdbDataList)
+	for _, v := range edbInfoList {
+		baseDataList := make([]*data_manage.EdbDataList, 0)
+		baseDataList, err = data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
+		if err != nil {
+			return
+		}
+		baseDataListMap[v.EdbInfoId] = baseDataList
 	}
 
 	latestDate := zlFutureGoodEdbInfoList[0].EndDate
@@ -170,33 +177,47 @@ func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, zlFutureGoodEdbInfo
 	sort.Slice(dateList, func(i, j int) bool {
 		return dateList[i] < dateList[j]
 	})
+	var reqEdbInfoIds []int
+	for _, v := range edbInfoList {
+		reqEdbInfoIds = append(reqEdbInfoIds, v.EdbInfoId)
+		tmp := data_manage.XData{
+			Name:   v.EdbName,
+			NameEn: v.EdbNameEn,
+		}
+		xDataList = append(xDataList, tmp)
+	}
+	var edbIdList []int
 
-	_, yDataList, err = ProfitChartChartData(baseDataList, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, baseEdbInfo.EndDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN)
+	edbIdList, yDataList, err = ProfitChartChartData(baseEdbInfo, baseDataListMap, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, baseEdbInfo.EndDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN, reqEdbInfoIds)
 
-	tmpXDataList, newYDataList, err := handleProfitResultData(baseEdbInfo, yDataList, earliestDateTime)
+	// todo 最后处理数据
+	tmpXDataList, newYDataList, err := handleProfitResultData(xDataList, baseEdbInfo, yDataList, earliestDateTime, edbIdList)
 	if err != nil {
 		return
 	}
-	xDataList = []data_manage.XData{
-		{
-			Name:   "现货利润",
-			NameEn: "Spot Price",
-		},
+	if len(reqXDataList) == 0 {
+		xDataList = tmpXDataList
+	} else {
+		xDataList = reqXDataList
 	}
-	xDataList = append(xDataList, tmpXDataList...)
+
 	yDataList = newYDataList
 
 	return
 }
 
 // ProfitChartChartData 获取数据
-func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdbInfoMap map[int]map[string]*future_good.FutureGoodEdbInfo, futureGoodEdbDataListMap map[int][]*data_manage.EdbDataList, chartInfoDateList []request.ChartInfoDateReq, latestDate string, specialFutureGoodEdbInfoMap map[int]map[int]*future_good.FutureGoodEdbInfo, formulaStr string, tagEdbIdMap map[string]int, dateList []string, maxN int) (edbIdList []int, yDataList []data_manage.YData, err error) {
+func ProfitChartChartData(baseEdbInfo *data_manage.EdbInfo, baseDataListMap map[int][]*data_manage.EdbDataList, futureGoodEdbInfoMap map[int]map[string]*future_good.FutureGoodEdbInfo, futureGoodEdbDataListMap map[int][]*data_manage.EdbDataList, chartInfoDateList []request.ChartInfoDateReq, latestDate string, specialFutureGoodEdbInfoMap map[int]map[int]*future_good.FutureGoodEdbInfo, formulaStr string, tagEdbIdMap map[string]int, dateList []string, maxN int, reqEdbInfoIds []int) (edbIdList []int, yDataList []data_manage.YData, err error) {
 	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
 	//earliestDateTime time.Time
 	// ETA指标数据
-	baseEdbDateData := make(map[string]float64)
-	for _, edbData := range baseDataList {
-		baseEdbDateData[edbData.DataTime] = edbData.Value
+	allBaseEdbDateDataMap := make(map[int]map[string]float64)
+	for edbInfoId, baseDataList := range baseDataListMap {
+		baseEdbDateData := make(map[string]float64)
+		for _, edbData := range baseDataList {
+			baseEdbDateData[edbData.DataTime] = edbData.Value
+		}
+		allBaseEdbDateDataMap[edbInfoId] = baseEdbDateData
 	}
 
 	// 商品指标数据
@@ -243,23 +264,55 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			return
 		}
 
-		findDataList := make([]float64, 0) // 当前日期的数据值
-		noDataIdList := make([]int, 0)     // 没有数据的指标id
-		xEdbInfoIdList := make([]int, 0)   // 当前数据的指标id列表
+		findDataList := make([]float64, 0)  // 当前日期的数据值
+		noDataIdList := make([]int, 0)      // 没有数据的指标id
+		noDataIdMap := make(map[int]int, 0) // 没有数据的指标map
+		xEdbInfoIdList := make([]int, 0)    // 当前数据的指标id列表
 
 		// 现货指标
-		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataList, baseEdbDateData)
+		index := 0
+		var realDateTime time.Time
+		// 现货指标
+		baseEdbDateData, ok := allBaseEdbDateDataMap[baseEdbInfo.EdbInfoId]
+		if !ok {
+			err = fmt.Errorf("指标id: %d 没有数据", baseEdbInfo.EdbInfoId)
+			return
+		}
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataListMap[baseEdbInfo.EdbInfoId], baseEdbDateData, edbDataMap)
 		if tmpErr != nil {
 			err = tmpErr
 			return
 		}
-		findDataList = append(findDataList, findDataValue)
-		yDataMap[0] = findDataValue
 		if isFind {
 			maxDate = realDateTime
 		}
+		edbIdList = make([]int, 0) //普通指标ID
+		for _, edbInfoId := range reqEdbInfoIds {
+			if edbInfoId == baseEdbInfo.EdbInfoId {
+				findDataList = append(findDataList, findDataValue)
+				yDataMap[index] = findDataValue
+				xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
+				edbIdList = append(edbIdList, edbInfoId)
+				index += 1
+				continue
+			}
+			baseEdbDateDataTmp, ok := allBaseEdbDateDataMap[edbInfoId]
+			if !ok {
+				err = fmt.Errorf("指标id: %d 没有数据", edbInfoId)
+				return
+			}
+			findDataValueTmp, isFindTmp := baseEdbDateDataTmp[realDateTime.Format(utils.FormatDate)]
+			if !isFindTmp {
+				noDataIdList = append(noDataIdList, edbInfoId)
+				noDataIdMap[edbInfoId] = edbInfoId
+			}
+			findDataList = append(findDataList, findDataValueTmp)
+			yDataMap[index] = findDataValueTmp
 
-		xEdbInfoIdList = append(xEdbInfoIdList, 0)
+			xEdbInfoIdList = append(xEdbInfoIdList, edbInfoId)
+			edbIdList = append(edbIdList, edbInfoId)
+			index += 1
+		}
 
 		mList := make([]int, 0) // 间隔月份
 
@@ -274,7 +327,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			//findDateTime
 
 			// 获取当前日期相对开始日期的期数
-			tmpN := (currDate.Year()-findDateTime.Year())*12 + int(currDate.Month()-findDateTime.Month())
+			tmpN := (currDate.Year()-realDateTime.Year())*12 + int(currDate.Month()-realDateTime.Month())
 			if tmpN <= 0 {
 				continue
 			}
@@ -329,7 +382,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			//计算公式异常,那么就移除该指标
 			if formulaFormStr == `` {
 				//removeDateList = append(removeDateList, sk)
-				//fmt.Println("异常了")
+				fmt.Println("异常了")
 				continue
 			}
 
@@ -382,6 +435,33 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			yDate = maxDate.Format(utils.FormatDate)
 		}
 
+		{
+			hasDataIndexList := make([]int, 0)
+			for dataK, edbInfoId := range xEdbInfoIdList {
+				if _, ok := noDataIdMap[edbInfoId]; !ok { // 如果是没有数据的指标id
+					hasDataIndexList = append(hasDataIndexList, dataK)
+				}
+			}
+			lenHasDataIndex := len(hasDataIndexList)
+			if lenHasDataIndex > 0 {
+				for lenHasDataI := 1; lenHasDataI < lenHasDataIndex; lenHasDataI++ {
+					perK := hasDataIndexList[lenHasDataI-1] //上一个有数据的指标下标
+					currK := hasDataIndexList[lenHasDataI]  //当前有数据的指标下标
+					preVal := findDataList[perK]            //上一个有数据的坐标的值
+					currVal := findDataList[currK]          //当前有数据的指标的值
+
+					// 环差值
+					hcValDeci := decimal.NewFromFloat(currVal).Sub(decimal.NewFromFloat(preVal)).Div(decimal.NewFromInt(int64(currK - perK)))
+					var tmpI int64
+					// 将两个中间的数据做平均值补全
+					for hcI := perK + 1; hcI < currK; hcI++ {
+						tmpI++
+						findDataList[hcI], _ = decimal.NewFromFloat(preVal).Add(hcValDeci.Mul(decimal.NewFromInt(tmpI))).RoundCeil(4).Float64()
+					}
+				}
+			}
+		}
+
 		yDataList = append(yDataList, data_manage.YData{
 			Date:           yDate,
 			ConfigDate:     realDateTime,
@@ -473,29 +553,37 @@ func getProfitFutureGoodEdbInfoList(earliestDateTime time.Time, zlFutureGoodEdbI
 }
 
 // handleProfitResultData 处理成最终的结果数据
-func handleProfitResultData(baseEdbInfo *data_manage.EdbInfo, yDataList []data_manage.YData, earliestDateTime time.Time) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) {
-	xDataList = make([]data_manage.XData, 0)
+func handleProfitResultData(xDataListInit []data_manage.XData, baseEdbInfo *data_manage.EdbInfo, yDataList []data_manage.YData, earliestDateTime time.Time, allEdbInfoIds []int) (xDataList []data_manage.XData, newYDataList []data_manage.YData, err error) {
 	newYDataList = yDataList
+	xDataList = xDataListInit
 
 	nMap := make(map[int]int)
-
+	nList := make([]int, 0)
+	nListEdbMap := make(map[int]struct{})
 	for _, v := range yDataList {
 		for _, n := range v.XEdbInfoIdList {
-			nMap[n] = n
+			if utils.InArrayByInt(allEdbInfoIds, n) {
+				if _, ok := nListEdbMap[n]; !ok {
+					nList = append(nList, n)
+					nListEdbMap[n] = struct{}{}
+				}
+			} else {
+				nMap[n] = n
+			}
 		}
 	}
 
 	// 找出所有的N值,并进行正序排列
-	nList := make([]int, 0)
+	nListTmp := make([]int, 0)
 	for _, n := range nMap {
-		nList = append(nList, n)
+		nListTmp = append(nListTmp, n)
 	}
-	sort.Slice(nList, func(i, j int) bool {
-		return nList[i] < nList[j]
+	sort.Slice(nListTmp, func(i, j int) bool {
+		return nListTmp[i] < nListTmp[j]
 	})
-
+	nList = append(nList, nListTmp...)
 	for _, n := range nList {
-		if n == 0 {
+		if utils.InArrayByInt(allEdbInfoIds, n) {
 			continue
 		}
 		xDataList = append(xDataList, data_manage.XData{
@@ -516,7 +604,7 @@ func handleProfitResultData(baseEdbInfo *data_manage.EdbInfo, yDataList []data_m
 			if len(xEdbInfoIdList) > 0 {
 				currN := xEdbInfoIdList[0]
 				// 当前距离最早的日期相差的N数
-				if n == currN {
+				if n == currN { // todo 改成所有的基础现货指标
 					if needNum > 0 {
 						currVal := yData.Value[valIndex]
 						preVal := yData.Value[valIndex-1]
@@ -530,8 +618,12 @@ func handleProfitResultData(baseEdbInfo *data_manage.EdbInfo, yDataList []data_m
 							newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, tmpVal)
 						}
 					}
+					if utils.InArrayByInt(allEdbInfoIds, currN) {
+						newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN)
+					} else {
+						newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN+1)
+					}
 
-					newYDataList[yIndex].XEdbInfoIdList = append(newYDataList[yIndex].XEdbInfoIdList, currN+1)
 					newYDataList[yIndex].Value = append(newYDataList[yIndex].Value, yData.Value[valIndex])
 					valIndex++
 					needNum = 0
@@ -558,7 +650,7 @@ func handleProfitResultData(baseEdbInfo *data_manage.EdbInfo, yDataList []data_m
 	}
 
 	earliestDateTime = time.Date(earliestDateTime.Year(), earliestDateTime.Month(), 1, 0, 0, 0, 0, time.Local)
-	xDataList = xDataList[0:maxI]
+	xDataList = xDataList[0 : maxI+1]
 	for yIndex, yData := range newYDataList {
 		if len(yData.XEdbInfoIdList) > maxI+1 {
 			newYDataList[yIndex].XEdbInfoIdList = yData.XEdbInfoIdList[0 : maxI+1]
@@ -571,10 +663,11 @@ func handleProfitResultData(baseEdbInfo *data_manage.EdbInfo, yDataList []data_m
 
 		nameList := make([]string, 0)
 		enNameList := make([]string, 0)
-		for _, n := range newYDataList[yIndex].XEdbInfoIdList {
-			if n == 1 { // 现货价不处理
-				nameList = append(nameList, baseEdbInfo.EdbName)
-				enNameList = append(enNameList, baseEdbInfo.EdbNameEn)
+		for k1, n := range newYDataList[yIndex].XEdbInfoIdList {
+			if utils.InArrayByInt(allEdbInfoIds, n) { // 现货价不处理
+				tmpItem := xDataListInit[k1]
+				nameList = append(nameList, tmpItem.Name)
+				enNameList = append(enNameList, tmpItem.NameEn)
 				continue
 			}
 			if n <= 0 {
@@ -639,6 +732,7 @@ func ReplaceFormula(tagEdbIdMap map[string]int, valArr map[int]float64, formulaS
 	for k, v := range funMap {
 		formulaStr = strings.Replace(formulaStr, v, k, -1)
 	}
+	fmt.Println(formulaStr)
 	if replaceCount == len(tagEdbIdMap) {
 		return formulaStr
 	} else {

+ 22 - 0
services/report_v2.go

@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/file"
 	"github.com/rdlucklib/rdluck_tools/http"
+	"html"
 	"os"
 	"path"
 	"strconv"
@@ -1380,9 +1381,13 @@ func UpdateReportVideo(reportInfo *models.Report) {
 		if err != nil {
 			return
 		}
+
+		reportContent := ""
 		for _, chapter := range chapterList {
 			if chapter.PublishState == 2 {
 				reportChapterIdList = append(reportChapterIdList, chapter.ReportChapterId)
+				reportContent += chapter.Title + `。`
+				reportContent += chapter.Content + `。`
 			}
 		}
 		if len(reportChapterIdList) > 0 {
@@ -1391,6 +1396,23 @@ func UpdateReportVideo(reportInfo *models.Report) {
 				utils.FileLog.Info(fmt.Sprintf("%d报告音频生产失败:%s", reportInfo.Id, err.Error()))
 			}
 		}
+
+		// 生成汇总音频
+
+		{
+			if reportInfo.VideoUrl != "" && reportInfo.VideoName != "" && reportInfo.VideoSize != "" && reportInfo.VideoPlaySeconds != "" {
+				return
+			}
+			videoUrl, videoName, videoSize, videoPlaySeconds, e := CreateReportVideo(reportInfo.Title, html.UnescapeString(reportContent), time.Now().Format(utils.FormatDateTime))
+			if e != nil {
+				err = e
+				return
+			}
+
+			// 修改报告的音频信息
+			err = models.ModifyReportVideoByNoVideo(reportInfo.Id, videoUrl, videoName, videoSize, videoPlaySeconds)
+
+		}
 	} else {
 		err := CreateVideo(reportInfo)
 		if err != nil {