瀏覽代碼

Merge branch 'debug' of http://8.136.199.33:3000/eta_server/eta_mobile into bzq/sci_hq_custom_cf

zqbao 8 月之前
父節點
當前提交
32efcf5f66
共有 31 個文件被更改,包括 3543 次插入552 次删除
  1. 3 1
      .gitignore
  2. 139 0
      controllers/data_manage/chart_info.go
  3. 158 0
      controllers/data_manage/chart_info_section.go
  4. 20 1
      controllers/data_manage/edb_info.go
  5. 4 1
      controllers/data_manage/edb_info_calculate.go
  6. 430 61
      controllers/data_manage/future_good/future_good_chart_info.go
  7. 163 105
      controllers/data_manage/future_good/future_good_profit_chart_info.go
  8. 58 57
      controllers/target.go
  9. 13 1
      controllers/user_login.go
  10. 14 0
      models/data_manage/chart_edb_mapping.go
  11. 251 70
      models/data_manage/chart_info.go
  12. 305 0
      models/data_manage/chart_series.go
  13. 29 0
      models/data_manage/chart_series_edb_mapping.go
  14. 38 0
      models/data_manage/chart_type.go
  15. 21 2
      models/data_manage/edb_info.go
  16. 2 0
      models/data_manage/edb_info_calculate.go
  17. 28 0
      models/data_manage/edb_info_record.go
  18. 19 0
      models/data_manage/future_good/future_good_edb_info_data.go
  19. 2 0
      models/data_manage/future_good/request/future_good_chart.go
  20. 65 40
      models/data_manage/future_good_chart_info.go
  21. 4 1
      models/db.go
  22. 2 0
      models/system/sys_user.go
  23. 36 0
      routers/commentsRouter.go
  24. 711 2
      services/data/chart_extra_config.go
  25. 493 5
      services/data/chart_info.go
  26. 112 0
      services/data/cross_variety/chart.go
  27. 44 44
      services/data/edb_data.go
  28. 30 0
      services/data/edb_info_record.go
  29. 212 119
      services/data/future_good/chart_info.go
  30. 135 41
      services/data/future_good/profit_chart_info.go
  31. 2 1
      utils/constants.go

+ 3 - 1
.gitignore

@@ -7,4 +7,6 @@
 /.idea/
 /.DS_Store
 *.tar.gz
-*.exe
+eta_mobile.exe
+/*.exe
+*.exe

+ 139 - 0
controllers/data_manage/chart_info.go

@@ -4094,3 +4094,142 @@ func (this *ChartInfoController) ChartInfoConvertDetail() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// ChartInfoImgSetByBase64
+// @Title 图表图片上传
+// @Param   Img   query   string  true       "图片"
+// @Param   ChartInfoId   query   int  true       "图表ID"
+// @Success 200 {object} models.ResourceResp
+// @router /chart_info/image/set_by_base64 [post]
+func (this *ChartInfoController) ChartInfoImgSetByBase64() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	imgData := this.GetString("Img")
+	if imgData == "" {
+		br.Msg = "图片参数错误"
+		br.ErrMsg = "图片参数错误,Img Is Empty"
+		return
+	}
+	chartInfoId, _ := this.GetInt("ChartInfoId", 0)
+	if chartInfoId <= 0 {
+		br.Msg = "图片参数错误"
+		br.ErrMsg = "图片参数错误,Img Is Empty"
+		return
+	}
+	resp := new(models.ResourceResp)
+
+	uploadDir := "static/images/"
+	if !utils.FileIsExist(uploadDir) {
+		err := os.MkdirAll(uploadDir, utils.DIR_MOD)
+		if err != nil {
+			br.Msg = "图表保存失败"
+			br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	//var saveToOssPath string
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	var fileName, outFileName string
+	fileName = randStr + ".txt"
+	fileName = uploadDir + fileName
+	err := utils.SaveToFile(imgData, fileName)
+	if err != nil {
+		br.Msg = "图片保存失败"
+		br.ErrMsg = "图片保存失败,Err:" + err.Error()
+		return
+	}
+
+	// 删除临时存储的svg文件
+	defer func() {
+		err = os.Remove(fileName)
+		if err != nil {
+			utils.FileLog.Info("删除临时存储的svg文件失败, err: " + err.Error())
+		}
+	}()
+	outFileName = randStr + ".png"
+
+	doneChannel := make(chan bool, 1)
+	errorChannel := make(chan error, 1)
+
+	cmd := exec.Command("highcharts-export-server", "--infile", fileName, "--constr", "Chart", "--scale", "2", "--workers", "10", "--workLimit", "3", "--outfile", outFileName)
+
+	go func() {
+		output, err := cmd.CombinedOutput()
+		if err != nil {
+			utils.FileLog.Info("execute command failed, output: , error: \n" + string(output) + err.Error())
+			errorChannel <- err
+			return
+		}
+		doneChannel <- true
+	}()
+	defer func() {
+		_ = os.Remove(outFileName)
+		if err != nil {
+			utils.FileLog.Info("删除生产的图片文件失败, err: " + err.Error())
+		}
+	}()
+
+	select {
+	case <-time.After(30 * time.Second):
+		utils.FileLog.Info("执行超过30秒 杀死超时进程")
+		e := cmd.Process.Kill()
+		if e != nil {
+			fmt.Println("cmd kill err: ", e.Error())
+			utils.FileLog.Info(fmt.Sprintf("cmd kill err: %s", e.Error()))
+			br.Msg = "图片生成失败"
+			br.ErrMsg = "图片生成失败, 执行超时" + e.Error()
+			return
+		}
+		fmt.Println("timeout kill process")
+	case <-doneChannel:
+		fmt.Println("done")
+	case err := <-errorChannel:
+		br.Msg = "文件上传失败"
+		br.ErrMsg = fmt.Sprintf("execute command failure err: %s", err.Error())
+		fmt.Println("execute command failure err:" + err.Error())
+		return
+	}
+
+	//上传到阿里云 和 minio
+	resourceUrl := ``
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	// 修改图表的缩略图信息
+	if chartInfoId > 0 && resourceUrl != "" {
+		err = data_manage.EditChartInfoImageV2(chartInfoId, resourceUrl)
+		if err != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存失败,Err:" + err.Error()
+			return
+		}
+
+		//修改es数据
+		go data.EsAddOrEditChartInfo(chartInfoId)
+		//修改my eta es数据
+		go data.EsAddOrEditMyChartInfoByChartInfoId(chartInfoId)
+	}
+
+	resp.ResourceUrl = resourceUrl
+	resp.Source = "convert"
+	//resp.CacheKey = imgDataKey
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+	return
+}

+ 158 - 0
controllers/data_manage/chart_info_section.go

@@ -0,0 +1,158 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_mobile/models"
+	"eta/eta_mobile/models/data_manage"
+	"eta/eta_mobile/services/data"
+	"eta/eta_mobile/utils"
+	"strings"
+)
+
+// GetChartTypeList
+// @Title 获取所有图表类型
+// @Description 获取所有图表类型
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /chart_info/type_list [get]
+func (this *ChartInfoController) GetChartTypeList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	listTmp, err := data_manage.GetChartTypeList()
+	if err != nil {
+		br.Msg = "获取图表类型失败"
+		br.ErrMsg = "获取图表类型失败,Err:" + err.Error()
+		return
+	}
+	//遍历list,将id和name组成map
+	chartTypeMap := make(map[int][]data_manage.ChartType)
+	for _, v := range listTmp {
+		if v.ParentId > 0 {
+			chartTypeMap[v.ParentId] = append(chartTypeMap[v.ParentId], v)
+		}
+	}
+	list := make([]data_manage.ChartTypeList, 0)
+	for _, v := range listTmp {
+		if v.ParentId == 0 {
+			tmp := data_manage.ChartTypeList{
+				ChartTypeId:     v.ChartTypeId,
+				ChartTypeName:   v.ChartTypeName,
+				ChartTypeNameEn: v.ChartTypeNameEn,
+				ParentId:        v.ParentId,
+			}
+			child, ok := chartTypeMap[v.ChartTypeId]
+			if ok {
+				tmp.Child = child
+			}
+			list = append(list, tmp)
+		}
+	}
+
+	resp := data_manage.ChartTypeListResp{List: list}
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取图表类型成功"
+
+}
+
+// PreviewSectionCombineChartInfo
+// @Title 图表-获取预览的截面组合图数据
+// @Description 图表-获取预览的截面组合图数据
+// @Param	request	body data_manage.PreviewSectionCombineChartReq true "type json string"
+// @Success 200 {object} data_manage.ChartEdbInfoDetailResp
+// @router /chart_info/preview/section_combine [post]
+func (this *ChartInfoController) PreviewSectionCombineChartInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req data_manage.PreviewSectionCombineChartReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	chartInfo := new(data_manage.ChartInfoView)
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	chartType := utils.CHART_TYPE_SECTION_COMBINE
+	edbInfoIdArr, err, errMsg := data.CheckChartExtraConfig(chartType, req.ExtraConfig)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "添加失败:" + err.Error()
+		return
+	}
+	chartInfo.ChartType = chartType
+	mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdArr)
+
+	// 获取图表中的指标数据
+	edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetChartEdbData(0, chartType, "", "", "", mappingList, req.ExtraConfig, "")
+	if err != nil {
+		br.Msg = "获取失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	warnEdbList := make([]string, 0)
+	for _, v := range edbList {
+		if v.IsNullData {
+			warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")
+		}
+	}
+	if len(warnEdbList) > 0 {
+		chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
+	}
+
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, true)
+	//判断是否需要展示英文标识
+	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList, utils.CHART_SOURCE_DEFAULT, chartType)
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp := new(data_manage.ChartInfoDetailResp)
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.XEdbIdValue = xEdbIdValue
+	resp.YDataList = yDataList
+	resp.DataResp = dataResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 20 - 1
controllers/data_manage/edb_info.go

@@ -2430,6 +2430,11 @@ func (this *EdbInfoController) EdbInfoEdit() {
 		return
 	}
 
+	// 记录旧的指标基本信息
+	oldEdbName := edbInfo.EdbName
+	oldFrequency := edbInfo.Frequency
+	oldUnit := edbInfo.Unit
+
 	var haveOperaAuth bool
 	// 权限校验
 	{
@@ -2521,8 +2526,22 @@ func (this *EdbInfoController) EdbInfoEdit() {
 	//			}
 	//		}
 	//	}
-	//}
 
+	// 新增操作记录
+	{
+		oldEdbInfo := new(data_manage.EdbInfo)
+		oldEdbInfo.EdbInfoId = edbInfo.EdbInfoId
+		oldEdbInfo.EdbName = oldEdbName
+		oldEdbInfo.Frequency = oldFrequency
+		oldEdbInfo.Unit = oldUnit
+		newEdbInfoRecord := new(data_manage.EdbInfoEditRecord)
+		newEdbInfoRecord.EdbName = req.EdbName
+		newEdbInfoRecord.Frequency = req.Frequency
+		newEdbInfoRecord.Unit = req.Unit
+		newEdbInfoRecord.OperateUserId = sysUser.AdminId
+		newEdbInfoRecord.OperateUserRealName = sysUser.RealName
+		go data.AddEditEdbInfoRcord(oldEdbInfo, newEdbInfoRecord)
+	}
 	//新增操作日志
 	{
 		edbLog := new(data_manage.EdbInfoLog)

+ 4 - 1
controllers/data_manage/edb_info_calculate.go

@@ -9,11 +9,12 @@ import (
 	"eta/eta_mobile/services/data/data_manage_permission"
 	"eta/eta_mobile/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"net/url"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // 计算指标
@@ -848,6 +849,8 @@ func (this *ChartInfoController) CalculateBatchEdit() {
 		Frequency:     req.Frequency,
 		Unit:          req.Unit,
 		ClassifyId:    req.ClassifyId,
+		AdminId:       sysUser.AdminId,
+		AdminName:     sysUser.RealName,
 		Formula:       req.Formula, //N数值移动平均计算、环比值、环差值
 		FromEdbInfoId: req.FromEdbInfoId,
 		Source:        req.Source,

+ 430 - 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
@@ -606,7 +611,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 = "参数解析异常!"
@@ -1289,8 +1294,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()
@@ -1303,7 +1308,7 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 		return
 	}
 
-	if edbInfoMapping == nil {
+	if len(edbInfoMappingList) == 0 {
 		br.Msg = "请选择ETA指标"
 		br.ErrMsg = "请选择ETA指标"
 		br.IsSendEmail = false
@@ -1317,16 +1322,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 = "商品价格曲线图未配置"
@@ -1339,10 +1346,24 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 		return
 	}
 
-	barChartInfoDateList = barConfig.DateList
+	baseEdbInfoId := barConfig.BaseEdbInfoId
+	var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+	// todo 兼容历史数据,
+	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()
@@ -1410,7 +1431,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
@@ -1492,8 +1513,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
@@ -1627,7 +1648,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()
@@ -1641,8 +1662,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 = "商品价格曲线图未配置"
@@ -1656,10 +1676,25 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		return
 	}
 
-	barChartInfoDateList = barConfig.DateList
+	baseEdbInfoId := barConfig.BaseEdbInfoId
+	var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+	// todo 兼容历史数据,
+	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()
@@ -1671,7 +1706,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		errMsg = "商品价格曲线图表异常"
 		return
 	}
-	baseEdbInfo := edbList[0] //现货指标
+	baseEdbInfo := baseEdbInfoMapping //现货指标
 
 	for _, v := range edbList {
 		if v.IsNullData {
@@ -2073,16 +2108,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 {
@@ -2093,8 +2125,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 = "商品价格曲线图未配置"
@@ -2108,8 +2139,6 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			return
 		}
 
-		barChartInfoDateList = barConfig.DateList
-
 		startDate := chartInfo.StartDate
 		endDate := chartInfo.EndDate
 
@@ -2123,8 +2152,24 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			}
 		}
 
+		baseEdbInfoId := barConfig.BaseEdbInfoId
+		var baseEdbInfoMapping *data_manage.ChartEdbInfoMapping
+		// todo 兼容历史数据,
+		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()
@@ -2136,7 +2181,7 @@ func (this *FutureGoodChartInfoController) BaseChartInfoDetailFromUniqueCode() {
 			br.ErrMsg = "商品价格曲线图表异常"
 			return
 		}
-		baseEdbInfo := edbList[0] //现货指标
+		baseEdbInfo := baseEdbInfoMapping //现货指标
 
 		for _, v := range edbList {
 			if v.IsNullData {
@@ -2182,10 +2227,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
@@ -2895,7 +2942,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 = "参数解析异常!"
@@ -2919,21 +2966,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 {
@@ -2949,7 +3018,7 @@ func (this *FutureGoodChartInfoController) PreviewBarChartInfo() {
 		}
 	}
 
-	if edbInfoMapping == nil {
+	if len(edbInfoMappingList) == 0 {
 		br.Msg = "请选择ETA指标"
 		br.ErrMsg = "请选择ETA指标"
 		br.IsSendEmail = false
@@ -2962,8 +3031,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()
@@ -2992,7 +3070,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
@@ -3025,7 +3103,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 = "参数解析异常!"
@@ -3065,19 +3143,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 = "获取图表信息失败!"
@@ -3085,10 +3166,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 != "" {
@@ -3122,7 +3246,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 {
@@ -3134,7 +3310,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 = "获取图表信息失败!"
@@ -3144,7 +3320,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
 			}
 
@@ -3173,7 +3349,59 @@ 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)
+		}
+		err = data_manage.EditBaseFutureGoodProfitChartInfoAndEdbEnInfo(chartItem, &req, this.Lang)
 	default:
 		br.Msg = "错误的图表类型"
 		br.ErrMsg = "错误的图表类型"
@@ -3192,7 +3420,9 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 	go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
 
 	//指标 修改es信息
-	go data.AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+	for _, v := range edbIds {
+		go data.AddOrEditEdbInfoToEs(v)
+	}
 
 	//新增操作日志
 	{
@@ -3221,3 +3451,142 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 	br.Msg = "编辑成功"
 	br.IsAddLog = true
 }
+
+// ChartInfoImgSetByBase64
+// @Title 图表图片上传
+// @Param   Img   query   string  true       "图片"
+// @Param   ChartInfoId   query   int  true       "图表ID"
+// @Success 200 {object} models.ResourceResp
+// @router /chart_info/image/set_by_base64 [post]
+func (this *FutureGoodChartInfoController) ChartInfoImgSetByBase64() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	imgData := this.GetString("Img")
+	if imgData == "" {
+		br.Msg = "图片参数错误"
+		br.ErrMsg = "图片参数错误,Img Is Empty"
+		return
+	}
+	chartInfoId, _ := this.GetInt("ChartInfoId", 0)
+	if chartInfoId <= 0 {
+		br.Msg = "图片参数错误"
+		br.ErrMsg = "图片参数错误,Img Is Empty"
+		return
+	}
+	resp := new(models.ResourceResp)
+
+	uploadDir := "static/images/"
+	if !utils.FileIsExist(uploadDir) {
+		err := os.MkdirAll(uploadDir, utils.DIR_MOD)
+		if err != nil {
+			br.Msg = "图表保存失败"
+			br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	//var saveToOssPath string
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	var fileName, outFileName string
+	fileName = randStr + ".txt"
+	fileName = uploadDir + fileName
+	err := utils.SaveToFile(imgData, fileName)
+	if err != nil {
+		br.Msg = "图片保存失败"
+		br.ErrMsg = "图片保存失败,Err:" + err.Error()
+		return
+	}
+
+	// 删除临时存储的svg文件
+	defer func() {
+		err = os.Remove(fileName)
+		if err != nil {
+			utils.FileLog.Info("删除临时存储的svg文件失败, err: " + err.Error())
+		}
+	}()
+	outFileName = randStr + ".png"
+
+	doneChannel := make(chan bool, 1)
+	errorChannel := make(chan error, 1)
+
+	cmd := exec.Command("highcharts-export-server", "--infile", fileName, "--constr", "Chart", "--scale", "2", "--workers", "10", "--workLimit", "3", "--outfile", outFileName)
+
+	go func() {
+		output, err := cmd.CombinedOutput()
+		if err != nil {
+			utils.FileLog.Info("execute command failed, output: , error: \n" + string(output) + err.Error())
+			errorChannel <- err
+			return
+		}
+		doneChannel <- true
+	}()
+	defer func() {
+		_ = os.Remove(outFileName)
+		if err != nil {
+			utils.FileLog.Info("删除生产的图片文件失败, err: " + err.Error())
+		}
+	}()
+
+	select {
+	case <-time.After(30 * time.Second):
+		utils.FileLog.Info("执行超过30秒 杀死超时进程")
+		e := cmd.Process.Kill()
+		if e != nil {
+			fmt.Println("cmd kill err: ", e.Error())
+			utils.FileLog.Info(fmt.Sprintf("cmd kill err: %s", e.Error()))
+			br.Msg = "图片生成失败"
+			br.ErrMsg = "图片生成失败, 执行超时" + e.Error()
+			return
+		}
+		fmt.Println("timeout kill process")
+	case <-doneChannel:
+		fmt.Println("done")
+	case err := <-errorChannel:
+		br.Msg = "文件上传失败"
+		br.ErrMsg = fmt.Sprintf("execute command failure err: %s", err.Error())
+		fmt.Println("execute command failure err:" + err.Error())
+		return
+	}
+
+	//上传到阿里云 和 minio
+	resourceUrl := ``
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	// 修改图表的缩略图信息
+	if chartInfoId > 0 && resourceUrl != "" {
+		err = data_manage.EditChartInfoImageV2(chartInfoId, resourceUrl)
+		if err != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存失败,Err:" + err.Error()
+			return
+		}
+
+		//修改es数据
+		go data.EsAddOrEditChartInfo(chartInfoId)
+		//修改my eta es数据
+		go data.EsAddOrEditMyChartInfoByChartInfoId(chartInfoId)
+	}
+
+	resp.ResourceUrl = resourceUrl
+	resp.Source = "convert"
+	//resp.CacheKey = imgDataKey
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+	return
+}

+ 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()
@@ -445,6 +459,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 = "商品利润曲线图信息异常"
@@ -454,34 +471,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)
@@ -549,26 +573,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,
@@ -593,7 +618,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()
@@ -911,9 +936,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()
@@ -921,25 +966,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 {
@@ -991,15 +1038,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 = "获取失败"
@@ -1235,15 +1285,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 = "获取失败"
@@ -1283,7 +1342,6 @@ func GetFutureGoodProfitChartInfoDetailFromUniqueCode(chartInfo *data_manage.Cha
 	}
 
 	warnEdbList := make([]string, 0)
-	baseEdbInfo := edbList[0] //现货指标
 
 	for _, v := range edbList {
 		if v.IsNullData {

+ 58 - 57
controllers/target.go

@@ -922,6 +922,63 @@ func (this *TargetController) ImportData() {
 					if strings.Contains(closeVal, "#N/A") {
 						continue
 					}
+
+					//校验表格中的日期格式
+					if strings.Contains(createDate, "-") {
+						//如果是带有 - 的普通日期格式文本
+						_, timeErr := time.Parse("2006-1-2", createDate)
+						if timeErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+					} else if strings.Contains(createDate, "/") {
+						//如果是带有 / 的普通日期格式文本
+						createDateTime, timeErr := time.Parse("2006/1/2", createDate)
+						if timeErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+						createDate = createDateTime.Format("2006-01-02")
+					} else {
+						//可能是excel的日期格式
+						_, tmpErr := strconv.Atoi(createDate)
+						if tmpErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+						createDate = utils.ConvertToFormatDay(createDate) //录入日期
+					}
+
 					closeValFloat, err := cells[3].Float() //值
 
 					if err != nil {
@@ -981,62 +1038,6 @@ func (this *TargetController) ImportData() {
 					}
 					//fmt.Println(classifyName, createDate, secName, closeVal)
 
-					//校验表格中的日期格式
-					if strings.Contains(createDate, "-") {
-						//如果是带有 - 的普通日期格式文本
-						_, timeErr := time.Parse("2006-1-2", createDate)
-						if timeErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-					} else if strings.Contains(createDate, "/") {
-						//如果是带有 / 的普通日期格式文本
-						createDateTime, timeErr := time.Parse("2006/1/2", createDate)
-						if timeErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-						createDate = createDateTime.Format("2006-01-02")
-					} else {
-						//可能是excel的日期格式
-						_, tmpErr := strconv.Atoi(createDate)
-						if tmpErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-						createDate = utils.ConvertToFormatDay(createDate) //录入日期
-					}
-
 					//获取指标分类信息
 					classify, ok := edbDataClassifyMap[classifyName]
 					if !ok {
@@ -1273,7 +1274,7 @@ func (this *TargetController) ImportFailListDownload() {
 		row.AddCell().SetValue(v.ClassifyName)
 		row.AddCell().SetValue(v.CreateDate)
 		row.AddCell().SetValue(v.SecName)
-		row.AddCell().SetValue(v.Close)
+		row.AddCell().SetString(v.Close)
 		row.AddCell().SetValue(v.Frequency)
 		row.AddCell().SetValue(v.Unit)
 		row.AddCell().SetValue(v.Remark)

+ 13 - 1
controllers/user_login.go

@@ -558,6 +558,8 @@ func (this *UserLoginController) Login() {
 	}
 	resp.ProductName = productName
 	resp.Authority = sysUser.Authority
+	resp.DepartmentName = sysUser.DepartmentName
+	resp.GroupName = sysUser.GroupName
 
 	// 设置redis缓存
 	{
@@ -934,6 +936,7 @@ func (this *UserLoginController) CheckUserLdap() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
+
 	type CheckUserLdapReq struct {
 		UserName string `description:"用户名"`
 	}
@@ -1031,6 +1034,13 @@ func (this *UserLoginController) BaseInfo() {
 		return
 	}
 
+	companyName, e := models.GetBusinessConfByKey("CompanyName")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+
 	type BaseInfoResp struct {
 		Icp           *models.BusinessConf `description:"Icp信息"`
 		ETATitle      *models.BusinessConf `description:"eta系统名称"`
@@ -1038,6 +1048,7 @@ func (this *UserLoginController) BaseInfo() {
 		LogoCn        *models.BusinessConf `description:"中文logo"`
 		LogoEn        *models.BusinessConf `description:"英文logo"`
 		LogoMobile    *models.BusinessConf `description:"移动端logo"`
+		CompanyName   *models.BusinessConf `description:"公司名称"`
 	}
 
 	resp := BaseInfoResp{
@@ -1047,10 +1058,11 @@ func (this *UserLoginController) BaseInfo() {
 		LogoCn:        logoCn,
 		LogoEn:        logoEn,
 		LogoMobile:    logoMobile,
+		CompanyName:   companyName,
 	}
 
 	br.Data = resp
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
-}
+}

+ 14 - 0
models/data_manage/chart_edb_mapping.go

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

+ 251 - 70
models/data_manage/chart_info.go

@@ -262,6 +262,11 @@ type EditChartInfoReq struct {
 	UnitEn               string                  `description:"英文单位名称"`
 }
 
+type EditFutureGoodChartInfoReq struct {
+	EditChartInfoReq
+	BarChartInfo FutureGoodBarChartInfoReq
+}
+
 type EditChartEnInfoReq struct {
 	ChartInfoId      int                       `description:"图表ID"`
 	ChartNameEn      string                    `description:"英文图表名称"`
@@ -698,10 +703,22 @@ type ChartInfoDetailResp struct {
 	DataResp             interface{}      `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
 }
 
+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:"图表数据,根据图的类型而定的,没有确定的数据格式"`
+}
+
 // XData 商品价格曲线的的x轴数据
 type XData struct {
 	Name   string `description:"别名"`
 	NameEn string `description:"英文别名"`
+	IsHide int    `description:"是否隐藏,0不隐藏,1隐藏"`
 }
 
 // YData 柱方图的y轴数据
@@ -1059,7 +1076,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 {
@@ -1392,6 +1409,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年"`
@@ -1609,6 +1631,17 @@ type ChartInfoDetailFromUniqueCodeResp struct {
 	CorrelationChartInfo *CorrelationInfo `description:"相关性图表信息"`
 	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")
@@ -1911,6 +1944,13 @@ type BarChartInfoReq struct {
 	UnitEn        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"`
@@ -1922,6 +1962,7 @@ type BarChartInfoEdbItemReq struct {
 	ConvertValue  float64 `description:"数据转换值"`
 	ConvertUnit   string  `description:"数据转换单位"`
 	ConvertEnUnit string  `description:"数据转换单位"`
+	IsHide        int     `description:"是否隐藏该项,0不隐藏,1隐藏"`
 }
 
 // BarChartInfoDateReq 柱方图预览请求数据(日期相关)
@@ -2354,6 +2395,215 @@ type RadarYData struct {
 	Value []float64 `description:"每个指标的值"`
 }
 
+// EditChartInfoImageV2
+// @Description: 修改图表的缩略图
+// @author: Roc
+// @datetime 2024-07-09 10:52:34
+// @param chartInfoId int
+// @param imageUrl string
+// @return err error
+func EditChartInfoImageV2(chartInfoId int, imageUrl string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+
+	sql := ` UPDATE  chart_info SET chart_image=?, modify_time = NOW() WHERE chart_info_id = ? `
+	_, err = o.Raw(sql, imageUrl, chartInfoId).Exec()
+	if err != nil {
+		fmt.Println("EditChartInfoImageV2 Err:", err.Error())
+		return err
+	}
+
+	return
+}
+
+// 截面组合图额外配置
+type ChartSectionExtraConf struct {
+	DateConfList        []*ChartSectionDateConfItem
+	IsHeap              int                      `description:"是否堆积(1.堆积,0不堆积)"`
+	XDataList           []XData                  `description:"横轴名称设置"`
+	UnitList            *ChartSectionCombineUnit `description:"纵轴单位设置"`
+	BaseChartSeriesName string                   `description:"基准系列名称"`
+	SortType            int                      `description:"排序类型,0默认,1升序,2降序"`
+}
+
+// 截面组合图额外配置
+type ChartSectionAllExtraConf struct {
+	ChartSectionExtraConf
+	SeriesList []*ChartSectionSeriesItem
+}
+
+type ChartSectionDateConfItem struct {
+	MoveForward    int    `description:"前移的期数"`
+	EdbInfoId      int    `description:"指标ID"`
+	EdbName        string `description:"指标名称"`
+	EdbNameEn      string `description:"指标名称英文"`
+	EdbInfoType    int    `description:"指标类型"`
+	Frequency      string `description:"频度"`
+	EndDate        string `description:"最新日期"`
+	DateType       int    `description:"日期类型:0 指标日期,1系统日期"`
+	DateConfName   string `description:"引用日期名称"` // 引用日期名称不能重复
+	DateConfNameEn string `description:"引用日期英文名称"`
+	DateChange     []*ChartSectionDateChange
+}
+
+// 截面组合图引用日期配置
+type ChartSectionDateChange struct {
+	Year         int
+	Month        int
+	Day          int
+	Frequency    string `description:"频度变换"`
+	FrequencyDay string `description:"频度的固定日期"`
+	ChangeType   int    `description:"日期变换类型1日期位移,2指定频率"`
+}
+
+// 截面组合图系列配置
+type ChartSectionSeriesItem struct {
+	ChartSeriesId int     `description:"系列ID"`
+	SeriesName    string  `description:"系列名称"` //系列名称不可同名
+	SeriesNameEn  string  `description:"系列英文名称"`
+	ChartStyle    string  `description:"图表类型"`
+	ChartColor    string  `description:"颜色"`
+	ChartWidth    int     `description:"线条大小"`
+	IsPoint       int     `description:"是否用数据点展示(0 否,1是)"`
+	IsNumber      int     `description:"是否用数值展示(0 否,1是)"`
+	IsAxis        int     `description:"1:左轴,0:右轴"`
+	MaxData       float64 `description:"上限"`
+	MinData       float64 `description:"下限"`
+	//IsOrder         bool    `description:"true:正序,false:逆序"`
+	EdbInfoList    []*ChartSectionSeriesEdbConf
+	DataList       []float64
+	NoDataEdbIndex []int
+}
+type ChartSectionSeriesEdbConf struct {
+	ChartSeriesEdbMappingId int `description:"映射ID"`
+	ChartSeriesId           int `description:"系列ID"`
+	//ChartInfoId             int `description:"图表ID"`
+	EdbInfoId    int `description:"指标id"`
+	DateConf     *ChartSectionSeriesDateConfItem
+	EdbName      string `description:"中文别名"`
+	EdbNameEn    string `description:"英文别名"`
+	EdbInfoType  int    `description:"指标类型"`
+	Unit         string `description:"单位"`
+	UnitEn       string `description:"英文单位"`
+	DateConfName string `description:"引用日期名称"`
+	DateConfType int    `description:"日期类型,0指标最新日期, 1引用日期"`
+}
+
+type ChartSectionCombineDataResp struct {
+	DateConfList        []*ChartSectionDateConfItem
+	IsHeap              int                      `description:"是否堆积(1.堆积,0不堆积)"`
+	XDataList           []XData                  `description:"横轴名称设置"`
+	UnitList            *ChartSectionCombineUnit `description:"纵轴单位设置"`
+	BaseChartSeriesName string                   `description:"基准系列名称"`
+	SortType            int                      `description:"排序类型,0默认,1升序,2降序"`
+	SeriesList          []*ChartSectionSeriesItem
+	LeftMin             string `description:"图表左侧最小值"`
+	LeftMax             string `description:"图表左侧最大值"`
+	RightMin            string `description:"图表右侧最小值"`
+	RightMax            string `description:"图表右侧最大值"`
+	Right2Min           string `description:"图表右侧最小值"`
+	Right2Max           string `description:"图表右侧最大值"`
+}
+
+// 系列里的指标日期配置
+type ChartSectionSeriesDateConfItem struct {
+	MoveForward int `description:"前移的期数"`
+	DateChange  []*ChartSectionDateChange
+}
+
+// PreviewSectionCombineChartReq 预览截面组合图的请求
+type PreviewSectionCombineChartReq struct {
+	ChartName       string `description:"图表名称"`
+	ChartClassifyId int    `description:"分类id"`
+	ExtraConfig     string `description:"图表额外配置信息,json字符串"`
+}
+
+type ChartSectionCombineUnit struct {
+	LeftName       string `description:"左轴单位"`
+	LeftNameEn     string `description:"左轴英文单位"`
+	RightName      string `description:"右轴单位"`
+	RightNameEn    string `description:"右轴英文单位"`
+	RightTwoName   string `description:"右2轴单位"`
+	RightTwoNameEn string `description:"右2轴英文单位"`
+}
+
+// 时序组合图额外配置
+type ChartTimeCombineExtraConf struct {
+	IsHeap int `description:"是否堆积(1.堆积,0不堆积)"`
+}
+
+type ChartTimeCombineDataResp struct {
+	IsHeap int `description:"是否堆积(1.堆积,0不堆积)"`
+}
+
+func getThsHfEdbDataListByMongo(source, subSource, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	list = make([]*EdbDataList, 0)
+
+	mogDataObj := mgo.EdbDataThsHf{}
+	// 构建查询条件
+	queryConditions := bson.M{
+		"edb_info_id": edbInfoId,
+	}
+
+	// 数据日期
+	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
+	if err != nil {
+		return
+	}
+	if len(dateCondition) > 0 {
+		queryConditions["data_time"] = dateCondition
+	}
+
+	// 获取列表数据
+	tmpDataList, tmpErr := mogDataObj.GetAllDataList(queryConditions, []string{"data_time"})
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	for k, v := range tmpDataList {
+		list = append(list, &EdbDataList{
+			EdbDataId:     k + 1,
+			EdbInfoId:     v.EdbInfoId,
+			DataTime:      v.DataTime.Format(utils.FormatDate),
+			DataTimestamp: v.DataTimestamp,
+			Value:         v.Value,
+		})
+	}
+	return
+}
+
+func getThsHfEdbDataListMinAndMaxByMongo(source, subSource, edbInfoId int, startDate, endDate string) (minData, maxData float64, err error) {
+	mogDataObj := mgo.EdbDataThsHf{}
+	// 构建查询条件
+	queryConditions := bson.M{
+		"edb_info_id": edbInfoId,
+	}
+	// 日期
+	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
+	if err != nil {
+		return
+	}
+	if len(dateCondition) > 0 {
+		queryConditions["data_time"] = dateCondition
+	}
+
+	pipeline := []bson.M{
+		{"$match": queryConditions},
+		{"$group": bson.M{
+			"_id":       nil,
+			"min_value": bson.M{"$min": "$value"},
+			"max_value": bson.M{"$max": "$value"},
+		}},
+		{"$project": bson.M{"_id": 0}}, // 可选,如果不需要_id字段
+	}
+	result, err := mogDataObj.GetEdbInfoMaxAndMinInfo(pipeline)
+	if err != nil {
+		return
+	}
+	minData = result.MinValue
+	maxData = result.MaxValue
+	return
+}
+
 type MarkersLine struct {
 	Axis             int             `json:"axis" description:"1左轴 2右轴 3横轴"`
 	AxisName         string          `json:"axisName" description:"轴的名称,例如'左轴'"`
@@ -2505,72 +2755,3 @@ type MaxMinLimitsData struct {
 	MaxValue      float64 `description:"最大值"`
 	MinValue      float64 `description:"最小值"`
 }
-
-func getThsHfEdbDataListByMongo(source, subSource, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
-	list = make([]*EdbDataList, 0)
-
-	mogDataObj := mgo.EdbDataThsHf{}
-	// 构建查询条件
-	queryConditions := bson.M{
-		"edb_info_id": edbInfoId,
-	}
-
-	// 数据日期
-	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
-	if err != nil {
-		return
-	}
-	if len(dateCondition) > 0 {
-		queryConditions["data_time"] = dateCondition
-	}
-
-	// 获取列表数据
-	tmpDataList, tmpErr := mogDataObj.GetAllDataList(queryConditions, []string{"data_time"})
-	if tmpErr != nil {
-		err = tmpErr
-		return
-	}
-	for k, v := range tmpDataList {
-		list = append(list, &EdbDataList{
-			EdbDataId:     k + 1,
-			EdbInfoId:     v.EdbInfoId,
-			DataTime:      v.DataTime.Format(utils.FormatDate),
-			DataTimestamp: v.DataTimestamp,
-			Value:         v.Value,
-		})
-	}
-	return
-}
-
-func getThsHfEdbDataListMinAndMaxByMongo(source, subSource, edbInfoId int, startDate, endDate string) (minData, maxData float64, err error) {
-	mogDataObj := mgo.EdbDataThsHf{}
-	// 构建查询条件
-	queryConditions := bson.M{
-		"edb_info_id": edbInfoId,
-	}
-	// 日期
-	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
-	if err != nil {
-		return
-	}
-	if len(dateCondition) > 0 {
-		queryConditions["data_time"] = dateCondition
-	}
-
-	pipeline := []bson.M{
-		{"$match": queryConditions},
-		{"$group": bson.M{
-			"_id":       nil,
-			"min_value": bson.M{"$min": "$value"},
-			"max_value": bson.M{"$max": "$value"},
-		}},
-		{"$project": bson.M{"_id": 0}}, // 可选,如果不需要_id字段
-	}
-	result, err := mogDataObj.GetEdbInfoMaxAndMinInfo(pipeline)
-	if err != nil {
-		return
-	}
-	minData = result.MinValue
-	maxData = result.MaxValue
-	return
-}

+ 305 - 0
models/data_manage/chart_series.go

@@ -0,0 +1,305 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ChartSeries struct {
+	ChartSeriesId int       `orm:"column(chart_series_id);pk"`
+	SeriesName    string    `description:"系列名称"`
+	SeriesNameEn  string    `description:"系列英文名称"`
+	ChartInfoId   int       `description:"图表ID"`
+	ChartStyle    string    `description:"图表类型"`
+	ChartColor    string    `description:"颜色"`
+	ChartWidth    int       `description:"线条大小"`
+	IsPoint       int       `description:"是否用数据点展示(0 否,1是)"`
+	IsNumber      int       `description:"是否用数值展示(0 否,1是)"`
+	IsAxis        int       `description:"1:左轴,0:右轴"`
+	MaxData       float64   `description:"上限"`
+	MinData       float64   `description:"下限"`
+	IsOrder       bool      `description:"true:正序,false:逆序"`
+	CreateTime    time.Time `description:"创建时间"`
+	ModifyTime    time.Time `description:"修改时间"`
+}
+
+func (c *ChartSeries) TableName() string {
+	return "chart_series"
+}
+
+func GetChartSeriesByChartInfoId(chartInfoId int) (items []*ChartSeries, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM chart_series WHERE chart_info_id = ?"
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&items)
+	return
+}
+
+// EditChartSeriesAndEdbMapping
+func EditChartSeriesAndEdbMapping(extraConfigStr string, chartInfoId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 获取已经存在的系列
+	series, err := GetChartSeriesByChartInfoId(chartInfoId)
+	if err != nil {
+		return
+	}
+	//整理成系列map
+	seriesMap := make(map[int]struct{})
+	seriesDeleteMap := make(map[int]struct{})
+	for _, v := range series {
+		seriesMap[v.ChartSeriesId] = struct{}{}
+		seriesDeleteMap[v.ChartSeriesId] = struct{}{}
+	}
+	var sectionExtraConfig ChartSectionAllExtraConf
+	err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfig)
+	if err != nil {
+		err = fmt.Errorf("截面组合图配置异常")
+		return
+	}
+
+	// 删除所有的指标映射
+	_, err = o.Raw("DELETE FROM chart_series_edb_mapping WHERE chart_info_id = ?", chartInfoId).Exec()
+	if err != nil {
+		return
+	}
+
+	seriesList := sectionExtraConfig.SeriesList
+	for _, v := range seriesList {
+		seriesId := v.ChartSeriesId
+		tmp := &ChartSeries{
+			ChartSeriesId: v.ChartSeriesId,
+			SeriesName:    v.SeriesName,
+			SeriesNameEn:  v.SeriesNameEn,
+			ChartInfoId:   chartInfoId,
+			ChartStyle:    v.ChartStyle,
+			ChartColor:    v.ChartColor,
+			ChartWidth:    v.ChartWidth,
+			IsPoint:       v.IsPoint,
+			IsNumber:      v.IsNumber,
+			IsAxis:        v.IsAxis,
+			MaxData:       v.MaxData,
+			MinData:       v.MinData,
+			ModifyTime:    time.Now(),
+		}
+		if _, ok := seriesMap[v.ChartSeriesId]; !ok {
+			if seriesId > 0 {
+				err = fmt.Errorf("系列ID错误")
+				return
+			}
+			//新增
+			tmp.CreateTime = time.Now()
+			seriesIdTmp, e := to.Insert(tmp)
+			if e != nil {
+				err = fmt.Errorf("AddChartSeries Err:" + e.Error())
+				return
+			}
+			seriesId = int(seriesIdTmp)
+		} else {
+			//编辑
+			delete(seriesDeleteMap, v.ChartSeriesId)
+			_, e := to.Update(tmp)
+			if e != nil {
+				err = fmt.Errorf("UpdateChartSeries Err:" + e.Error())
+				return
+			}
+		}
+
+		addSeriesEdbList := make([]*ChartSeriesEdbMapping, 0)
+		for _, edbItem := range v.EdbInfoList {
+			dateConfStrByte, e := json.Marshal(edbItem.DateConf)
+			if e != nil {
+				err = e
+				return
+			}
+			dateConfStr := string(dateConfStrByte)
+			edbTmp := &ChartSeriesEdbMapping{
+				ChartSeriesId: seriesId,    //todo 系列ID
+				ChartInfoId:   chartInfoId, //todo 表图ID
+				EdbInfoId:     edbItem.EdbInfoId,
+				//EdbAliasName:            "",
+				//EdbAliasNameEn:          "",
+				DateConfName: edbItem.DateConfName,
+				DateConf:     dateConfStr,
+				DateConfType: edbItem.DateConfType,
+				CreateTime:   time.Now(),
+				ModifyTime:   time.Now(),
+			}
+			addSeriesEdbList = append(addSeriesEdbList, edbTmp)
+		}
+		if len(addSeriesEdbList) > 0 {
+			_, err = to.InsertMulti(len(addSeriesEdbList), addSeriesEdbList)
+			if err != nil {
+				err = fmt.Errorf("AddChartSeries Err:" + err.Error())
+				return
+			}
+		}
+	}
+	//删除旧的系列和ID
+	seriesIds := make([]int, 0)
+	for id, _ := range seriesDeleteMap {
+		seriesIds = append(seriesIds, id)
+	}
+	if len(seriesIds) > 0 {
+		sql := `DELETE FROM chart_series WHERE chart_series_id IN (` + utils.GetOrmInReplace(len(seriesIds)) + `) and chart_info_id=?`
+		_, err = to.Raw(sql, seriesIds, chartInfoId).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除系列失败 Err:" + err.Error())
+			return
+		}
+		sql = `DELETE FROM chart_series_edb_mapping WHERE chart_series_id IN (` + utils.GetOrmInReplace(len(seriesIds)) + `) and chart_info_id=?`
+		_, err = to.Raw(sql, seriesIds, chartInfoId).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除系列指标 Err:" + err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+func AddChartSeriesAndEdbMapping(extraConfigStr string, chartInfoId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	var sectionExtraConfig ChartSectionAllExtraConf
+	err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfig)
+	if err != nil {
+		err = fmt.Errorf("截面组合图配置异常")
+		return
+	}
+	seriesList := sectionExtraConfig.SeriesList
+	for _, v := range seriesList {
+		tmp := &ChartSeries{
+			SeriesName:   v.SeriesName,
+			SeriesNameEn: v.SeriesNameEn,
+			ChartInfoId:  chartInfoId,
+			ChartStyle:   v.ChartStyle,
+			ChartColor:   v.ChartColor,
+			ChartWidth:   v.ChartWidth,
+			IsPoint:      v.IsPoint,
+			IsNumber:     v.IsNumber,
+			IsAxis:       v.IsAxis,
+			MaxData:      v.MaxData,
+			MinData:      v.MinData,
+			IsOrder:      false, //todo 是否排序
+			CreateTime:   time.Now(),
+			ModifyTime:   time.Now(),
+		}
+		seriesIdTmp, e := to.Insert(tmp)
+		if e != nil {
+			err = fmt.Errorf("AddChartSeries Err:" + e.Error())
+			return
+		}
+		seriesId := int(seriesIdTmp)
+		addSeriesEdbList := make([]*ChartSeriesEdbMapping, 0)
+		for _, edbItem := range v.EdbInfoList {
+			dateConfStrByte, e := json.Marshal(edbItem.DateConf)
+			if e != nil {
+				err = e
+				return
+			}
+			dateConfStr := string(dateConfStrByte)
+			edbTmp := &ChartSeriesEdbMapping{
+				ChartSeriesId: seriesId,    //todo 系列ID
+				ChartInfoId:   chartInfoId, //todo 表图ID
+				EdbInfoId:     edbItem.EdbInfoId,
+				//EdbAliasName:            "",
+				//EdbAliasNameEn:          "",
+				DateConfName: edbItem.DateConfName,
+				DateConfType: edbItem.DateConfType,
+				DateConf:     dateConfStr,
+				CreateTime:   time.Now(),
+				ModifyTime:   time.Now(),
+			}
+			addSeriesEdbList = append(addSeriesEdbList, edbTmp)
+		}
+		if len(addSeriesEdbList) > 0 {
+			_, e = to.InsertMulti(len(addSeriesEdbList), addSeriesEdbList)
+			if e != nil {
+				err = fmt.Errorf("AddChartSeries Err:" + e.Error())
+				return
+			}
+		}
+	}
+	return
+}
+
+func DeleteChartSeriesAndEdbMapping(chartInfoId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := ` DELETE FROM chart_series WHERE chart_info_id=? `
+	_, err = to.Raw(sql, chartInfoId).Exec()
+	if err != nil {
+		return
+	}
+	sql = ` DELETE FROM  chart_series_edb_mapping WHERE chart_info_id=? `
+	_, err = to.Raw(sql, chartInfoId).Exec()
+	return
+}
+
+type ChartSectionSeriesValSortAsc []ChartSectionSeriesValSort
+type ChartSectionSeriesValSortDesc []ChartSectionSeriesValSort
+
+type ChartSectionSeriesValSort struct {
+	Index int
+	Value float64
+}
+
+func (s ChartSectionSeriesValSortAsc) Len() int {
+	return len(s)
+}
+
+func (s ChartSectionSeriesValSortAsc) Less(i, j int) bool {
+	return s[i].Value < s[j].Value // 升序排序,如果想要降序则改为 s[i].Value > s[j].Value
+}
+
+func (s ChartSectionSeriesValSortAsc) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}
+
+func (s ChartSectionSeriesValSortDesc) Len() int {
+	return len(s)
+}
+
+func (s ChartSectionSeriesValSortDesc) Less(i, j int) bool {
+	return s[i].Value > s[j].Value // 升序排序,如果想要降序则改为 s[i].Value > s[j].Value
+}
+
+func (s ChartSectionSeriesValSortDesc) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}

+ 29 - 0
models/data_manage/chart_series_edb_mapping.go

@@ -0,0 +1,29 @@
+package data_manage
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ChartSeriesEdbMapping struct {
+	ChartSeriesEdbMappingId int       `orm:"column(chart_series_edb_mapping_id);pk"`
+	ChartSeriesId           int       `description:"系列ID"`
+	ChartInfoId             int       `description:"图表ID"`
+	EdbInfoId               int       `description:"指标id"`
+	DateConfName            string    `description:"引用日期配置名称"`
+	DateConfType            int       `description:"日期类型,0指标最新日期, 1引用日期"`
+	DateConf                string    `description:"日期配置名称"`
+	ModifyTime              time.Time `description:"修改时间"`
+	CreateTime              time.Time `description:"创建时间"`
+}
+
+func (c *ChartSeriesEdbMapping) TableName() string {
+	return "chart_series_edb_mapping"
+}
+
+func GetChartSeriesEdbByChartInfoId(chartInfoId int) (items []*ChartSeriesEdbMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM chart_series_edb_mapping WHERE chart_info_id = ?"
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&items)
+	return
+}

+ 38 - 0
models/data_manage/chart_type.go

@@ -0,0 +1,38 @@
+package data_manage
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type ChartType struct {
+	ChartTypeId     int    `orm:"column(chart_type_id);pk"`
+	ChartTypeName   string `description:"图表类型名称"`
+	ChartTypeNameEn string `description:"英文图表类型名称"`
+	ParentId        int    `description:"父级ID"`
+	Sort            int    `description:"排序"`
+	CreateTime      string `description:"创建时间"`
+}
+
+type ChartTypeList struct {
+	ChartTypeId     int
+	ChartTypeName   string `description:"图表类型名称"`
+	ChartTypeNameEn string `description:"英文图表类型名称"`
+	ParentId        int    `description:"父级ID"`
+	Child           []ChartType
+}
+
+type ChartTypeListResp struct {
+	List []ChartTypeList
+}
+
+func (c *ChartType) TableName() string {
+	return "chart_type"
+}
+
+// 查询所有图表类型
+func GetChartTypeList() (items []ChartType, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_type order by sort asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}

+ 21 - 2
models/data_manage/edb_info.go

@@ -51,12 +51,12 @@ type EdbInfo struct {
 	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
 	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
 	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
-	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
-	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	TerminalCode     string  `description:"终端编码,用于配置在机器上"`
 	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
 	ErDataUpdateDate string  `description:"本次更新,数据发生变化的最早日期"`
 	SourceIndexName  string  `description:"数据源中的指标名称"`
+	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	SubSource        int     `description:"子数据来源:0:经济数据库,1:日期序列"`
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
@@ -1658,6 +1658,25 @@ func GetEdbInfoCount(source int, edbCode string) (count int, err error) {
 	return
 }
 
+type EdbInfoEditRecord struct {
+	EdbInfoId           int    `description:"指标ID"`
+	EdbName             string `description:"指标名称"`
+	Frequency           string `description:"频率"`
+	Unit                string `description:"单位"`
+	ClassifyId          int    `description:"分类id"`
+	CalculateFormula    string `description:"计算公式"`
+	OperateUserId       int    `description:"操作人id"`
+	OperateUserRealName string `description:"操作人姓名"`
+}
+
+func ModifyEdbInfoBaseTimeById(edbInfoId int, cTime time.Time) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	// 更新修改时间
+	sql := ` UPDATE edb_info SET base_modify_time = ? WHERE edb_info_id = ? `
+	_, err = o.Raw(sql, cTime, edbInfoId).Exec()
+	return
+}
+
 // GetEdbInfoByNameArr 根据名称获取指标
 func GetEdbInfoByNameArr(names []string, edbInfoType int) (items []*EdbInfo, err error) {
 	if len(names) == 0 {

+ 2 - 0
models/data_manage/edb_info_calculate.go

@@ -254,6 +254,8 @@ type EdbInfoCalculateBatchEditReqByEdbLib struct {
 	Frequency     string `description:"频度"`
 	Unit          string `description:"单位"`
 	ClassifyId    int    `description:"分类id"`
+	AdminId       int    `description:"操作人id"`
+	AdminName     string `description:"操作人姓名"`
 	Formula       string `description:"N值"`
 	EdbInfoId     int    `description:"编辑指标id"`
 	FromEdbInfoId int    `description:"计算来源指标id"`

+ 28 - 0
models/data_manage/edb_info_record.go

@@ -0,0 +1,28 @@
+package data_manage
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type EdbInfoRecord struct {
+	EdbInfoRecordId     int       `orm:"column(edb_info_record_id);pk"`
+	EdbInfoId           int       `orm:"column(edb_info_id)"`
+	OldEdbName          string    `description:"旧的指标名称"`
+	OldFrequency        string    `description:"旧的频率"`
+	OldUnit             string    `description:"旧的单位"`
+	NewEdbName          string    `description:"新的指标名称"`
+	NewFrequency        string    `description:"新的频率"`
+	NewUnit             string    `description:"新的单位"`
+	OperateUserId       int       `description:"执行人id"`
+	OperateUserRealName string    `description:"执行人名称"`
+	CreateTime          time.Time `description:"记录的生成时间"`
+	Timestamp           int64     `description:"时间戳"`
+}
+
+func AddEditEdbInfoRcord(edbRecord *EdbInfoRecord) (e error) {
+	o := orm.NewOrmUsingDB("data")
+	_, e = o.Insert(edbRecord)
+	return
+}

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

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

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

@@ -56,6 +56,8 @@ type ChartInfoReq struct {
 	BaseEdbInfoId           int                          `description:"基础的指标id"`
 	DateList                []ChartInfoDateReq           `description:"日期配置"`
 	ProfitNameEn            string                       `description:"利润英文名称"`
+	EdbInfoIdList           []int                        `description:"现货指标ID列表"`
+	XDataList               []data_manage.XData          `description:"横轴配置"`
 }
 
 // ChartInfoDateReq 图表的日期数据(日期相关)

+ 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

+ 4 - 1
models/db.go

@@ -20,9 +20,10 @@ import (
 	"eta/eta_mobile/models/system"
 	"eta/eta_mobile/models/yb"
 	"eta/eta_mobile/utils"
-	_ "github.com/go-sql-driver/mysql"
 	"time"
 
+	_ "github.com/go-sql-driver/mysql"
+
 	"github.com/beego/beego/v2/client/orm"
 )
 
@@ -295,6 +296,7 @@ func initEdbData() {
 	orm.RegisterModel(
 		new(data_manage.EdbClassify),
 		new(data_manage.EdbInfo), //hz_data库的edb_info表
+		new(data_manage.EdbInfoRecord),
 		new(data_manage.EdbDataThs),
 		new(data_manage.EdbDataWind),
 		new(data_manage.EdbDataPb),
@@ -613,3 +615,4 @@ func afterInitTable() {
 	// 初始化是否启用mongo配置
 	InitUseMongoConf()
 }
+

+ 2 - 0
models/system/sys_user.go

@@ -24,6 +24,8 @@ type LoginResp struct {
 	AdminId         int    `description:"系统用户id"`
 	ProductName     string `description:"产品名称:admin,ficc,权益"`
 	Authority       int    `description:"管理权限,0:无,1:部门负责人,2:小组负责人,或者ficc销售主管,4:ficc销售组长"`
+	DepartmentName  string `description:"部门名称"`
+	GroupName       string `description:"分组名称"`
 }
 
 type Admin struct {

+ 36 - 0
routers/commentsRouter.go

@@ -1141,6 +1141,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoImgSetByBase64",
+            Router: `/chart_info/image/set_by_base64`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage/future_good:FutureGoodChartInfoController"],
         beego.ControllerComments{
             Method: "ChartList",
@@ -1987,6 +1996,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "ChartInfoImgSetByBase64",
+            Router: `/chart_info/image/set_by_base64`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoMove",
@@ -2014,6 +2032,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "PreviewSectionCombineChartInfo",
+            Router: `/chart_info/preview/section_combine`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "PreviewSectionScatterChartInfo",
@@ -2059,6 +2086,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "GetChartTypeList",
+            Router: `/chart_info/type_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "SaveAdjustEdbInfo",

+ 711 - 2
services/data/chart_extra_config.go

@@ -5,13 +5,16 @@ import (
 	"errors"
 	"eta/eta_mobile/models/data_manage"
 	"eta/eta_mobile/services/google"
+	"eta/eta_mobile/utils"
+	"fmt"
+	"sort"
 	"strconv"
 	"strings"
+	"time"
 )
 
-func HandleExtraConfig(chartType int, extraConfigStr string) (newExtraConfigStr string, err error, errMsg string) {
+func HandleExtraConfig(chartInfoId int, chartType int, extraConfigStr string) (newExtraConfigStr string, newAllExtraConfigStr string, err error, errMsg string) {
 	newExtraConfigStr = extraConfigStr
-
 	switch chartType {
 	case 10: // 截面散点图
 		var tmpExtraConfig data_manage.SectionScatterReq
@@ -28,6 +31,48 @@ func HandleExtraConfig(chartType int, extraConfigStr string) (newExtraConfigStr
 		}
 
 		newExtraConfigStr, err, errMsg = handleSectionScatterChartData(tmpExtraConfig)
+	case utils.CHART_TYPE_SECTION_COMBINE:
+		//整理组合图的配置信息,将部分信息存入其他表
+		// 预览和详情都走这个接口
+		var sectionExtraConfig data_manage.ChartSectionAllExtraConf
+		if extraConfigStr == `` {
+			errMsg = "截面组合图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfig)
+		if err != nil {
+			errMsg = "截面组合图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		newAllExtraConfig, e, msg := handleChartSectionCombineData(chartInfoId, sectionExtraConfig)
+		if e != nil {
+			err = e
+			errMsg = msg
+			return
+		}
+		newAllExtraConfigByte, e := json.Marshal(newAllExtraConfig)
+		if e != nil {
+			err = e
+			return
+		}
+		newAllExtraConfigStr = string(newAllExtraConfigByte)
+
+		newExtraConfig := &data_manage.ChartSectionExtraConf{
+			DateConfList:        newAllExtraConfig.DateConfList,
+			IsHeap:              newAllExtraConfig.IsHeap,
+			XDataList:           newAllExtraConfig.XDataList,
+			UnitList:            newAllExtraConfig.UnitList,
+			BaseChartSeriesName: newAllExtraConfig.BaseChartSeriesName,
+			SortType:            newAllExtraConfig.SortType,
+		}
+		extraConfigByte, e := json.Marshal(newExtraConfig)
+		if e != nil {
+			err = e
+			return
+		}
+		newExtraConfigStr = string(extraConfigByte)
 	}
 	return
 }
@@ -197,3 +242,667 @@ func GetEnNameMapByCnNameList(cnNameList []string) (contentEnMap map[string]stri
 	}
 	return
 }
+
+// handleSectionScatterChartData 截面组合图的英文文案处理
+func handleChartSectionCombineData(chartInfoId int, extraConfig data_manage.ChartSectionAllExtraConf) (newExtraConfig data_manage.ChartSectionAllExtraConf, err error, errMsg string) {
+	dateConfListMapSave := make(map[string]bool)
+	for k, v := range extraConfig.DateConfList {
+		if v.DateConfNameEn == "" {
+			extraConfig.DateConfList[k].DateConfNameEn = v.DateConfName
+		}
+	}
+
+	if extraConfig.UnitList.LeftNameEn == "" {
+		extraConfig.UnitList.LeftNameEn = extraConfig.UnitList.LeftName
+	}
+	if extraConfig.UnitList.RightNameEn == "" {
+		extraConfig.UnitList.RightNameEn = extraConfig.UnitList.RightName
+	}
+	if extraConfig.UnitList.RightTwoNameEn == "" {
+		extraConfig.UnitList.RightTwoNameEn = extraConfig.UnitList.RightTwoName
+	}
+
+	for k, v := range extraConfig.XDataList {
+		if v.NameEn == "" {
+			extraConfig.XDataList[k].NameEn = v.Name
+		}
+	}
+	for k, v := range extraConfig.SeriesList {
+		if v.SeriesNameEn == `` {
+			extraConfig.SeriesList[k].SeriesNameEn = v.SeriesName
+		}
+		for _, info := range v.EdbInfoList {
+			if info.DateConfType == 1 && info.DateConfName != "" {
+				dateConfListMapSave[info.DateConfName] = true
+			}
+		}
+	}
+
+	if chartInfoId > 0 {
+		// 查询表里的系列信息
+		chartSectionCombineEdbList, e := data_manage.GetChartSeriesEdbByChartInfoId(chartInfoId)
+		if e != nil {
+			err = e
+			errMsg = "查询图表系列信息失败"
+			return
+		}
+		for _, info := range chartSectionCombineEdbList {
+			if info.DateConfType == 1 && info.DateConfName != "" {
+				dateConfListMapSave[info.DateConfName] = true
+			}
+		}
+	}
+	newExtraConfig = extraConfig
+	// 去掉没有被引用的配置
+	newExtraConfig.DateConfList = make([]*data_manage.ChartSectionDateConfItem, 0)
+	for _, v := range extraConfig.DateConfList {
+		if _, ok := dateConfListMapSave[v.DateConfName]; ok {
+			newExtraConfig.DateConfList = append(newExtraConfig.DateConfList, v)
+		}
+	}
+	return
+}
+
+// GetChartSectionCombineData 截面组合图的数据处理
+func GetChartSectionCombineData(chartInfo *data_manage.ChartInfo, mappingList []*data_manage.ChartEdbInfoMapping, edbDataListMap map[int][]*data_manage.EdbDataList, extraConfig data_manage.ChartSectionAllExtraConf) (edbIdList []int, dataListResp data_manage.ChartSectionCombineDataResp, err error) {
+	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
+	edbDataMap := make(map[int]map[string]float64)
+	for edbInfoId, edbDataList := range edbDataListMap {
+		edbDateData := make(map[string]float64)
+		for _, edbData := range edbDataList {
+			edbDateData[edbData.DataTime] = edbData.Value
+		}
+		edbDataMap[edbInfoId] = edbDateData
+	}
+
+	// edbIdList 指标展示顺序;x轴的指标顺序
+	edbIdList = make([]int, 0)
+	edbMappingMap := make(map[int]*data_manage.ChartEdbInfoMapping)
+	for _, v := range mappingList {
+		edbIdList = append(edbIdList, v.EdbInfoId)
+		edbMappingMap[v.EdbInfoId] = v
+	}
+	// 确定好截面散点图返回的数据格式
+	// 获取所有的引用日期设置
+	dateConfListMap := make(map[string]*data_manage.ChartSectionDateConfItem)
+	dateConfEdbIds := make([]int, 0)
+	for _, v := range extraConfig.DateConfList {
+		if v.EdbInfoId > 0 {
+			dateConfEdbIds = append(dateConfEdbIds, v.EdbInfoId)
+		}
+		dateConfListMap[v.DateConfName] = v
+	}
+	// 遍历每个系列
+	// 遍历每个指标,根据选中的日期,进行日期变换得到最终的日期,根据最终的日期获取对应的值
+	// 组装数据
+	baseSeries := new(data_manage.ChartSectionSeriesItem) //y轴的系列
+	var firstUnit, leftUnit, rightUnit, right2Unit *data_manage.XData
+	var (
+		LeftMin   float64
+		LeftMax   float64
+		RightMin  float64
+		RightMax  float64
+		Right2Min float64
+		Right2Max float64
+	)
+	seriesDataListMap := make(map[string][]float64)
+	seriesNoDataIndexMap := make(map[string][]int)
+	for _, seriesItem := range extraConfig.SeriesList {
+		var maxDate time.Time
+		var minVal, maxVal float64
+		noDataEdbIndex := make([]int, 0)
+		dataList := make([]float64, len(seriesItem.EdbInfoList))
+		for index, edbConf := range seriesItem.EdbInfoList {
+			edbInfoId := edbConf.EdbInfoId //X轴的指标
+			edbMappingInfo, ok := edbMappingMap[edbInfoId]
+			if !ok {
+				continue
+			}
+			seriesItem.EdbInfoList[index].EdbName = edbMappingInfo.EdbName
+			seriesItem.EdbInfoList[index].EdbNameEn = edbMappingInfo.EdbNameEn
+			seriesItem.EdbInfoList[index].EdbInfoType = edbMappingInfo.EdbInfoCategoryType
+			seriesItem.EdbInfoList[index].Unit = edbMappingInfo.Unit
+			seriesItem.EdbInfoList[index].UnitEn = edbMappingInfo.UnitEn
+			if index == 0 {
+				firstUnit = &data_manage.XData{
+					Name:   edbMappingInfo.Unit,
+					NameEn: edbMappingInfo.UnitEn,
+				}
+			}
+			edbDataList, ok3 := edbDataListMap[edbInfoId]
+			if !ok3 {
+				err = fmt.Errorf("指标%d的日期数据不存在", edbInfoId)
+				return
+			}
+			//日期变换处理,判断用指标的最新日期还是,直接获取引用日期
+			var findDate string
+			if edbConf.DateConfType == 0 {
+				if edbInfoId == 0 {
+					err = fmt.Errorf("请选择指标")
+					return
+				}
+				findDate, err = GetChartSectionSeriesDateByDateChange(edbInfoId, edbDataList, edbConf.DateConf.DateChange, edbConf.DateConf.MoveForward)
+				if err != nil {
+					err = fmt.Errorf("指标%d的日期变换处理失败", edbInfoId)
+					return
+				}
+			} else {
+				// 获取日期配置
+				dateConfItem, ok1 := dateConfListMap[edbConf.DateConfName]
+				if !ok1 {
+					err = fmt.Errorf("引用日期配置不存在")
+					return
+				}
+				// todo 根据日期变换得到最终日期
+				edbDataListTmp := make([]*data_manage.EdbDataList, 0)
+				if dateConfItem.EdbInfoId > 0 {
+					edbDataListTmp, ok1 = edbDataListMap[dateConfItem.EdbInfoId]
+					if !ok1 {
+						err = fmt.Errorf("指标%d的日期数据不存在", dateConfItem.EdbInfoId)
+						return
+					}
+				}
+
+				findDate, err = GetChartSectionSeriesDateByDateChange(dateConfItem.EdbInfoId, edbDataListTmp, dateConfItem.DateChange, dateConfItem.MoveForward)
+				if err != nil {
+					err = fmt.Errorf("指标%d的日期变换处理失败", dateConfItem.EdbInfoId)
+					return
+				}
+			}
+			findDateTime, _ := time.ParseInLocation(utils.FormatDate, findDate, time.Local)
+			if maxDate.IsZero() {
+				maxDate = findDateTime
+			} else {
+				if findDateTime.After(maxDate) {
+					maxDate = findDateTime
+				}
+			}
+			if tmpValue, ok := edbDataMap[edbInfoId][findDate]; ok {
+				dataList[index] = tmpValue
+				if index == 0 {
+					minVal = tmpValue
+					maxVal = tmpValue
+				} else {
+					if tmpValue < minVal {
+						minVal = tmpValue
+					}
+					if tmpValue > maxVal {
+						maxVal = tmpValue
+					}
+				}
+			} else {
+				dataList[index] = 0
+				noDataEdbIndex = append(noDataEdbIndex, index)
+				continue
+			}
+		}
+		seriesDataListMap[seriesItem.SeriesName] = dataList
+		seriesNoDataIndexMap[seriesItem.SeriesName] = noDataEdbIndex
+		seriesItem.DataList = dataList
+		seriesItem.MinData = minVal
+		seriesItem.MaxData = maxVal
+		seriesItem.NoDataEdbIndex = noDataEdbIndex
+		if extraConfig.BaseChartSeriesName == seriesItem.SeriesName {
+			baseSeries = seriesItem
+		}
+		if seriesItem.IsAxis == 1 && leftUnit == nil { //左轴,右轴
+			leftUnit = firstUnit
+		} else if seriesItem.IsAxis == 0 && rightUnit == nil {
+			rightUnit = firstUnit
+		} else if seriesItem.IsAxis == 2 && right2Unit == nil {
+			right2Unit = firstUnit
+		}
+
+		//处理上下限
+		var minData, maxData float64
+		for _, d := range seriesItem.DataList {
+			if minData > d {
+				minData = d
+			}
+			if maxData < d {
+				maxData = d
+			}
+		}
+		if seriesItem.IsAxis == 1 {
+			if LeftMin > minData {
+				LeftMin = minData
+			}
+			if LeftMax < maxData {
+				LeftMax = maxData
+			}
+		} else if seriesItem.IsAxis == 0 {
+			if RightMin > minData {
+				RightMin = minData
+			}
+			if RightMax < maxData {
+				RightMax = maxData
+			}
+		} else {
+			if Right2Min > minData {
+				Right2Min = minData
+			}
+			if Right2Max < maxData {
+				Right2Max = maxData
+			}
+		}
+	}
+	// 处理横轴
+	// 遍历基准系列,判断有几个横轴名称
+	if baseSeries == nil {
+		err = fmt.Errorf("基准系列不存在")
+		return
+	}
+	// 处理系列排序
+	if extraConfig.SortType > 0 {
+		newSeriesDataListMap, newSeriesNoDataIndexMap := SortChartSeriesDataSet(baseSeries.SeriesName, baseSeries.DataList, baseSeries.NoDataEdbIndex, seriesDataListMap, seriesNoDataIndexMap, extraConfig.SortType)
+		for k, item := range extraConfig.SeriesList {
+			dataList, ok := newSeriesDataListMap[item.SeriesName]
+			if ok {
+				extraConfig.SeriesList[k].DataList = dataList
+			}
+			noIndex, ok := newSeriesNoDataIndexMap[item.SeriesName]
+			if ok {
+				extraConfig.SeriesList[k].NoDataEdbIndex = noIndex
+			}
+		}
+	}
+
+	xDataList := make([]data_manage.XData, 0)
+	for index, item := range baseSeries.EdbInfoList {
+		if index == 0 {
+			firstUnit = &data_manage.XData{
+				Name:   item.Unit,
+				NameEn: item.UnitEn,
+			}
+		}
+		tmp := data_manage.XData{
+			Name:   item.EdbName,
+			NameEn: item.EdbNameEn,
+		}
+		// 如果已经设置了横轴名称,则用设置的名称替换
+		if len(extraConfig.XDataList) > index {
+			newItem := extraConfig.XDataList[index]
+			if newItem.Name != "" {
+				tmp = newItem
+			}
+		}
+		xDataList = append(xDataList, tmp)
+	}
+	dataListResp.XDataList = xDataList
+
+	unitList := new(data_manage.ChartSectionCombineUnit)
+	if baseSeries.IsAxis == 1 { //左轴,右轴
+		leftUnit = firstUnit
+	} else if baseSeries.IsAxis == 2 {
+		rightUnit = firstUnit
+	} else {
+		right2Unit = firstUnit
+	}
+	if leftUnit != nil {
+		unitList.LeftName = leftUnit.Name
+		unitList.LeftNameEn = leftUnit.NameEn
+	}
+	if rightUnit != nil {
+		unitList.RightName = rightUnit.Name
+		unitList.RightNameEn = rightUnit.NameEn
+	}
+	if right2Unit != nil {
+		unitList.RightTwoName = right2Unit.Name
+		unitList.RightTwoNameEn = right2Unit.NameEn
+	}
+	if extraConfig.UnitList.LeftName != "" {
+		unitList.LeftName = extraConfig.UnitList.LeftName
+		unitList.LeftNameEn = extraConfig.UnitList.LeftNameEn
+	}
+	if extraConfig.UnitList.RightName != "" {
+		unitList.RightName = extraConfig.UnitList.RightName
+		unitList.RightNameEn = extraConfig.UnitList.RightNameEn
+	}
+
+	if extraConfig.UnitList.RightTwoName != "" {
+		unitList.RightTwoName = extraConfig.UnitList.RightTwoName
+		unitList.RightTwoNameEn = extraConfig.UnitList.RightTwoNameEn
+	}
+
+	if chartInfo != nil && chartInfo.MinMaxSave == 1 {
+		dataListResp.LeftMin = chartInfo.LeftMin
+		dataListResp.LeftMax = chartInfo.LeftMax
+		dataListResp.RightMin = chartInfo.RightMin
+		dataListResp.RightMax = chartInfo.RightMax
+		dataListResp.Right2Min = chartInfo.Right2Min
+		dataListResp.Right2Max = chartInfo.Right2Max
+	} else {
+		dataListResp.LeftMin = strconv.FormatFloat(LeftMin, 'f', -1, 64)
+		dataListResp.LeftMax = strconv.FormatFloat(LeftMax, 'f', -1, 64)
+		dataListResp.RightMin = strconv.FormatFloat(RightMin, 'f', -1, 64)
+		dataListResp.RightMax = strconv.FormatFloat(RightMax, 'f', -1, 64)
+		dataListResp.Right2Min = strconv.FormatFloat(Right2Min, 'f', -1, 64)
+		dataListResp.Right2Max = strconv.FormatFloat(Right2Max, 'f', -1, 64)
+	}
+
+	// 查询引用日期里的指标信息
+	if len(dateConfEdbIds) > 0 {
+		dateConfEdbList, e := data_manage.GetEdbInfoByIdList(dateConfEdbIds)
+		if e != nil {
+			err = fmt.Errorf("查询引用日期里的指标信息失败,错误信息:%s", e.Error())
+			return
+		}
+		dateConfEdbMap := make(map[int]*data_manage.EdbInfo)
+		for _, dateConfEdb := range dateConfEdbList {
+			dateConfEdbMap[dateConfEdb.EdbInfoId] = dateConfEdb
+		}
+		for i, dateConf := range extraConfig.DateConfList {
+			if dateConf.EdbInfoId > 0 {
+				edbItem, ok := dateConfEdbMap[dateConf.EdbInfoId]
+				if ok {
+					extraConfig.DateConfList[i].EdbName = edbItem.EdbName
+					extraConfig.DateConfList[i].EdbInfoId = edbItem.EdbInfoId
+					extraConfig.DateConfList[i].EdbInfoType = edbItem.EdbInfoType
+					extraConfig.DateConfList[i].Frequency = edbItem.Frequency
+					extraConfig.DateConfList[i].EndDate = edbItem.EndDate
+				}
+
+			}
+		}
+	}
+
+	dataListResp.SeriesList = extraConfig.SeriesList
+	dataListResp.DateConfList = extraConfig.DateConfList
+	dataListResp.BaseChartSeriesName = extraConfig.BaseChartSeriesName
+	dataListResp.UnitList = unitList
+	dataListResp.IsHeap = extraConfig.IsHeap
+	dataListResp.SortType = extraConfig.SortType
+	return
+}
+
+// GetChartSectionSeriesDateByDateChange 获取日期变换后的日期edbInfoId 1指标日期,2 系统日期
+func GetChartSectionSeriesDateByDateChange(edbInfoId int, dataList []*data_manage.EdbDataList, dateChange []*data_manage.ChartSectionDateChange, moveForward int) (newDate string, err error) {
+	if edbInfoId > 0 { //指标日期
+		newDate = GetEdbDateByMoveForward(moveForward, dataList)
+	} else {
+		//系统日期
+		newDate = time.Now().Format(utils.FormatDate)
+	}
+	if newDate != "" && len(dateChange) > 0 {
+		newDate, err = HandleChartSectionSeriesDateChange(newDate, dateChange)
+	}
+	return
+}
+
+func GetEdbDateByMoveForward(moveForward int, edbDataList []*data_manage.EdbDataList) (date string) {
+	dateList := make([]string, 0)
+	for _, v := range edbDataList {
+		dateList = append(dateList, v.DataTime)
+	}
+
+	date = GetEdbDateByMoveForwardByDateList(moveForward, dateList)
+	return
+}
+
+func GetEdbDateByMoveForwardByDateList(moveForward int, dateList []string) (date string) {
+	// 根据日期进行排序
+	index := len(dateList) - 1 - moveForward
+	for k, v := range dateList {
+		if k == index {
+			date = v
+			return
+		}
+	}
+	return
+}
+
+// HandleChartSectionSeriesDateChange 处理日期变换
+func HandleChartSectionSeriesDateChange(date string, dateChange []*data_manage.ChartSectionDateChange) (newDate string, err error) {
+	newDate = date
+	if newDate != "" {
+		if len(dateChange) > 0 {
+			var dateTime time.Time
+			dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+			if err != nil {
+				err = fmt.Errorf("日期解析失败: %s", err.Error())
+				return
+			}
+			for _, v := range dateChange {
+				if v.ChangeType == 1 {
+					dateTime = dateTime.AddDate(v.Year, v.Month, v.Day)
+					newDate = dateTime.Format(utils.FormatDate)
+				} else if v.ChangeType == 2 {
+					newDate, err, _ = handleSystemAppointDateT(dateTime, v.FrequencyDay, v.Frequency)
+					if err != nil {
+						return
+					}
+					dateTime, err = time.ParseInLocation(utils.FormatDate, newDate, time.Local)
+					if err != nil {
+						err = fmt.Errorf("日期解析失败: %s", err.Error())
+						return
+					}
+				}
+			}
+		}
+	}
+
+	return
+}
+
+// handleSystemAppointDateT
+// @Description: 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
+// @author: Roc
+// @datetime2023-10-27 09:31:35
+// @param Frequency string
+// @param Day string
+// @return date string
+// @return err error
+// @return errMsg string
+func handleSystemAppointDateT(currDate time.Time, appointDay, frequency string) (date string, err error, errMsg string) {
+	//currDate := time.Now()
+	switch frequency {
+	case "本周":
+		day := int(currDate.Weekday())
+		if day == 0 { // 周日
+			day = 7
+		}
+		num := 0
+		switch appointDay {
+		case "周一":
+			num = 1
+		case "周二":
+			num = 2
+		case "周三":
+			num = 3
+		case "周四":
+			num = 4
+		case "周五":
+			num = 5
+		case "周六":
+			num = 6
+		case "周日":
+			num = 7
+		}
+		day = num - day
+		date = currDate.AddDate(0, 0, day).Format(utils.FormatDate)
+	case "本旬":
+		day := currDate.Day()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if day <= 10 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
+			} else if day <= 20 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 11, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 21, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if day <= 10 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 10, 0, 0, 0, 0, currDate.Location())
+			} else if day <= 20 {
+				tmpDate = time.Date(currDate.Year(), currDate.Month(), 20, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
+			}
+		}
+		date = tmpDate.Format(utils.FormatDate)
+	case "本月":
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			tmpDate = time.Date(currDate.Year(), currDate.Month(), 1, 0, 0, 0, 0, currDate.Location())
+		case "最后一天":
+			tmpDate = time.Date(currDate.Year(), currDate.Month()+1, 1, 0, 0, 0, 0, currDate.Location()).AddDate(0, 0, -1)
+		}
+		date = tmpDate.Format(utils.FormatDate)
+	case "本季":
+		month := currDate.Month()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if month <= 3 {
+				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 4, 1, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 9 {
+				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 10, 1, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if month <= 3 {
+				tmpDate = time.Date(currDate.Year(), 3, 31, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
+			} else if month <= 9 {
+				tmpDate = time.Date(currDate.Year(), 9, 30, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+			}
+		}
+		date = tmpDate.Format(utils.FormatDate)
+	case "本半年":
+		month := currDate.Month()
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 7, 1, 0, 0, 0, 0, currDate.Location())
+			}
+		case "最后一天":
+			if month <= 6 {
+				tmpDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, currDate.Location())
+			} else {
+				tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+			}
+		}
+		date = tmpDate.Format(utils.FormatDate)
+	case "本年":
+		var tmpDate time.Time
+		switch appointDay {
+		case "第一天":
+			tmpDate = time.Date(currDate.Year(), 1, 1, 0, 0, 0, 0, currDate.Location())
+		case "最后一天":
+			tmpDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, currDate.Location())
+		}
+		date = tmpDate.Format(utils.FormatDate)
+	default:
+		errMsg = "错误的日期频度:" + frequency
+		err = errors.New(errMsg)
+		return
+	}
+
+	return
+}
+
+// sortTripleDataSet 以第一组数据为基准,排序之后,空数组的位置也要同步变更
+func SortChartSeriesDataSet(baseName string, baseDataList []float64, baseSeriesNoDataIndexList []int, dataListMap map[string][]float64, noDataListIndexMap map[string][]int, asc int) (newDataListMap map[string][]float64, newNoDataListIndexMap map[string][]int) {
+	newDataListMap = make(map[string][]float64)
+	newNoDataListIndexMap = make(map[string][]int)
+
+	indices := make([]int, len(baseDataList))
+	newIndices := make([]int, len(baseDataList)-len(baseSeriesNoDataIndexList))
+	// 初始化indices
+	for i := range indices {
+		indices[i] = i
+	}
+	if len(baseSeriesNoDataIndexList) > 0 { //把空值移动到最右边
+		j := 0
+		for i := range indices {
+			isEmpty := false
+			for _, v := range baseSeriesNoDataIndexList {
+				if i == v {
+					isEmpty = true
+					break
+				}
+			}
+			if isEmpty {
+				continue
+			}
+			newIndices[j] = i
+			j += 1
+		}
+		newIndices = append(newIndices, baseSeriesNoDataIndexList...)
+		// 根据排序后的indices重新排列所有组的数据
+		for i, idx := range newIndices {
+			for k, _ := range dataListMap {
+				if _, ok := newDataListMap[k]; !ok {
+					newDataListMap[k] = make([]float64, len(baseDataList))
+				}
+				if utils.InArrayByInt(noDataListIndexMap[k], idx) { //如果i位置上的数据为空,那么
+					newNoDataListIndexMap[k] = append(newNoDataListIndexMap[k], i)
+				}
+				newDataListMap[k][i] = dataListMap[k][idx]
+			}
+		}
+		dataListMap = newDataListMap
+		noDataListIndexMap = newNoDataListIndexMap
+		newDataListMap = make(map[string][]float64)
+		newNoDataListIndexMap = make(map[string][]int)
+		baseDataList, _ = dataListMap[baseName]
+		//先把空的数据移动到最后面
+		indices = make([]int, len(baseDataList)-len(baseSeriesNoDataIndexList)) //空值不参与排序
+		newIndices = make([]int, len(baseDataList))                             //空值不参与排序
+		// 初始化indices
+		for i := range indices {
+			indices[i] = i
+		}
+
+	}
+	length := len(indices)
+	baseDataSortList := make([]data_manage.ChartSectionSeriesValSort, length)
+	for i, value := range baseDataList {
+		if i < length {
+			baseDataSortList[i] = data_manage.ChartSectionSeriesValSort{Index: i, Value: value}
+		}
+	}
+	if asc == 1 {
+		// 使用sort.Sort进行排序
+		sort.Sort(data_manage.ChartSectionSeriesValSortAsc(baseDataSortList))
+	} else {
+		sort.Sort(data_manage.ChartSectionSeriesValSortDesc(baseDataSortList))
+	}
+
+	for k, v := range baseDataSortList {
+		indices[k] = v.Index
+	}
+
+	for i := range newIndices {
+		if i < length {
+			newIndices[i] = indices[i]
+		} else {
+			newIndices[i] = i
+		}
+	}
+	// 根据排序后的indices重新排列所有组的数据
+	for i, idx := range newIndices {
+		for k, _ := range dataListMap {
+			if _, ok := newDataListMap[k]; !ok {
+				newDataListMap[k] = make([]float64, len(baseDataList))
+			}
+			if utils.InArrayByInt(noDataListIndexMap[k], idx) { //如果i位置上的数据为空,那么
+				newNoDataListIndexMap[k] = append(newNoDataListIndexMap[k], i)
+			}
+			newDataListMap[k][i] = dataListMap[k][idx]
+		}
+	}
+	return
+}

+ 493 - 5
services/data/chart_info.go

@@ -301,6 +301,18 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 
 	var extraConfig interface{}
 	switch chartType {
+	case 6:
+		var tmpConfig data_manage.ChartTimeCombineExtraConf
+		if extraConfigStr != `` {
+			err = json.Unmarshal([]byte(extraConfigStr), &tmpConfig)
+			if err != nil {
+				errMsg = "雷达图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+		}
+
+		extraConfig = tmpConfig
 	case 7: // 柱形图
 		var barConfig data_manage.BarChartInfoReq
 		if extraConfigStr == `` {
@@ -344,6 +356,159 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 			return
 		}
 		extraConfig = barConfig
+	case utils.CHART_TYPE_SECTION_COMBINE:
+		// 预览和详情都走这个接口
+		var sectionExtraConfig data_manage.ChartSectionAllExtraConf
+		if extraConfigStr == `` {
+			errMsg = "截面组合图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		if chartInfoId > 0 {
+			var sectionExtraConfigTmp data_manage.ChartSectionExtraConf
+			err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfigTmp)
+			if err != nil {
+				errMsg = "截面组合图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+			sectionExtraConfig.XDataList = sectionExtraConfigTmp.XDataList
+			sectionExtraConfig.BaseChartSeriesName = sectionExtraConfigTmp.BaseChartSeriesName
+			sectionExtraConfig.UnitList = sectionExtraConfigTmp.UnitList
+			sectionExtraConfig.DateConfList = sectionExtraConfigTmp.DateConfList
+			sectionExtraConfig.IsHeap = sectionExtraConfigTmp.IsHeap
+			sectionExtraConfig.SortType = sectionExtraConfigTmp.SortType
+			// 查询所有的seriesEdb
+			seriesEdbList, e := data_manage.GetChartSeriesEdbByChartInfoId(chartInfoId)
+			if e != nil {
+				errMsg = "查询seriesEdb失败"
+				err = errors.New(errMsg + e.Error())
+				return
+			}
+			// todo 是否有必要返回单位信息
+			// 组装成map
+			seriesEdbMap := make(map[int][]*data_manage.ChartSectionSeriesEdbConf)
+			for _, v := range seriesEdbList {
+				var dateConf *data_manage.ChartSectionSeriesDateConfItem
+				if v.DateConf != "" {
+					err = json.Unmarshal([]byte(v.DateConf), &dateConf)
+					if err != nil {
+						errMsg = "截面组合图配置异常"
+						err = errors.New(errMsg + err.Error())
+						return
+					}
+				}
+				tmp := &data_manage.ChartSectionSeriesEdbConf{
+					ChartSeriesEdbMappingId: v.ChartSeriesEdbMappingId,
+					ChartSeriesId:           v.ChartSeriesId,
+					//ChartInfoId:             v.ChartInfoId,
+					EdbInfoId:    v.EdbInfoId,
+					DateConf:     dateConf,
+					EdbName:      "",
+					EdbNameEn:    "",
+					Unit:         "",
+					UnitEn:       "",
+					DateConfName: v.DateConfName,
+					DateConfType: v.DateConfType,
+				}
+				seriesEdbMap[v.ChartSeriesId] = append(seriesEdbMap[v.ChartSeriesId], tmp)
+			}
+			//查询series
+			seriesListTmp, e := data_manage.GetChartSeriesByChartInfoId(chartInfoId)
+			if e != nil {
+				errMsg = "查询series失败"
+				err = errors.New(errMsg + e.Error())
+				return
+			}
+			seriesList := make([]*data_manage.ChartSectionSeriesItem, 0)
+			for _, v := range seriesListTmp {
+
+				tmpSeries := &data_manage.ChartSectionSeriesItem{
+					ChartSeriesId: v.ChartSeriesId,
+					SeriesName:    v.SeriesName,
+					SeriesNameEn:  v.SeriesNameEn,
+					ChartStyle:    v.ChartStyle,
+					ChartColor:    v.ChartColor,
+					ChartWidth:    v.ChartWidth,
+					IsPoint:       v.IsPoint,
+					IsNumber:      v.IsNumber,
+					IsAxis:        v.IsAxis,
+					MaxData:       v.MaxData,
+					MinData:       v.MinData,
+					//IsOrder:         false,
+					EdbInfoList: nil,
+					DataList:    nil,
+				}
+				edbInfoList, ok := seriesEdbMap[v.ChartSeriesId]
+				if ok {
+					tmpSeries.EdbInfoList = edbInfoList
+				}
+				seriesList = append(seriesList, tmpSeries)
+			}
+			sectionExtraConfig.SeriesList = seriesList
+
+		} else {
+			err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfig)
+			if err != nil {
+				errMsg = "截面组合图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+		}
+
+		//校验引用日期名称是否重复
+		dateNameMap := make(map[string]int)
+		dateNameEnMap := make(map[string]int)
+		for _, v := range sectionExtraConfig.DateConfList {
+			if _, ok := dateNameMap[v.DateConfName]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfName)
+				return
+			}
+			if _, ok := dateNameEnMap[v.DateConfNameEn]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfNameEn)
+				return
+			}
+			if v.DateConfName != "" {
+				dateNameMap[v.DateConfName] = 1
+			}
+			if v.DateConfNameEn != "" {
+				dateNameEnMap[v.DateConfNameEn] = 1
+			}
+
+		}
+
+		//检查系列名称是否重复
+		seriesNameMap := make(map[string]int)
+		seriesNameEnMap := make(map[string]int)
+		for _, v := range sectionExtraConfig.SeriesList {
+			if _, ok := seriesNameMap[v.SeriesName]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesName)
+				return
+			}
+			if _, ok := seriesNameEnMap[v.SeriesNameEn]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesNameEn)
+				return
+			}
+			if v.SeriesName != "" {
+				seriesNameMap[v.SeriesName] = 1
+			}
+			if v.SeriesNameEn != "" {
+				seriesNameEnMap[v.SeriesNameEn] = 1
+			}
+		}
+
+		// 检查基准系列是否设置
+		if sectionExtraConfig.BaseChartSeriesName == "" {
+			errMsg = "截面组合图基准系列名称未设置"
+			err = errors.New(errMsg)
+			return
+		}
+		//todo 如果是详情接口,应该要从其他表里查询配置
+		extraConfig = sectionExtraConfig
 	default:
 		xEdbIdValue = make([]int, 0)
 		yDataList = make([]data_manage.YData, 0)
@@ -357,6 +522,15 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 
 	// 特殊图形数据处理
 	switch chartType {
+	case 6: //时序组合图
+		//判断是否堆积
+		timeConf := extraConfig.(data_manage.ChartTimeCombineExtraConf)
+		if extraConfigStr == "" { //历史数据,默认开启堆积
+			timeConf = data_manage.ChartTimeCombineExtraConf{
+				IsHeap: 1,
+			}
+		}
+		dataResp = data_manage.ChartTimeCombineDataResp{IsHeap: timeConf.IsHeap}
 	case 2: // 季节性图
 		if seasonExtraConfig != "" {
 			// 季节性图计算不管图上数据时间,拿所有数据
@@ -406,6 +580,23 @@ func GetChartEdbData(chartInfoId, chartType int, calendar, startDate, endDate st
 			return
 		}
 
+		// 这个数据没有必要返回给前端
+		for _, v := range edbList {
+			v.DataList = nil
+		}
+	case utils.CHART_TYPE_SECTION_COMBINE: // 截面组合图
+		sectionConf := extraConfig.(data_manage.ChartSectionAllExtraConf)
+		var chartInfo *data_manage.ChartInfo
+		if chartInfoId > 0 {
+			chartInfo, err = data_manage.GetChartInfoById(chartInfoId)
+			if err != nil {
+				errMsg = "获取图表信息失败"
+				return
+			}
+		}
+
+		xEdbIdValue, dataResp, err = GetChartSectionCombineData(chartInfo, mappingList, edbDataListMap, sectionConf)
+
 		// 这个数据没有必要返回给前端
 		for _, v := range edbList {
 			v.DataList = nil
@@ -1631,6 +1822,96 @@ func CheckChartExtraConfig(chartType int, extraConfigStr string) (edbIdList []in
 			err = errors.New(errMsg)
 			return
 		}
+	case utils.CHART_TYPE_SECTION_COMBINE:
+		var extraConfig data_manage.ChartSectionAllExtraConf
+		if extraConfigStr == `` {
+			errMsg = "截面组合图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &extraConfig)
+		if err != nil {
+			errMsg = "截面组合图配置异常"
+			err = errors.New(errMsg + err.Error())
+			return
+		}
+		//校验引用日期名称是否重复
+		dateNameMap := make(map[string]int)
+		dateNameEnMap := make(map[string]int)
+		for _, v := range extraConfig.DateConfList {
+			if _, ok := dateNameMap[v.DateConfName]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfName)
+				return
+			}
+			if _, ok := dateNameEnMap[v.DateConfNameEn]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfNameEn)
+				return
+			}
+			if v.DateConfName != "" {
+				dateNameMap[v.DateConfName] = 1
+			}
+			if v.DateConfNameEn != "" {
+				dateNameEnMap[v.DateConfNameEn] = 1
+			}
+
+		}
+
+		//检查系列名称是否重复
+		seriesNameMap := make(map[string]int)
+		seriesNameEnMap := make(map[string]int)
+		for _, v := range extraConfig.SeriesList {
+			if _, ok := seriesNameMap[v.SeriesName]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesName)
+				return
+			}
+			if _, ok := seriesNameEnMap[v.SeriesNameEn]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesNameEn)
+				return
+			}
+			if v.SeriesName != "" {
+				seriesNameMap[v.SeriesName] = 1
+			}
+			if v.SeriesNameEn != "" {
+				seriesNameEnMap[v.SeriesNameEn] = 1
+			}
+		}
+
+		// 检查基准系列是否设置
+		if extraConfig.BaseChartSeriesName == "" {
+			errMsg = "截面组合图基准系列名称未设置"
+			err = errors.New(errMsg)
+			return
+		}
+		//todo 如果是详情接口,应该要从其他表里查询配置
+
+		// 遍历指标列表获取指标id
+		edbIdMap := make(map[int]int)
+		hasUsed := make(map[string]struct{})
+		for _, v := range extraConfig.SeriesList {
+			for _, item := range v.EdbInfoList {
+				if item.DateConfName != "" && item.DateConfType == 1 {
+					hasUsed[item.DateConfName] = struct{}{}
+				}
+				if _, ok := edbIdMap[item.EdbInfoId]; !ok {
+					edbIdMap[item.EdbInfoId] = item.EdbInfoId
+					edbIdList = append(edbIdList, item.EdbInfoId)
+				}
+			}
+		}
+		// todo 遍历引用日期获取引用日期里的指标ID, 如果引用日期里的指标没有被引用,是否加入映射
+		for _, v := range extraConfig.DateConfList {
+			if _, ok := hasUsed[v.DateConfName]; !ok {
+				continue
+			}
+			if _, ok := edbIdMap[v.EdbInfoId]; !ok && v.EdbInfoId > 0 {
+				edbIdMap[v.EdbInfoId] = v.EdbInfoId
+				edbIdList = append(edbIdList, v.EdbInfoId)
+			}
+		}
 	}
 	return
 }
@@ -2136,7 +2417,9 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 	}
 
 	// 图表额外配置
-	extraConfig, err, errMsg = HandleExtraConfig(chartType, extraConfig)
+	// 图表额外配置
+	var allExtraConfig string
+	extraConfig, allExtraConfig, err, errMsg = HandleExtraConfig(0, chartType, extraConfig)
 	if err != nil {
 		if errMsg == `` {
 			errMsg = "指标异常!"
@@ -2319,6 +2602,15 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 		return
 	}
 
+	if chartType == utils.CHART_TYPE_SECTION_COMBINE {
+		err = data_manage.AddChartSeriesAndEdbMapping(allExtraConfig, int(newId))
+		if err != nil {
+			errMsg = `保存失败`
+			err = errors.New("保存失败,Err:" + err.Error())
+			return
+		}
+	}
+
 	//添加es数据
 	go EsAddOrEditChartInfo(chartInfo.ChartInfoId)
 
@@ -2520,7 +2812,7 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	}
 
 	// 图表额外配置
-	extraConfig, err, errMsg := HandleExtraConfig(req.ChartType, req.ExtraConfig)
+	extraConfig, allExtraConfig, err, errMsg := HandleExtraConfig(req.ChartInfoId, req.ChartType, req.ExtraConfig)
 	if err != nil {
 		if errMsg == `` {
 			errMsg = "指标异常!"
@@ -2670,6 +2962,14 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	resp.UniqueCode = chartItem.UniqueCode
 	resp.ChartType = req.ChartType
 
+	if chartItem.ChartType == utils.CHART_TYPE_SECTION_COMBINE {
+		err = data_manage.EditChartSeriesAndEdbMapping(allExtraConfig, chartItem.ChartInfoId)
+		if err != nil {
+			errMsg = "保存失败"
+			err = errors.New("保存失败,Err:" + err.Error())
+			return
+		}
+	}
 	//添加es数据
 	go EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据
@@ -3215,6 +3515,18 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 
 	var extraConfig interface{}
 	switch chartType {
+	case 6:
+		var tmpConfig data_manage.ChartTimeCombineExtraConf
+		if extraConfigStr != `` {
+			err = json.Unmarshal([]byte(extraConfigStr), &tmpConfig)
+			if err != nil {
+				errMsg = "雷达图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+		}
+
+		extraConfig = tmpConfig
 	case 7: // 柱形图
 		var barConfig data_manage.BarChartInfoReq
 		if extraConfigStr == `` {
@@ -3258,6 +3570,159 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 			return
 		}
 		extraConfig = barConfig
+	case utils.CHART_TYPE_SECTION_COMBINE:
+		// 预览和详情都走这个接口
+		var sectionExtraConfig data_manage.ChartSectionAllExtraConf
+		if extraConfigStr == `` {
+			errMsg = "截面组合图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		if chartInfoId > 0 {
+			var sectionExtraConfigTmp data_manage.ChartSectionExtraConf
+			err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfigTmp)
+			if err != nil {
+				errMsg = "截面组合图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+			sectionExtraConfig.XDataList = sectionExtraConfigTmp.XDataList
+			sectionExtraConfig.BaseChartSeriesName = sectionExtraConfigTmp.BaseChartSeriesName
+			sectionExtraConfig.UnitList = sectionExtraConfigTmp.UnitList
+			sectionExtraConfig.DateConfList = sectionExtraConfigTmp.DateConfList
+			sectionExtraConfig.IsHeap = sectionExtraConfigTmp.IsHeap
+			sectionExtraConfig.SortType = sectionExtraConfigTmp.SortType
+			// 查询所有的seriesEdb
+			seriesEdbList, e := data_manage.GetChartSeriesEdbByChartInfoId(chartInfoId)
+			if e != nil {
+				errMsg = "查询seriesEdb失败"
+				err = errors.New(errMsg + e.Error())
+				return
+			}
+			// todo 是否有必要返回单位信息
+			// 组装成map
+			seriesEdbMap := make(map[int][]*data_manage.ChartSectionSeriesEdbConf)
+			for _, v := range seriesEdbList {
+				var dateConf *data_manage.ChartSectionSeriesDateConfItem
+				if v.DateConf != "" {
+					err = json.Unmarshal([]byte(v.DateConf), &dateConf)
+					if err != nil {
+						errMsg = "截面组合图配置异常"
+						err = errors.New(errMsg + err.Error())
+						return
+					}
+				}
+				tmp := &data_manage.ChartSectionSeriesEdbConf{
+					ChartSeriesEdbMappingId: v.ChartSeriesEdbMappingId,
+					ChartSeriesId:           v.ChartSeriesId,
+					//ChartInfoId:             v.ChartInfoId,
+					EdbInfoId:    v.EdbInfoId,
+					DateConf:     dateConf,
+					EdbName:      "",
+					EdbNameEn:    "",
+					Unit:         "",
+					UnitEn:       "",
+					DateConfName: v.DateConfName,
+					DateConfType: v.DateConfType,
+				}
+				seriesEdbMap[v.ChartSeriesId] = append(seriesEdbMap[v.ChartSeriesId], tmp)
+			}
+			//查询series
+			seriesListTmp, e := data_manage.GetChartSeriesByChartInfoId(chartInfoId)
+			if e != nil {
+				errMsg = "查询series失败"
+				err = errors.New(errMsg + e.Error())
+				return
+			}
+			seriesList := make([]*data_manage.ChartSectionSeriesItem, 0)
+			for _, v := range seriesListTmp {
+
+				tmpSeries := &data_manage.ChartSectionSeriesItem{
+					ChartSeriesId: v.ChartSeriesId,
+					SeriesName:    v.SeriesName,
+					SeriesNameEn:  v.SeriesNameEn,
+					ChartStyle:    v.ChartStyle,
+					ChartColor:    v.ChartColor,
+					ChartWidth:    v.ChartWidth,
+					IsPoint:       v.IsPoint,
+					IsNumber:      v.IsNumber,
+					IsAxis:        v.IsAxis,
+					MaxData:       v.MaxData,
+					MinData:       v.MinData,
+					//IsOrder:         false,
+					EdbInfoList: nil,
+					DataList:    nil,
+				}
+				edbInfoList, ok := seriesEdbMap[v.ChartSeriesId]
+				if ok {
+					tmpSeries.EdbInfoList = edbInfoList
+				}
+				seriesList = append(seriesList, tmpSeries)
+			}
+			sectionExtraConfig.SeriesList = seriesList
+
+		} else {
+			err = json.Unmarshal([]byte(extraConfigStr), &sectionExtraConfig)
+			if err != nil {
+				errMsg = "截面组合图配置异常"
+				err = errors.New(errMsg)
+				return
+			}
+		}
+
+		//校验引用日期名称是否重复
+		dateNameMap := make(map[string]int)
+		dateNameEnMap := make(map[string]int)
+		for _, v := range sectionExtraConfig.DateConfList {
+			if _, ok := dateNameMap[v.DateConfName]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfName)
+				return
+			}
+			if _, ok := dateNameEnMap[v.DateConfNameEn]; ok {
+				errMsg = "截面组合图引用日期名称设置重复"
+				err = errors.New(errMsg + v.DateConfNameEn)
+				return
+			}
+			if v.DateConfName != "" {
+				dateNameMap[v.DateConfName] = 1
+			}
+			if v.DateConfNameEn != "" {
+				dateNameEnMap[v.DateConfNameEn] = 1
+			}
+
+		}
+
+		//检查系列名称是否重复
+		seriesNameMap := make(map[string]int)
+		seriesNameEnMap := make(map[string]int)
+		for _, v := range sectionExtraConfig.SeriesList {
+			if _, ok := seriesNameMap[v.SeriesName]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesName)
+				return
+			}
+			if _, ok := seriesNameEnMap[v.SeriesNameEn]; ok {
+				errMsg = "截面组合图系列名称设置重复"
+				err = errors.New(errMsg + v.SeriesNameEn)
+				return
+			}
+			if v.SeriesName != "" {
+				seriesNameMap[v.SeriesName] = 1
+			}
+			if v.SeriesNameEn != "" {
+				seriesNameEnMap[v.SeriesNameEn] = 1
+			}
+		}
+
+		// 检查基准系列是否设置
+		if sectionExtraConfig.BaseChartSeriesName == "" {
+			errMsg = "截面组合图基准系列名称未设置"
+			err = errors.New(errMsg)
+			return
+		}
+		//todo 如果是详情接口,应该要从其他表里查询配置
+		extraConfig = sectionExtraConfig
 	default:
 		xEdbIdValue = make([]int, 0)
 		yDataList = make([]data_manage.YData, 0)
@@ -3271,6 +3736,15 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 
 	// 特殊图形数据处理
 	switch chartType {
+	case 6: //时序组合图
+		//判断是否堆积
+		timeConf := extraConfig.(data_manage.ChartTimeCombineExtraConf)
+		if extraConfigStr == "" { //历史数据,默认开启堆积
+			timeConf = data_manage.ChartTimeCombineExtraConf{
+				IsHeap: 1,
+			}
+		}
+		dataResp = data_manage.ChartTimeCombineDataResp{IsHeap: timeConf.IsHeap}
 	case 2: // 季节性图
 		if seasonExtraConfig != "" {
 			// 季节性图计算不管图上数据时间,拿所有数据
@@ -3320,6 +3794,22 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 			return
 		}
 
+		// 这个数据没有必要返回给前端
+		for _, v := range edbList {
+			v.DataList = nil
+		}
+	case utils.CHART_TYPE_SECTION_COMBINE: // 截面组合图
+		sectionConf := extraConfig.(data_manage.ChartSectionAllExtraConf)
+		var chartInfo *data_manage.ChartInfo
+		if chartInfoId > 0 {
+			chartInfo, err = data_manage.GetChartInfoById(chartInfoId)
+			if err != nil {
+				errMsg = "获取图表信息失败"
+				return
+			}
+		}
+		xEdbIdValue, dataResp, err = GetChartSectionCombineData(chartInfo, mappingList, edbDataListMap, sectionConf)
+
 		// 这个数据没有必要返回给前端
 		for _, v := range edbList {
 			v.DataList = nil
@@ -3331,7 +3821,6 @@ func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate
 	return
 }
 
-
 // SeasonChartData 季节性图的数据处理
 func SeasonChartData(dataList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (dataResp data_manage.SeasonChartResp, err error) {
 	var seasonConfig data_manage.SeasonExtraItem
@@ -3897,7 +4386,6 @@ func HandleDateChange(date string, edbDateConf data_manage.EdbDateChangeConf) (n
 	return
 }
 
-
 // handleSystemAppointDateT
 // @Description: 处理系统日期相关的指定频率(所在周/旬/月/季/半年/年的最后/最早一天)
 // @author: Roc
@@ -4025,4 +4513,4 @@ func handleSystemAppointDateT2(currDate time.Time, appointDay, frequency string)
 	}
 
 	return
-}
+}

+ 112 - 0
services/data/cross_variety/chart.go

@@ -650,6 +650,62 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 		}
 	}
 
+	// 数据校验(品种、标签、指标)
+	{
+		// 标签m
+		var xTagInfo, yTagInfo *cross_varietyModel.ChartTag
+		{
+			tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY})
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range tagList {
+				if v.ChartTagId == req.TagX {
+					xTagInfo = v
+				} else if v.ChartTagId == req.TagY {
+					yTagInfo = v
+				}
+			}
+		}
+		if xTagInfo == nil {
+			errMsg = "找不到对应的X轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+		if yTagInfo == nil {
+			errMsg = "找不到对应的Y轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+
+		_, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList)
+		if tmpErr != nil {
+			err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(edbInfoIdList) <= 0 {
+			errMsg = "品种未配置指标"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+		if tmpErr != nil {
+			errMsg = "获取指标信息失败"
+			err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(mappingList) <= 0 {
+			errMsg = "关联指标为空"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+	}
+
 	var chartInfoId int
 	// 判断图表是否存在
 	//var condition string
@@ -850,6 +906,62 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string)
 		return
 	}
 
+	// 数据校验(品种、标签、指标)
+	{
+		// 标签m
+		var xTagInfo, yTagInfo *cross_varietyModel.ChartTag
+		{
+			tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY})
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range tagList {
+				if v.ChartTagId == req.TagX {
+					xTagInfo = v
+				} else if v.ChartTagId == req.TagY {
+					yTagInfo = v
+				}
+			}
+		}
+		if xTagInfo == nil {
+			errMsg = "找不到对应的X轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+		if yTagInfo == nil {
+			errMsg = "找不到对应的Y轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+
+		_, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList)
+		if tmpErr != nil {
+			err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(edbInfoIdList) <= 0 {
+			errMsg = "品种未配置指标"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+		if tmpErr != nil {
+			errMsg = "获取指标信息失败"
+			err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(mappingList) <= 0 {
+			errMsg = "关联指标为空"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+	}
+
 	//判断图表是否存在
 	//var condition string
 	//var pars []interface{}

+ 44 - 44
services/data/edb_data.go

@@ -518,6 +518,50 @@ func getPageDataByMongo(edbInfoId, source, subSource int, endDataTime string, st
 	return
 }
 
+func getThsHfPageDataByMongo(edbInfoId, source, subSource int, endDataTime string, startSize, pageSize int) (dataCount int, dataList []*data_manage.EdbData, err error) {
+	dataList = make([]*data_manage.EdbData, 0)
+
+	mogDataObj := mgo.EdbDataThsHf{}
+	// 构建查询条件
+	queryConditions := bson.M{
+		"edb_info_id": edbInfoId,
+	}
+
+	// 结束日期
+	dateCondition, err := mgo.BuildDateCondition("", endDataTime)
+	if err != nil {
+		return
+	}
+	if len(dateCondition) > 0 {
+		queryConditions["data_time"] = dateCondition
+	}
+
+	// 获取数据总量
+	tmpCount, tmpErr := mogDataObj.GetCountDataList(queryConditions)
+	if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+		err = tmpErr
+		return
+	}
+	dataCount = int(tmpCount)
+
+	// 获取列表数据
+	tmpDataList, tmpErr := mogDataObj.GetPageDataList(queryConditions, int64(startSize), int64(pageSize), []string{"-data_time"})
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	for k, v := range tmpDataList {
+		dataList = append(dataList, &data_manage.EdbData{
+			EdbDataId: k + 1,
+			EdbInfoId: v.EdbInfoId,
+			DataTime:  v.DataTime.Format(utils.FormatDate),
+			Value:     v.Value,
+		})
+	}
+
+	return
+}
+
 // GetEdbDataTbzForSeason 获取指标的同比值数据
 func GetEdbDataTbzForSeason(frequency string, tmpDataList []*data_manage.EdbDataList, startDateTime time.Time) (dataList []*data_manage.EdbDataList, minValue, maxValue float64, err error) {
 	dataList = make([]*data_manage.EdbDataList, 0)
@@ -623,47 +667,3 @@ func GetEdbDataTbzForSeason(frequency string, tmpDataList []*data_manage.EdbData
 
 	return
 }
-
-func getThsHfPageDataByMongo(edbInfoId, source, subSource int, endDataTime string, startSize, pageSize int) (dataCount int, dataList []*data_manage.EdbData, err error) {
-	dataList = make([]*data_manage.EdbData, 0)
-
-	mogDataObj := mgo.EdbDataThsHf{}
-	// 构建查询条件
-	queryConditions := bson.M{
-		"edb_info_id": edbInfoId,
-	}
-
-	// 结束日期
-	dateCondition, err := mgo.BuildDateCondition("", endDataTime)
-	if err != nil {
-		return
-	}
-	if len(dateCondition) > 0 {
-		queryConditions["data_time"] = dateCondition
-	}
-
-	// 获取数据总量
-	tmpCount, tmpErr := mogDataObj.GetCountDataList(queryConditions)
-	if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
-		err = tmpErr
-		return
-	}
-	dataCount = int(tmpCount)
-
-	// 获取列表数据
-	tmpDataList, tmpErr := mogDataObj.GetPageDataList(queryConditions, int64(startSize), int64(pageSize), []string{"-data_time"})
-	if tmpErr != nil {
-		err = tmpErr
-		return
-	}
-	for k, v := range tmpDataList {
-		dataList = append(dataList, &data_manage.EdbData{
-			EdbDataId: k + 1,
-			EdbInfoId: v.EdbInfoId,
-			DataTime:  v.DataTime.Format(utils.FormatDate),
-			Value:     v.Value,
-		})
-	}
-
-	return
-}

+ 30 - 0
services/data/edb_info_record.go

@@ -0,0 +1,30 @@
+package data
+
+import (
+	"eta/eta_mobile/models/data_manage"
+	"time"
+)
+
+func AddEditEdbInfoRcord(oldEdbInfo *data_manage.EdbInfo, newEdbInfo *data_manage.EdbInfoEditRecord) (err error) {
+	if oldEdbInfo.EdbName != newEdbInfo.EdbName || oldEdbInfo.Frequency != newEdbInfo.Frequency || oldEdbInfo.Unit != newEdbInfo.Unit {
+		ctime := time.Now()
+		edbRecord := new(data_manage.EdbInfoRecord)
+		edbRecord.EdbInfoId = oldEdbInfo.EdbInfoId
+		edbRecord.OldEdbName = oldEdbInfo.EdbName
+		edbRecord.OldFrequency = oldEdbInfo.Frequency
+		edbRecord.OldUnit = oldEdbInfo.Unit
+		edbRecord.NewEdbName = newEdbInfo.EdbName
+		edbRecord.NewFrequency = newEdbInfo.Frequency
+		edbRecord.NewUnit = newEdbInfo.Unit
+		edbRecord.OperateUserId = newEdbInfo.OperateUserId
+		edbRecord.OperateUserRealName = newEdbInfo.OperateUserRealName
+		edbRecord.CreateTime = ctime
+		edbRecord.Timestamp = ctime.Unix()
+		err = data_manage.AddEditEdbInfoRcord(edbRecord)
+		if err != nil {
+			return
+		}
+		err = data_manage.ModifyEdbInfoBaseTimeById(edbRecord.EdbInfoId, ctime)
+	}
+	return
+}

+ 212 - 119
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, //todo baseEdbInfoMapping
+			Frequency:           baseEdbInfoMapping.Frequency,
+			FrequencyEn:         baseEdbInfoMapping.FrequencyEn,
+			Unit:                baseEdbInfoMapping.Unit,
+			UnitEn:              baseEdbInfoMapping.UnitEn,
 			StartDate:           v.StartDate,
 			EndDate:             v.EndDate,
 			ModifyTime:          v.ModifyTime.Format(utils.FormatDateTime),
 			ChartEdbMappingId:   v.FutureGoodEdbInfoId,
-			ChartInfoId:         edbInfoMapping.ChartInfoId,
+			ChartInfoId:         baseEdbInfoMapping.ChartInfoId,
 			MaxData:             v.MaxValue,
 			MinData:             v.MinValue,
-			IsOrder:             edbInfoMapping.IsOrder,
-			IsAxis:              edbInfoMapping.IsAxis,
-			EdbInfoType:         edbInfoMapping.EdbInfoType,
-			EdbInfoCategoryType: edbInfoMapping.EdbInfoCategoryType,
-			LeadValue:           edbInfoMapping.LeadValue,
-			LeadUnit:            edbInfoMapping.LeadUnit,
-			LeadUnitEn:          edbInfoMapping.LeadUnitEn,
-			ChartStyle:          edbInfoMapping.ChartStyle,
-			ChartColor:          edbInfoMapping.ChartColor,
-			PredictChartColor:   edbInfoMapping.PredictChartColor,
-			ChartWidth:          edbInfoMapping.ChartWidth,
-			ChartType:           edbInfoMapping.ChartType,
+			IsOrder:             baseEdbInfoMapping.IsOrder,
+			IsAxis:              baseEdbInfoMapping.IsAxis,
+			EdbInfoType:         baseEdbInfoMapping.EdbInfoType,
+			EdbInfoCategoryType: baseEdbInfoMapping.EdbInfoCategoryType,
+			LeadValue:           baseEdbInfoMapping.LeadValue,
+			LeadUnit:            baseEdbInfoMapping.LeadUnit,
+			LeadUnitEn:          baseEdbInfoMapping.LeadUnitEn,
+			ChartStyle:          baseEdbInfoMapping.ChartStyle,
+			ChartColor:          baseEdbInfoMapping.ChartColor,
+			PredictChartColor:   baseEdbInfoMapping.PredictChartColor,
+			ChartWidth:          baseEdbInfoMapping.ChartWidth,
+			ChartType:           baseEdbInfoMapping.ChartType,
 			LatestDate:          v.LatestDate.Format(utils.FormatDateTime),
 			LatestValue:         v.LatestValue,
 			UniqueCode:          futureGoodEdbInfoMapping.UniqueCode + strconv.Itoa(k),
@@ -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,22 +263,42 @@ 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 {
+		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, tmpErr := future_good2.GetFutureGoodEdbDataListByDate(v.EdbInfoId, startDate, endDate)
-		if tmpErr != nil {
+		tmpDataList, ok := tmpDataListMap[v.EdbInfoId]
+		if !ok {
+			err = fmt.Errorf("期货数据不存在 FutureGoodEdbInfoId: %d", v.EdbInfoId)
 			return
 		}
 		for _, tmpData := range tmpDataList {
@@ -259,14 +314,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 +357,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,7 +388,7 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 
 		for i := lenEdbId - 1; i >= 0; i-- {
 			// 如果没有在无数据的指标列表中找到,那么就找到了最大x轴的下标
-			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok {
+			if _, ok := noDataEdbIdMap[edbInfoIdList[i]]; !ok || utils.InArrayByInt(baseEdbIds, edbInfoIdList[i]) {
 				// 如果最大x轴的下标 小于 当前下标,那么就重新赋值
 				if maxIndex < i-1 {
 					maxIndex = i - 1
@@ -362,34 +424,43 @@ 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[string]float64)
+	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 edbInfoId == edbInfoMapping.EdbInfoId {
+		if _, ok1 := edbInfoMappingMap[edbInfoId]; ok1 {
+			edbDateData := make(map[string]float64)
 			for _, edbData := range edbDataList {
-				baseEdbDataMap[edbData.DataTime] = edbData.Value
+				edbDateData[edbData.DataTime] = edbData.Value
 			}
+			baseEdbDataMap[edbInfoId] = edbDateData
 		}
 	}
 
 	// 期货指标数据map
 	futureGoodEdbDataMap := make(map[int]map[string]float64)
 	for edbInfoId, edbDataList := range edbDataListMap {
-		if edbInfoId == edbInfoMapping.EdbInfoId {
+		if _, ok := edbInfoMappingMap[edbInfoId]; ok {
 			continue
 		}
 		edbDateData := make(map[string]float64)
@@ -401,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)
 	}
@@ -442,19 +516,35 @@ 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], baseEdbDataMap, futureGoodEdbDataMap)
+		// 先找到基准日期
+		var realDateTime time.Time
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[baseEdbInfoMapping.EdbInfoId], baseEdbDataMap[baseEdbInfoMapping.EdbInfoId], futureGoodEdbDataMap)
 		if tmpErr != nil {
 			err = tmpErr
 			return
 		}
-		findDataList = append(findDataList, findDataValue)
-		yDataMap[edbInfoMapping.EdbInfoId] = findDataValue
-		if isFind {
-			maxDate = realDateTime
-		} else {
-			noDataIdList = append(noDataIdList, edbInfoMapping.EdbInfoId)
-			noDataIdMap[edbInfoMapping.EdbInfoId] = edbInfoMapping.EdbInfoId
+		// 处理其余现货指标
+		for _, v := range edbInfoMappingList {
+			if v.EdbInfoId == baseEdbInfoMapping.EdbInfoId {
+				findDataList = append(findDataList, findDataValue)
+				yDataMap[baseEdbInfoMapping.EdbInfoId] = findDataValue
+				if isFind {
+					maxDate = realDateTime
+				} else {
+					noDataIdList = append(noDataIdList, baseEdbInfoMapping.EdbInfoId)
+					noDataIdMap[baseEdbInfoMapping.EdbInfoId] = baseEdbInfoMapping.EdbInfoId
+				}
+				xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId)
+				continue
+			}
+			findDataValueTmp, isFindTmp := baseEdbDataMap[v.EdbInfoId][realDateTime.Format(utils.FormatDate)]
+			findDataList = append(findDataList, findDataValueTmp)
+			yDataMap[v.EdbInfoId] = findDataValueTmp
+			if !isFindTmp {
+				noDataIdList = append(noDataIdList, v.EdbInfoId)
+				noDataIdMap[v.EdbInfoId] = v.EdbInfoId
+			}
+			xEdbInfoIdList = append(xEdbInfoIdList, v.EdbInfoId)
 		}
 		//currMonth := findDateTime.Month() // 当前月份
 		//currYear := findDateTime.Year()   // 当前年份
@@ -463,7 +553,6 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 		currMonth := realDateTime.Month() // 当前月份
 		currYear := realDateTime.Year()   // 当前年份
 
-		xEdbInfoIdList = append(xEdbInfoIdList, edbInfoMapping.EdbInfoId)
 		mList := make([]int, 0) // 间隔月份
 		indexList := make([]int, 0)
 		if regionType == `国内` {
@@ -583,15 +672,15 @@ 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 {
 				break
 			}
+			// todo x轴 内容调整
 			xDataList = append(xDataList, data_manage.XData{
 				Name:   fmt.Sprint("M+", i),
 				NameEn: fmt.Sprint("M+", i),
@@ -620,11 +709,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 {
@@ -696,8 +785,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
 			}
 
@@ -736,12 +825,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 {
@@ -947,11 +1036,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 {
@@ -966,7 +1059,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
 	}

+ 135 - 41
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, edbDataMap)
+		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) // 间隔月份
 
@@ -331,7 +384,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			//计算公式异常,那么就移除该指标
 			if formulaFormStr == `` {
 				//removeDateList = append(removeDateList, sk)
-				//fmt.Println("异常了")
+				fmt.Println("异常了")
 				continue
 			}
 
@@ -384,6 +437,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,
@@ -475,29 +555,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{
@@ -518,7 +606,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]
@@ -532,8 +620,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
@@ -573,10 +665,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 {
@@ -641,6 +734,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 {

+ 2 - 1
utils/constants.go

@@ -160,7 +160,7 @@ const (
 	DATA_SOURCE_PREDICT_CALCULATE_ZSXY                          // 预测指数修匀->73
 	DATA_SOURCE_CALCULATE_ZDYFX                                 // 自定义分析->74
 	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
-	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->76
+	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->78
 	DATA_SOURCE_ICPI                                 = 79       // ICPI消费价格指数->79
 	DATA_SOURCE_BUSINESS                             = 84       // 来源于自有数据
 	DATA_SOURCE_SCI_HQ                               = 88       // 卓创红期
@@ -353,6 +353,7 @@ const (
 	CHART_TYPE_BAR             = 7  //柱形图
 	CHART_TYPE_SECTION_SCATTER = 10 //截面散点图样式
 	CHART_TYPE_RADAR           = 11 //雷达图
+	CHART_TYPE_SECTION_COMBINE = 14 //截面组合图
 )
 
 // 指标类型