Browse Source

新增区间计算图表

xyxie 7 tháng trước cách đây
mục cha
commit
944ca62c0c

+ 20 - 0
controllers/data_manage/range_analysis/chart_classify.go

@@ -489,6 +489,26 @@ func (this *RangeChartClassifyController) DeleteChartClassify() {
 			br.ErrMsg = "删除失败,Err:" + err.Error()
 			return
 		}
+
+		// 删除图表系列
+		chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
+		seriesMappingItem, e := chartSeriesOb.GetItemByChartInfoId(chartInfo.ChartInfoId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+			} else {
+				br.Msg = "删除失败"
+				br.ErrMsg = "获取图表关联失败, Err: " + e.Error()
+				return
+			}
+		} else {
+			factorSeriesOb := new(data_manage.FactorEdbSeries)
+			e = factorSeriesOb.RemoveSeriesAndMappingByFactorEdbSeriesId(seriesMappingItem)
+			if e != nil {
+				br.Msg = "删除失败"
+				br.ErrMsg = "获取图表关联失败, Err: " + e.Error()
+				return
+			}
+		}
 		//删除ES
 		{
 			go data.EsDeleteChartInfo(chartInfo.ChartInfoId)

+ 938 - 4
controllers/data_manage/range_analysis/chart_info.go

@@ -5,9 +5,16 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	"eta/eta_api/services/data/data_manage_permission"
 	rangeServ "eta/eta_api/services/data/range_analysis"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"sort"
+	"strconv"
+	"strings"
 	"time"
 )
 
@@ -118,27 +125,954 @@ func (this *RangeChartChartInfoController) Preview() {
 	chartInfo.ChartType = 1
 
 	// 获取图表x轴y轴
-	xEdbIdValue, dataResp, e := rangeServ.GetChartDataByEdbInfoList(edbInfoMappingList, &req.ExtraConf)
+	edbList, xEdbIdValue, dataResp, e := rangeServ.GetChartDataByEdbInfoList(0, "", "", edbInfoMappingList, &req.ExtraConf)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取区间计算图表, 图表计算值失败, Err:" + e.Error()
 		return
 	}
-	// 完善指标信息
-	edbList, e := rangeServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingList)
+
+	resp := new(data_manage.ChartInfoDetailResp)
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.XEdbIdValue = xEdbIdValue
+	resp.DataResp = dataResp
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Add
+// @Title 新增图表接口
+// @Description 新增图表接口
+// @Param	request	body data_manage.AddChartInfoReq true "type json string"
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /chart_info/add [post]
+func (this *RangeChartChartInfoController) Add() {
+	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
+	}
+	deleteCache := true
+	cacheKey := "CACHE_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			_ = utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(this.Ctx.Input.RequestBody)
+		return
+	}
+	var req data_manage.AddChartInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	chartInfo, err, errMsg, isSendEmail := rangeServ.AddChartInfo(req, utils.CHART_SOURCE_RANGE_ANALYSIS, sysUser, this.Lang)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = req.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "新增区间计算图表"
+		chartLog.Method = this.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = chartInfo.ChartType
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// Edit
+// @Title 编辑图表接口
+// @Description 编辑图表接口
+// @Param	request	body data_manage.EditChartInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /chart_info/edit [post]
+func (this *RangeChartChartInfoController) Edit() {
+	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
+	}
+
+	var req data_manage.EditChartInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	chartItem, err, errMsg, isSendEmail := rangeServ.EditChartInfo(req, sysUser, this.Lang)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartItem.ChartInfoId
+	resp.UniqueCode = chartItem.UniqueCode
+	resp.ChartType = req.ChartType
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(this.Ctx.Input.RequestBody)
+		chartLog.Status = "编辑区间计算图表"
+		chartLog.Method = this.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// Detail
+// @Title 获取图表详情
+// @Description 获取图表详情接口
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Param   DateType   query   int  true       "日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间"
+// @Param   StartDate   query   string  true       "自定义开始日期"
+// @Param   EndDate   query   string  true       "自定义结束日期"
+// @Param   Calendar   query   string  true       "公历/农历"
+// @Param   SeasonStartDate   query   string  true       "季节性图开始日期"
+// @Param   SeasonEndDate   query   string  true       "季节性图结束日期"
+// @Param   EdbInfoId   query   string  true       "指标ID,多个用英文逗号隔开"
+// @Param   ChartType   query   int  true       "生成样式:1:曲线图,2:季节性图"
+// @Success 200 {object} data_manage.ChartInfoDetailResp
+// @router /chart_info/detail [get]
+func (this *RangeChartChartInfoController) Detail() {
+	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
+	}
+	chartInfoId, _ := this.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	dateType, _ := this.GetInt("DateType")
+	fmt.Println("dateType:", dateType)
+
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+	startYear, _ := this.GetInt("StartYear")
+
+	var err error
+	chartInfo := new(data_manage.ChartInfoView)
+	chartInfo, err = data_manage.GetChartInfoViewById(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图被删除,请刷新页面"
+			br.ErrMsg = "图被删除,请刷新页面,Err:" + err.Error()
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+	if dateType <= 0 {
+		dateType = chartInfo.DateType
+	}
+	// 获取主题样式
+	chartTheme, err := data.GetChartThemeConfig(chartInfo.ChartThemeId, utils.CHART_SOURCE_DEFAULT, 1)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取主题信息失败,Err:" + err.Error()
+		return
+	}
+	chartInfo.ChartThemeStyle = chartTheme.Config
+	chartInfo.ChartThemeId = chartTheme.ChartThemeId
+
+	// 获取指标信息
+	//chartInfo.CorrelationLeadUnit = req.LeadUnit
+	edbInfoMappingList, err := data_manage.GetChartEdbMappingList(chartInfoId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	yearMax := 0
+
+	if dateType == utils.DateTypeNYears {
+		for _, v := range edbInfoMappingList {
+			if v.LatestDate != "" {
+				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
+				if tErr != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
+					return
+				}
+				if lastDateT.Year() > yearMax {
+					yearMax = lastDateT.Year()
+				}
+			}
+		}
+	}
+	// 开始/结束日期
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+
+	// 区间计算图表配置校验
+	var extraConfig data_manage.ChartRangeAnalysisExtraConf
+	if chartInfo.ExtraConfig == `` {
+		br.Msg = "配置信息错误"
+		return
+	}
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConfig)
+	if err != nil {
+		br.Msg = "配置信息错误"
+		br.ErrMsg = "图表配置信息错误,Err:" + err.Error()
+		return
+	}
+
+	// 获取图表数据
+	if len(edbInfoMappingList) == 0 {
+		br.Msg = "获取失败"
+		br.ErrMsg = "图表没有指标,无法计算"
+		return
+	}
+
+	// 获取图表x轴y轴
+	// todo 日期处理,
+	edbList, xEdbIdValue, dataResp, e := rangeServ.GetChartDataByEdbInfoList(chartInfoId, "", "", edbInfoMappingList, &extraConfig)
 	if e != nil {
 		br.Msg = "获取失败"
-		br.ErrMsg = "获取区间计算图表, 完善指标信息失败, Err:" + e.Error()
+		br.ErrMsg = "获取区间计算图表, 图表计算值失败, Err:" + e.Error()
 		return
 	}
 
+	// 判断是否加入我的图库
+	if chartInfoId > 0 && chartInfo != nil {
+		{
+			var myChartCondition string
+			var myChartPars []interface{}
+			myChartCondition += ` AND a.admin_id=? `
+			myChartPars = append(myChartPars, sysUser.AdminId)
+			myChartCondition += ` AND a.chart_info_id=? `
+			myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+			myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+				return
+			}
+			if myChartList != nil && len(myChartList) > 0 {
+				chartInfo.IsAdd = true
+				chartInfo.MyChartId = myChartList[0].MyChartId
+				chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+			}
+		}
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, true)
+	//判断是否需要展示英文标识
+	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
+	// todo 中英文处理
+	chartInfo.UnitEn = extraConfig.DataConvertConf.EnUnit
+
+	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+	// 另存为
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    chartInfo.IsEdit,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	// 指标权限
+	{
+		edbClassifyPermissionMap := make(map[int]data_manage_permission.EdbClassifyPermission)
+		classifyMap := make(map[int]*data_manage.EdbClassify)
+		// 分类
+		{
+			classifyIdList := make([]int, 0)
+			for _, v := range edbList {
+				classifyIdList = append(classifyIdList, v.ClassifyId)
+			}
+			classifyList, tmpErr := data_manage.GetEdbClassifyByIdList(classifyIdList)
+			if tmpErr != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类列表失败,Err:" + tmpErr.Error()
+				return
+			}
+			for _, v := range classifyList {
+				classifyMap[v.ClassifyId] = v
+			}
+		}
+
+		// 遍历到校验map
+		for _, v := range edbList {
+			edbClassifyPermissionMap[v.EdbInfoId] = data_manage_permission.EdbClassifyPermission{
+				ClassifyId:       v.ClassifyId,
+				IsJoinPermission: v.IsJoinPermission,
+				EdbInfoId:        v.EdbInfoId,
+			}
+		}
+
+		// 获取所有有权限的指标和分类
+		permissionEdbIdList, permissionClassifyIdList, err := data_manage_permission.GetUserEdbAndClassifyPermissionList(sysUser.AdminId, 0, 0)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取所有有权限的指标和分类失败,Err:" + err.Error()
+			return
+		}
+
+		for _, v := range edbList {
+			// 数据权限
+			edbItem, ok := edbClassifyPermissionMap[v.EdbInfoId]
+			if !ok {
+				continue
+			}
+
+			if currClassify, ok := classifyMap[edbItem.ClassifyId]; ok {
+				v.HaveOperaAuth = data_manage_permission.CheckEdbPermissionByPermissionIdList(edbItem.IsJoinPermission, currClassify.IsJoinPermission, edbItem.EdbInfoId, edbItem.ClassifyId, permissionEdbIdList, permissionClassifyIdList)
+			}
+		}
+	}
+
+	// 图表当前分类的分类树
+	classifyLevels := make([]string, 0)
+	{
+		list, e := data_manage.GetChartClassifyAllBySource(utils.CHART_SOURCE_RANGE_ANALYSIS)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取图表分类失败, Err: %v", e)
+			return
+		}
+		parents := data.GetChartClassifyParentRecursive(list, chartInfo.ChartClassifyId)
+		sort.Slice(parents, func(i, j int) bool {
+			return parents[i].Level < parents[i].Level
+		})
+		for _, v := range parents {
+			classifyLevels = append(classifyLevels, v.UniqueCode)
+		}
+	}
+
 	resp := new(data_manage.ChartInfoDetailResp)
 	resp.ChartInfo = chartInfo
 	resp.EdbInfoList = edbList
 	resp.XEdbIdValue = xEdbIdValue
 	resp.DataResp = dataResp
+	resp.ClassifyLevels = classifyLevels
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
 	br.Data = resp
+}
+
+// DetailFromUniqueCode
+// @Title 根据编码获取图表详情
+// @Description 根据编码获取图表详情接口
+// @Param   UniqueCode   query   int  true       "图表唯一编码,如果是管理后台访问,传固定字符串:7c69b590249049942070ae9dcd5bf6dc"
+// @Param   IsCache   query   bool  true       "是否走缓存,默认false"
+// @Success 200 {object} data_manage.ChartInfoDetailFromUniqueCodeResp
+// @router /chart_info/detail/from_unique_code [get]
+func (this *RangeChartChartInfoController) DetailFromUniqueCode() {
+	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
+	}
+	adminId := sysUser.AdminId
+
+	uniqueCode := this.GetString("UniqueCode")
+	if uniqueCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,uniqueCode is empty"
+		return
+	}
+
+	//是否走缓存
+	isCache, _ := this.GetBool("IsCache")
+
+	resp := new(data_manage.ChartInfoDetailFromUniqueCodeResp)
+	status := true
+	chartInfo, err := data_manage.GetChartInfoViewByUniqueCode(uniqueCode)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			status = false
+		} else {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+			return
+		}
+	}
+	if chartInfo == nil {
+		status = false
+	}
+	if !status {
+		endInfoList := make([]*data_manage.ChartEdbInfoMapping, 0)
+		resp.EdbInfoList = endInfoList
+		resp.ChartInfo = chartInfo
+		resp.Status = false
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+
+	//判断是否存在缓存,如果存在缓存,那么直接从缓存中获取
+	key := data.GetChartInfoDataKey(chartInfo.ChartInfoId)
+	if utils.Re == nil && isCache {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if d, e := utils.Rc.RedisBytes(key); e == nil {
+				err := json.Unmarshal(d, &resp)
+				if err == nil && resp != nil {
+					// 这里跟当前用户相关的信息重新查询写入resp, 不使用缓存中的
+					var myCond string
+					var myPars []interface{}
+					myCond += ` AND a.admin_id=? `
+					myPars = append(myPars, adminId)
+					myCond += ` AND a.chart_info_id=? `
+					myPars = append(myPars, chartInfo.ChartInfoId)
+					myList, err := data_manage.GetMyChartByCondition(myCond, myPars)
+					if err != nil && err.Error() != utils.ErrNoRow() {
+						br.Msg = "获取失败"
+						br.ErrMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+						return
+					}
+					resp.ChartInfo.IsAdd = false
+					resp.ChartInfo.MyChartId = 0
+					resp.ChartInfo.MyChartClassifyId = ""
+					if myList != nil && len(myList) > 0 {
+						resp.ChartInfo.IsAdd = true
+						resp.ChartInfo.MyChartId = myList[0].MyChartId
+						resp.ChartInfo.MyChartClassifyId = myList[0].MyChartClassifyId
+					}
+
+					br.Ret = 200
+					br.Success = true
+					br.Msg = "获取成功"
+					br.Data = resp
+					return
+				}
+			}
+		}
+	}
+	resp, isOk, msg, errMsg := GetChartInfoDetailFromUniqueCode(chartInfo, isCache, sysUser)
+	if !isOk {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		return
+	}
+	if !isOk {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		return
+	}
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// 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)
+
+	adminId := sysUser.AdminId
+
+	// 指标数据map
+	edbClassifyPermissionMap := make(map[int]data_manage_permission.EdbClassifyPermission)
+	defer func() {
+		if isOk {
+			// 这里跟当前用户相关的信息重新查询写入resp, 不使用缓存中的
+			{
+				//判断是否加入我的图库
+				var myChartCondition string
+				var myChartPars []interface{}
+				myChartCondition += ` AND a.admin_id=? `
+				myChartPars = append(myChartPars, adminId)
+				myChartCondition += ` AND a.chart_info_id=? `
+				myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+				myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					msg = "获取失败"
+					errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+					return
+				}
+				if myChartList != nil && len(myChartList) > 0 {
+					chartInfo.IsAdd = true
+					chartInfo.MyChartId = myChartList[0].MyChartId
+					chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+				}
+			}
+
+			resp.ChartInfo.HaveOperaAuth = true
+
+			// 指标权限
+			{
+				classifyMap := make(map[int]*data_manage.EdbClassify)
+				// 分类
+				{
+					classifyIdList := make([]int, 0)
+					for _, v := range resp.EdbInfoList {
+						classifyIdList = append(classifyIdList, v.ClassifyId)
+					}
+					classifyList, tmpErr := data_manage.GetEdbClassifyByIdList(classifyIdList)
+					if tmpErr != nil {
+						errMsg = "获取分类列表失败,Err:" + tmpErr.Error()
+						return
+					}
+					for _, v := range classifyList {
+						classifyMap[v.ClassifyId] = v
+					}
+				}
+
+				// 指标
+				if len(edbClassifyPermissionMap) < 0 {
+					edbInfoIdList := make([]int, 0)
+					for _, v := range resp.EdbInfoList {
+						edbInfoIdList = append(edbInfoIdList, v.EdbInfoId)
+					}
+					edbInfoList, tmpErr := data_manage.GetEdbInfoByIdList(edbInfoIdList)
+					if tmpErr != nil {
+						errMsg = "获取指标列表失败,Err:" + tmpErr.Error()
+						return
+					}
+					for _, v := range edbInfoList {
+						edbClassifyPermissionMap[v.EdbInfoId] = data_manage_permission.EdbClassifyPermission{
+							ClassifyId:       v.ClassifyId,
+							IsJoinPermission: v.IsJoinPermission,
+							EdbInfoId:        v.EdbInfoId,
+						}
+					}
+				}
+
+				// 获取所有有权限的指标和分类
+				permissionEdbIdList, permissionClassifyIdList, err := data_manage_permission.GetUserEdbAndClassifyPermissionList(sysUser.AdminId, 0, 0)
+				if err != nil {
+					errMsg = "获取所有有权限的指标和分类失败,Err:" + err.Error()
+					return
+				}
+
+				for _, v := range resp.EdbInfoList {
+					// 数据权限
+					edbItem, ok := edbClassifyPermissionMap[v.EdbInfoId]
+					if !ok {
+						continue
+					}
+
+					if currClassify, ok := classifyMap[edbItem.ClassifyId]; ok {
+						v.HaveOperaAuth = data_manage_permission.CheckEdbPermissionByPermissionIdList(edbItem.IsJoinPermission, currClassify.IsJoinPermission, edbItem.EdbInfoId, edbItem.ClassifyId, permissionEdbIdList, permissionClassifyIdList)
+					}
+				}
+			}
+		}
+	}()
+
+	//判断是否存在缓存,如果存在缓存,那么直接从缓存中获取
+	key := data.GetChartInfoDataKey(chartInfo.ChartInfoId)
+	if utils.Re == nil && isCache {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if chartData, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err := json.Unmarshal(chartData, &resp)
+				if err != nil || resp == nil {
+					return
+				}
+				isOk = true
+				fmt.Println("source redis")
+				return
+			}
+		}
+	}
+
+	// 获取主题样式
+	chartTheme, err := data.GetChartThemeConfig(chartInfo.ChartThemeId, utils.CHART_SOURCE_DEFAULT, 1)
+	if err != nil {
+		msg = "获取失败"
+		errMsg = "获取主题信息失败,Err:" + err.Error()
+		return
+	}
+	chartInfo.ChartThemeStyle = chartTheme.Config
+	chartInfo.ChartThemeId = chartTheme.ChartThemeId
+
+	chartInfoId := chartInfo.ChartInfoId
+
+	// 获取指标信息
+	//chartInfo.CorrelationLeadUnit = req.LeadUnit
+	edbInfoMappingList, err := data_manage.GetChartEdbMappingList(chartInfoId)
+	if err != nil {
+		msg = "获取失败"
+		errMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	yearMax := 0
+	dateType := chartInfo.DateType
+	if dateType == utils.DateTypeNYears {
+		for _, v := range edbInfoMappingList {
+			if v.LatestDate != "" {
+				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
+				if tErr != nil {
+					msg = "获取失败"
+					errMsg = "获取图表日期信息失败,Err:" + tErr.Error()
+					return
+				}
+				if lastDateT.Year() > yearMax {
+					yearMax = lastDateT.Year()
+				}
+			}
+		}
+	}
+	// 开始/结束日期
+	startYear := chartInfo.StartYear
+	startDate := chartInfo.StartDate
+	endDate := chartInfo.EndDate
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+
+	// 区间计算图表配置校验
+	var extraConfig data_manage.ChartRangeAnalysisExtraConf
+	if chartInfo.ExtraConfig == `` {
+		msg = "配置信息错误"
+		return
+	}
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &extraConfig)
+	if err != nil {
+		msg = "配置信息错误"
+		errMsg = "图表配置信息错误,Err:" + err.Error()
+		return
+	}
+
+	// 获取图表数据
+	if len(edbInfoMappingList) == 0 {
+		msg = "获取失败"
+		errMsg = "图表没有指标,无法计算"
+
+		return
+	}
+
+	// 获取图表x轴y轴
+	// todo 日期处理,
+	edbList, xEdbIdValue, dataResp, e := rangeServ.GetChartDataByEdbInfoList(chartInfoId, "", "", edbInfoMappingList, &extraConfig)
+	if e != nil {
+		msg = "获取失败"
+		errMsg = "获取区间计算图表, 图表计算值失败, Err:" + e.Error()
+		return
+	}
+
+	if chartInfoId > 0 && chartInfo != nil {
+		//判断是否加入我的图库
+		{
+			var myChartCondition string
+			var myChartPars []interface{}
+			myChartCondition += ` AND a.admin_id=? `
+			myChartPars = append(myChartPars, sysUser.AdminId)
+			myChartCondition += ` AND a.chart_info_id=? `
+			myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+			myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				msg = "获取失败"
+				errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+				return
+			}
+			if myChartList != nil && len(myChartList) > 0 {
+				chartInfo.IsAdd = true
+				chartInfo.MyChartId = myChartList[0].MyChartId
+				chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+			}
+		}
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, true)
+	//判断是否需要展示英文标识
+	chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
+	chartInfo.UnitEn = ""
+
+	// 另存为
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    chartInfo.IsEdit,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	// 图表的指标来源
+	sourceNameList, sourceNameEnList := data.GetEdbSourceByEdbInfoIdList(edbList)
+	chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+	chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+	resp.ChartInfo = chartInfo
+	resp.EdbInfoList = edbList
+	resp.XEdbIdValue = xEdbIdValue
+	resp.DataResp = dataResp
+	resp.Status = true
+
+	// 遍历到校验map
+	for _, v := range edbList {
+		edbClassifyPermissionMap[v.EdbInfoId] = data_manage_permission.EdbClassifyPermission{
+			ClassifyId:       v.ClassifyId,
+			IsJoinPermission: v.IsJoinPermission,
+			EdbInfoId:        v.EdbInfoId,
+		}
+	}
+
+	// 将数据加入缓存
+	if utils.Re == nil {
+		d, _ := json.Marshal(resp)
+		_ = utils.Rc.Put(key, d, 2*time.Hour)
+	}
+	isOk = true
+	return
+}
+
+// List
+// @Title 区间计算图表列表接口
+// @Description 区间计算图表列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ChartClassifyId   query   int  true       "分类id"
+// @Param   Keyword   query   string  true       "搜索关键词"
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Param   Source   query   int  true       "图表类型,3:区间计算,4:滚动区间计算"
+// @Success 200 {object} data_manage.ChartListResp
+// @router /chart_info/list [get]
+func (this *RangeChartChartInfoController) List() {
+	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
+	}
+
+	chartClassifyId, _ := this.GetInt("ChartClassifyId")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	keyword := this.GetString("KeyWord")
+
+	var total int
+	page := paging.GetPaging(currentIndex, pageSize, total)
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	source := utils.CHART_SOURCE_RANGE_ANALYSIS
+
+	var condition string
+	var pars []interface{}
+
+	// 普通图表
+	condition += ` AND source = ? `
+	pars = append(pars, source)
+
+	if chartClassifyId > 0 {
+		chartClassifyId, err := data_manage.GetChartClassify(chartClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取图表信息失败"
+			br.ErrMsg = "获取信息失败,GetChartClassify,Err:" + err.Error()
+			return
+		}
+		condition += " AND chart_classify_id IN(" + chartClassifyId + ") "
+	}
+	if keyword != "" {
+		condition += ` AND  ( chart_name LIKE '%` + keyword + `%' )`
+	}
+
+	//只看我的
+	isShowMe, _ := this.GetBool("IsShowMe")
+	if isShowMe {
+		condition += ` AND sys_user_id = ? `
+		pars = append(pars, sysUser.AdminId)
+	}
+
+	// 获取当前账号的不可见指标
+	noPermissionChartIdList := make([]int, 0)
+	{
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllChartListByAdminId(this.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range confList {
+			noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
+		}
+	}
+
+	lenNoPermissionChartIdList := len(noPermissionChartIdList)
+	if lenNoPermissionChartIdList > 0 {
+		condition += ` AND chart_info_id not in (` + utils.GetOrmInReplace(lenNoPermissionChartIdList) + `) `
+		pars = append(pars, noPermissionChartIdList)
+	}
+
+	//获取图表信息
+	list, err := data_manage.GetChartListByCondition(condition, pars, startSize, pageSize)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Success = true
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	myChartList, err := data_manage.GetMyChartListByAdminId(sysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取我的图表信息失败,Err:" + err.Error()
+		return
+	}
+	myChartMap := make(map[int]*data_manage.MyChartView)
+	for _, v := range myChartList {
+		myChartMap[v.ChartInfoId] = v
+	}
+	listLen := len(list)
+	chartEdbMap := make(map[int][]*data_manage.ChartEdbInfoMapping)
+	if listLen > 0 {
+		chartInfoIds := ""
+		for _, v := range list {
+			chartInfoIds += strconv.Itoa(v.ChartInfoId) + ","
+		}
+		if chartInfoIds != "" {
+			chartInfoIds = strings.Trim(chartInfoIds, ",")
+			//判断是否需要展示英文标识
+			edbList, e := data_manage.GetChartEdbMappingListByChartInfoIds(chartInfoIds)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + e.Error()
+				return
+			}
+			for _, v := range edbList {
+				chartEdbMap[v.ChartInfoId] = append(chartEdbMap[v.ChartInfoId], v)
+			}
+		}
+	}
+	for i := 0; i < listLen; i++ {
+		//判断是否需要展示英文标识
+		if edbTmpList, ok := chartEdbMap[list[i].ChartInfoId]; ok {
+			list[i].IsEnChart = data.CheckIsEnChart(list[i].ChartNameEn, edbTmpList, list[i].Source, list[i].ChartType)
+		}
+
+		if existItem, ok := myChartMap[list[i].ChartInfoId]; ok {
+			list[i].IsAdd = true
+			list[i].MyChartId = existItem.MyChartId
+			list[i].MyChartClassifyId = existItem.MyChartClassifyId
+		}
+	}
+
+	resp := new(data_manage.ChartListResp)
+	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
+		items := make([]*data_manage.ChartInfoView, 0)
+		resp.Paging = page
+		resp.List = items
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		return
+	}
+
+	dataCount, err := data_manage.GetChartListCountByCondition(condition, pars)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
+		return
+	}
+	page = paging.GetPaging(currentIndex, pageSize, dataCount)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
 }

+ 196 - 4
models/data_manage/chart_info_range_analysis.go

@@ -1,6 +1,13 @@
 package data_manage
 
-import "time"
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
+	"time"
+)
 
 type ChartRangeAnalysisExtraConf struct {
 	EdbInfoMode          int                                `description:"指标模式 0: 单指标,1: 多指标"`
@@ -13,7 +20,8 @@ type ChartRangeAnalysisExtraConf struct {
 	UnNormalDataConf     ChartRangeAnalysisDeleteDataConf
 	DataConvertType      int                               `description:"数据转换类型 0不转, 1乘 2除 3对数"`
 	DataConvertConf      ChartRangeAnalysisDataConvertConf `description:"数据转换详情"`
-	SeriesId             int                               `description:"指标系列ID"`
+	SeriesName           string                            `description:"指标系列名称"`
+	EdbInfoIds           []int
 }
 
 type ChartRangeAnalysisAutoDateChangeConf struct {
@@ -61,8 +69,9 @@ type ChartRangeAnalysisYearDateConf struct {
 
 // ChartRangeAnalysisPreviewReq 相关性图表请求体
 type ChartRangeAnalysisPreviewReq struct {
-	ExtraConf  ChartRangeAnalysisExtraConf
-	EdbInfoIds []int `description:"指标Id"`
+	ExtraConf   ChartRangeAnalysisExtraConf
+	EdbInfoIds  []int `description:"指标Id"`
+	EdbInfoType int
 }
 
 type ChartRangeAnalysisManualDateConfList []ChartRangeAnalysisManualDateConf
@@ -83,3 +92,186 @@ type ChartRangeAnalysisDateDataItem struct {
 	EndDate   time.Time
 	DataList  []*EdbDataList
 }
+
+// CreateRangeChartAndEdb 新增区间计算图表
+func CreateRangeChartAndEdb(chartInfo *ChartInfo, edbMappingList []*ChartEdbMapping) (chartInfoId int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+		} else {
+			_ = tx.Commit()
+		}
+	}()
+
+	// 新增图表信息
+	newId, err := tx.Insert(chartInfo)
+	if err != nil {
+		return
+	}
+	// 指标mapping
+	chartInfo.ChartInfoId = int(newId)
+	chartInfoId = int(newId)
+	if len(edbMappingList) > 0 {
+		for i := range edbMappingList {
+			edbMappingList[i].ChartInfoId = chartInfoId
+		}
+		_, err = tx.InsertMulti(len(edbMappingList), edbMappingList)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+// EditRangeChartInfoAndMapping 修改区间计算图表的 图表与指标 的关系
+func EditRangeChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr, lang string, calendar string, dateType, disabled int, barChartConf string) (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 pars []interface{}
+	pars = append(pars, req.ChartName)
+	pars = append(pars, edbInfoIdStr)
+	pars = append(pars, req.ChartType)
+	pars = append(pars, req.ChartClassifyId)
+	pars = append(pars, disabled)
+	pars = append(pars, barChartConf)
+	pars = append(pars, req.ExtraConfig)
+	pars = append(pars, req.SourcesFrom)
+
+	sql := ` UPDATE  chart_info
+			SET
+			  chart_name =?,
+              edb_info_ids=?,
+			  chart_type=?,
+			  chart_classify_id = ?,
+			  modify_time = NOW(),
+              disabled = ?,
+              bar_config = ?,
+			  extra_config = ?,
+			  sources_from = ?
+			`
+	if calendar != "" {
+		sql += `,calendar = ? `
+		pars = append(pars, calendar)
+	}
+	if dateType > 0 {
+		sql += `,date_type = ? `
+		pars = append(pars, dateType)
+	}
+
+	sql += `,start_date = ? `
+	pars = append(pars, req.StartDate)
+
+	sql += `,end_date = ? `
+	pars = append(pars, req.EndDate)
+
+	sql += `,season_start_date = ? `
+	pars = append(pars, req.StartDate)
+
+	sql += `,season_end_date = ? `
+	pars = append(pars, req.EndDate)
+
+	sql += `,left_min = ? `
+	pars = append(pars, req.LeftMin)
+
+	sql += `,left_max = ? `
+	pars = append(pars, req.LeftMax)
+
+	sql += `,right_min = ? `
+	pars = append(pars, req.RightMin)
+
+	sql += `,right_max = ? `
+	pars = append(pars, req.RightMax)
+
+	sql += `WHERE chart_info_id = ?`
+
+	pars = append(pars, req.ChartInfoId)
+	_, err = to.Raw(sql, pars).Exec()
+	if err != nil {
+		fmt.Println("UPDATE  chart_info Err:", err.Error())
+		return err
+	}
+	chartEdbMappingIdList := make([]string, 0)
+	for _, v := range req.ChartEdbInfoList {
+		// 查询该指标是否存在,如果存在的话,那么就去修改,否则新增
+		var tmpChartEdbMapping *ChartEdbMapping
+		csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND edb_info_id=? AND source = ? `
+		err = to.Raw(csql, req.ChartInfoId, v.EdbInfoId, utils.CHART_SOURCE_RANGE_ANALYSIS).QueryRow(&tmpChartEdbMapping)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			fmt.Println("QueryRow Err:", err.Error())
+			return err
+		}
+		if tmpChartEdbMapping != nil {
+			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(tmpChartEdbMapping.ChartEdbMappingId))
+			//tmpChartEdbMapping.ModifyTime = time.Now()
+			//tmpChartEdbMapping.MaxData = v.MaxData
+			//tmpChartEdbMapping.MinData = v.MinData
+			//tmpChartEdbMapping.IsOrder = v.IsOrder
+			//tmpChartEdbMapping.IsAxis = v.IsAxis
+			//tmpChartEdbMapping.EdbInfoType = v.EdbInfoType
+			//tmpChartEdbMapping.LeadValue = v.LeadValue
+			//tmpChartEdbMapping.LeadUnit = v.LeadUnit
+			//tmpChartEdbMapping.ChartStyle = v.ChartStyle
+			//tmpChartEdbMapping.ChartColor = v.ChartColor
+			//tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
+			//tmpChartEdbMapping.ChartWidth = v.ChartWidth
+			//_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth")
+			//if err != nil {
+			//	fmt.Println("chart_edb_mapping Err:" + err.Error())
+			//	return err
+			//}
+		} else {
+			mapItem := new(ChartEdbMapping)
+			mapItem.ChartInfoId = req.ChartInfoId
+			mapItem.EdbInfoId = v.EdbInfoId
+			mapItem.CreateTime = time.Now()
+			mapItem.ModifyTime = time.Now()
+			timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+			mapItem.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp + "_" + strconv.Itoa(v.EdbInfoId))
+			//mapItem.MaxData = v.MaxData
+			//mapItem.MinData = v.MinData
+			mapItem.IsOrder = true
+			mapItem.IsAxis = 1
+			mapItem.EdbInfoType = 1
+			//mapItem.LeadValue = v.LeadValue
+			//mapItem.LeadUnit = v.LeadUnit
+			//mapItem.ChartStyle = v.ChartStyle
+			//mapItem.ChartColor = v.ChartColor
+			//mapItem.PredictChartColor = v.PredictChartColor
+			//mapItem.ChartWidth = v.ChartWidth
+			mapItem.Source = utils.CHART_SOURCE_RANGE_ANALYSIS
+			tmpId, err := to.Insert(mapItem)
+			if err != nil {
+				fmt.Println("AddChartEdbMapping Err:" + err.Error())
+				return err
+			}
+			mapItem.ChartEdbMappingId = int(tmpId)
+			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(mapItem.ChartEdbMappingId))
+		}
+	}
+	if len(chartEdbMappingIdList) > 0 {
+		chartEdbMappingIdStr := strings.Join(chartEdbMappingIdList, ",")
+		dsql := `DELETE FROM chart_edb_mapping WHERE chart_info_id=? AND chart_edb_mapping_id NOT IN(` + chartEdbMappingIdStr + `)`
+		_, err = to.Raw(dsql, req.ChartInfoId).Exec()
+		if err != nil {
+			fmt.Println("delete err:" + err.Error())
+			return err
+		}
+	}
+
+	return
+}

+ 62 - 0
models/data_manage/factor_edb_series.go

@@ -349,3 +349,65 @@ func (a FactorEdbSeriesCorrelationMatrixOrder) Less(i, j int) bool {
 	// 负数按绝对值的降序排序(即数值的升序)
 	return a[i].XData > a[j].XData
 }
+
+// RemoveSeriesAndMappingByFactorEdbSeriesId 删除系列和指标关联
+func (m *FactorEdbSeries) RemoveSeriesAndMappingByFactorEdbSeriesId(factorEdbSeriesChartMapping *FactorEdbSeriesChartMapping) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("orm begin err: %v", e)
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+	factorEdbSeriesId := factorEdbSeriesChartMapping.FactorEdbSeriesId
+	err = factorEdbSeriesChartMapping.Remove()
+	if err != nil {
+		err = fmt.Errorf("factorEdbSeriesChartMapping.delete err: %v", err)
+		return
+	}
+	if factorEdbSeriesId == 0 {
+		return
+	}
+
+	// 清除原指标关联
+	seriesOb := new(FactorEdbSeries)
+	cond := fmt.Sprintf("%s = ?", seriesOb.Cols().PrimaryId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, factorEdbSeriesId)
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, seriesOb.TableName(), cond)
+	_, e = tx.Raw(sql, pars).Exec()
+	if e != nil {
+		err = fmt.Errorf("remove FactorEdbSeries err: %v", e)
+		return
+	}
+
+	// 清除原指标关联
+	mappingOb := new(FactorEdbSeriesMapping)
+	cond1 := fmt.Sprintf("%s = ?", mappingOb.Cols().FactorEdbSeriesId)
+	pars1 := make([]interface{}, 0)
+	pars1 = append(pars1, factorEdbSeriesId)
+	sql = fmt.Sprintf(`DELETE FROM %s WHERE %s`, mappingOb.TableName(), cond1)
+	_, e = tx.Raw(sql, pars1).Exec()
+	if e != nil {
+		err = fmt.Errorf("remove mapping err: %v", e)
+		return
+	}
+	dataOb := new(FactorEdbSeriesCalculateDataQjjs)
+	//删除原指标数据
+	cond2 := fmt.Sprintf("%s = ?", dataOb.Cols().FactorEdbSeriesId)
+	pars2 := make([]interface{}, 0)
+	pars2 = append(pars2, factorEdbSeriesId)
+	sql = fmt.Sprintf(`DELETE FROM %s WHERE %s`, dataOb.TableName(), cond2)
+	_, e = tx.Raw(sql, pars2).Exec()
+	if e != nil {
+		err = fmt.Errorf("remove mapping err: %v", e)
+		return
+	}
+	return
+}

+ 210 - 0
models/data_manage/factor_edb_series_calculate_data_qjjs.go

@@ -0,0 +1,210 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// FactorEdbSeriesCalculateDataQjjs 因子指标系列-区间计算数据表
+type FactorEdbSeriesCalculateDataQjjs struct {
+	FactorEdbSeriesCalculateDataId int       `orm:"column(factor_edb_series_calculate_data_id);pk"`
+	FactorEdbSeriesId              int       `description:"因子指标系列ID"`
+	EdbInfoId                      int       `description:"指标ID"`
+	EdbCode                        string    `description:"指标编码"`
+	DataTime                       time.Time `description:"数据日期"`
+	Value                          float64   `description:"数据值"`
+	CreateTime                     time.Time `description:"创建时间"`
+	ModifyTime                     time.Time `description:"修改时间"`
+	DataTimestamp                  int64     `description:"数据日期时间戳"`
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) TableName() string {
+	return "factor_edb_series_calculate_data_qjjs"
+}
+
+type FactorEdbSeriesCalculateDataQjjsCols struct {
+	PrimaryId         string
+	FactorEdbSeriesId string
+	EdbInfoId         string
+	EdbCode           string
+	DataTime          string
+	Value             string
+	CreateTime        string
+	ModifyTime        string
+	DataTimestamp     string
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Cols() FactorEdbSeriesCalculateDataCols {
+	return FactorEdbSeriesCalculateDataCols{
+		PrimaryId:         "factor_edb_series_calculate_data_id",
+		FactorEdbSeriesId: "factor_edb_series_id",
+		EdbInfoId:         "edb_info_id",
+		EdbCode:           "edb_code",
+		DataTime:          "data_time",
+		Value:             "value",
+		CreateTime:        "create_time",
+		ModifyTime:        "modify_time",
+		DataTimestamp:     "data_timestamp",
+	}
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FactorEdbSeriesCalculateDataId = int(id)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) CreateMulti(items []*FactorEdbSeriesCalculateDataQjjs) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(500, items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Remove() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	_, err = o.Raw(sql, m.FactorEdbSeriesCalculateDataId).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) MultiRemove(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.Cols().PrimaryId, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) RemoveByCondition(condition string, pars []interface{}) (err error) {
+	if condition == "" {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s`, m.TableName(), condition)
+	_, err = o.Raw(sql, pars).Exec()
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemById(id int) (item *FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().PrimaryId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FactorEdbSeriesCalculateDataQjjs, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, m.Cols().CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// FactorEdbSeriesCalculateDataQjjsItem 因子指标系列-计算数据信息
+type FactorEdbSeriesCalculateDataQjjsItem struct {
+	DataId            int     `description:"数据ID"`
+	FactorEdbSeriesId int     `description:"因子指标系列ID"`
+	EdbInfoId         int     `description:"指标ID"`
+	EdbCode           string  `description:"指标编码"`
+	DataTime          string  `description:"数据日期"`
+	Value             float64 `description:"数据值"`
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) Format2Item() (item *FactorEdbSeriesCalculateDataQjjsItem) {
+	item = new(FactorEdbSeriesCalculateDataQjjsItem)
+	item.DataId = m.FactorEdbSeriesCalculateDataId
+	item.FactorEdbSeriesId = m.FactorEdbSeriesId
+	item.EdbInfoId = m.EdbInfoId
+	item.EdbCode = m.EdbCode
+	return
+}
+
+// TransEdbSeriesCalculateDataQjjs2EdbDataList 转换数据格式
+func TransEdbSeriesCalculateDataQjjs2EdbDataList(items []*FactorEdbSeriesCalculateDataQjjs) (list []*EdbDataList) {
+	list = make([]*EdbDataList, 0)
+	for _, v := range items {
+		list = append(list, &EdbDataList{
+			DataTime: v.DataTime.Format(utils.FormatDate),
+			Value:    v.Value,
+		})
+	}
+	return
+}
+
+func (m *FactorEdbSeriesCalculateDataQjjs) GetEdbDataList(seriesId int, edbInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	var pars []interface{}
+	sql := `SELECT factor_edb_series_calculate_data_id as edb_data_id  ,edb_info_id,data_time,value,data_timestamp FROM %s WHERE edb_info_id=? and factor_edb_series_id=? `
+	pars = append(pars, edbInfoId, seriesId)
+	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 `
+	sql = fmt.Sprintf(sql, m.TableName())
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
+}

+ 8 - 0
models/data_manage/factor_edb_series_chart_mapping.go

@@ -10,6 +10,7 @@ import (
 
 const (
 	FactorEdbSeriesChartCalculateTypeCorrelation = 1 // 相关性计算
+	FactorEdbSeriesChartCalculateTypeRange       = 2 // 	区间计算
 )
 
 // FactorEdbSeriesChartMapping 因子指标系列-图表关联
@@ -110,6 +111,13 @@ func (m *FactorEdbSeriesChartMapping) GetItemById(id int) (item *FactorEdbSeries
 	return
 }
 
+func (m *FactorEdbSeriesChartMapping) GetItemByChartInfoId(id int) (item *FactorEdbSeriesChartMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().ChartInfoId)
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
 func (m *FactorEdbSeriesChartMapping) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FactorEdbSeriesChartMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
 	order := ``

+ 7 - 0
models/data_manage/factor_edb_series_mapping.go

@@ -165,3 +165,10 @@ func (m *FactorEdbSeriesMapping) Format2Item() (item *FactorEdbSeriesMappingItem
 	item.EdbCode = m.EdbCode
 	return
 }
+
+func (m *FactorEdbSeriesMapping) GetItemBySeriesId(seriesId int) (items []*FactorEdbSeriesMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().FactorEdbSeriesId)
+	_, err = o.Raw(sql, seriesId).QueryRows(&items)
+	return
+}

+ 5 - 4
models/db.go

@@ -607,9 +607,10 @@ func initFeCalendar() {
 // initFactorEdbSeries 因子指标系列数据表
 func initFactorEdbSeries() {
 	orm.RegisterModel(
-		new(data_manage.FactorEdbSeries),              // 因子指标系列
-		new(data_manage.FactorEdbSeriesChartMapping),  // 因子指标系列-图表关联
-		new(data_manage.FactorEdbSeriesMapping),       // 因子指标系列-指标计算数据
-		new(data_manage.FactorEdbSeriesCalculateData), // 因子指标系列-指标关联
+		new(data_manage.FactorEdbSeries),                  // 因子指标系列
+		new(data_manage.FactorEdbSeriesChartMapping),      // 因子指标系列-图表关联
+		new(data_manage.FactorEdbSeriesMapping),           // 因子指标系列-指标计算数据
+		new(data_manage.FactorEdbSeriesCalculateData),     // 因子指标系列-指标关联
+		new(data_manage.FactorEdbSeriesCalculateDataQjjs), // 因子指标系列-区间计算数据
 	)
 }

+ 45 - 0
routers/commentsRouter.go

@@ -1843,6 +1843,51 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/chart_info/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/chart_info/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "DetailFromUniqueCode",
+            Router: `/chart_info/detail/from_unique_code`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/chart_info/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/chart_info/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
         beego.ControllerComments{
             Method: "Preview",

+ 385 - 98
services/data/range_analysis/chart_info.go

@@ -1,12 +1,18 @@
 package range_analysis
 
 import (
+	"encoding/json"
 	"errors"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"math"
+	"sort"
+	"strconv"
+	"strings"
 	"time"
 )
 
@@ -199,7 +205,6 @@ func GetChartEdbInfoFormat(chartInfoId int, edbInfoMappingList []*data_manage.Ch
 			edbInfoMapping.ChartStyle = ""
 			edbInfoMapping.ChartColor = ""
 			edbInfoMapping.ChartWidth = 0
-
 		} else {
 			edbInfoMapping.LeadUnitEn = data.GetLeadUnitEn(edbInfoMapping.LeadUnit)
 		}
@@ -209,7 +214,11 @@ func GetChartEdbInfoFormat(chartInfoId int, edbInfoMappingList []*data_manage.Ch
 }
 
 // GetChartDataByEdbInfoList 区间计算图表-根据指标信息获取x轴和y轴
-func GetChartDataByEdbInfoList(edbInfoMappingList []*data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (xEdbIdValue []int, dataResp data_manage.ChartRangeAnalysisDataResp, err error) {
+func GetChartDataByEdbInfoList(chartInfoId int, startDate, endDate string, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, dataResp data_manage.ChartRangeAnalysisDataResp, err error) {
+	if chartInfoId > 0 && req.EdbInfoMode == 1 {
+		edbList, xEdbIdValue, dataResp, err = GetChartDataByEdbInfoListBySeries(chartInfoId, startDate, endDate, edbInfoMappingList, req)
+		return
+	}
 	for _, edbInfoMapping := range edbInfoMappingList {
 		edbInfoMapping, err = getChartDataByEdbInfo(edbInfoMapping, req)
 		if err != nil {
@@ -219,6 +228,46 @@ func GetChartDataByEdbInfoList(edbInfoMappingList []*data_manage.ChartEdbInfoMap
 	}
 
 	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req}
+	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
+	if err != nil {
+		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
+		return
+	}
+	return
+}
+
+func GetChartDataByEdbInfoListBySeries(chartInfoId int, startDate, endDate string, edbInfoMappingList []*data_manage.ChartEdbInfoMapping, req *data_manage.ChartRangeAnalysisExtraConf) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, dataResp data_manage.ChartRangeAnalysisDataResp, err error) {
+	//查询seriesId
+	chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
+	seriesMappingItem, err := chartSeriesOb.GetItemByChartInfoId(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			err = fmt.Errorf("图表关联关系不存在")
+			return
+		} else {
+			err = fmt.Errorf("获取图表关联失败, Err: " + err.Error())
+			return
+		}
+	}
+	//根据seriesId查询数据
+	//并把数据放到dataList中
+	for _, edbInfoMapping := range edbInfoMappingList {
+		dataOb := new(data_manage.FactorEdbSeriesCalculateDataQjjs)
+		dataList, e := dataOb.GetEdbDataList(seriesMappingItem.FactorEdbSeriesId, edbInfoMapping.EdbInfoId, startDate, endDate)
+		if e != nil {
+			err = e
+			return
+		}
+		edbInfoMapping.DataList = dataList
+		xEdbIdValue = append(xEdbIdValue, edbInfoMapping.EdbInfoId)
+	}
+
+	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req}
+	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
+	if err != nil {
+		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
+		return
+	}
 	return
 }
 
@@ -508,7 +557,7 @@ func GetChartAndCorrelationInfo(chartInfoId int) (chartInfo *data_manage.ChartIn
 		return
 	}
 	return
-}
+}*/
 
 // AddChartInfo 添加图表
 func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.Admin, lang string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
@@ -537,7 +586,7 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 	err = json.Unmarshal([]byte(req.ExtraConfig), &extraConfig)
 	if err != nil {
 		errMsg = "配置信息错误"
-		err = errors.New(errMsg)
+		err = errors.New(errMsg + ", Err: " + err.Error())
 		return
 	}
 
@@ -548,6 +597,28 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 		return
 	}
 
+	extraConfig.SeriesName = strings.TrimSpace(extraConfig.SeriesName)
+	if extraConfig.SeriesName == "" && extraConfig.EdbInfoMode == 1 {
+		errMsg = "请输入指标系列名称"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+	if len(req.ChartEdbInfoList) > 100 {
+		errMsg = "添加指标总数量不得超过100"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	if extraConfig.CalculateType > 5 || extraConfig.CalculateType < 0 {
+		errMsg = "计算方式参数错误"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
+	}
+
+	//todo 校验时间区间设置
 	chartClassify, err := data_manage.GetChartClassifyById(req.ChartClassifyId)
 	if err != nil {
 		if err.Error() == utils.ErrNoRow() {
@@ -568,6 +639,7 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 	}
 
 	var edbInfoIdArr []int
+
 	for _, v := range req.ChartEdbInfoList {
 		edbInfoId := v.EdbInfoId
 		edbInfo, tmpErr := data_manage.GetEdbInfoById(edbInfoId)
@@ -673,6 +745,7 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 	// 指标信息
 	mapList := make([]*data_manage.ChartEdbMapping, 0)
 	for _, v := range req.ChartEdbInfoList {
+		// todo 指标名称修改
 		mapItem := new(data_manage.ChartEdbMapping)
 		mapItem.EdbInfoId = v.EdbInfoId
 		mapItem.CreateTime = time.Now()
@@ -684,11 +757,26 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 		mapItem.EdbInfoType = 1
 		mapItem.Source = utils.CHART_SOURCE_RANGE_ANALYSIS
 		mapList = append(mapList, mapItem)
+
 	}
 
+	// 新增图表和指标mapping
+	chartInfoId, e := data_manage.CreateRangeChartAndEdb(chartInfo, mapList)
+	if e != nil {
+		errMsg = "操作失败"
+		err = errors.New("新增区间计算图表失败, Err: " + e.Error())
+		return
+	}
 	// 把系列和图表绑定
-	if extraConfig.SeriesId > 0 {
-		// todo 更新系列的ID
+	if extraConfig.EdbInfoMode == 1 {
+		// 新增指标系列
+		err = AddSeries(edbInfoIdArr, chartInfoId, utils.CHART_SOURCE_RANGE_ANALYSIS, extraConfig, req.ExtraConfig)
+		if err != nil {
+			errMsg = "操作失败"
+			err = errors.New("新增区间计算图表失败, Err: " + err.Error())
+			return
+		}
+		//todo 如果保存失败是否要删除
 	}
 
 	// 添加指标引用记录
@@ -716,7 +804,7 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 		return
 	}
 
-	if chartItem.Source != utils.CHART_SOURCE_RANGE_ANALYSIS && chartItem.Source != utils.CHART_SOURCE_ROLLING_CORRELATION {
+	if chartItem.Source != utils.CHART_SOURCE_RANGE_ANALYSIS {
 		errMsg = "该图不是区间计算图表!"
 		err = errors.New(errMsg)
 		isSendEmail = false
@@ -730,44 +818,43 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 		isSendEmail = false
 		return
 	}
-	// 区间计算图表配置
-	if req.CorrelationChartInfo.LeadValue == 0 && chartItem.Source == utils.CHART_SOURCE_RANGE_ANALYSIS {
-		errMsg = "请输入领先期数"
+	// 区间计算图表配置校验
+	var extraConfig data_manage.ChartRangeAnalysisExtraConf
+	if req.ExtraConfig == `` {
+		errMsg = "配置信息错误"
 		err = errors.New(errMsg)
-		isSendEmail = false
 		return
 	}
-	if req.CorrelationChartInfo.LeadUnit == "" {
-		errMsg = "请填写领先单位"
+	err = json.Unmarshal([]byte(req.ExtraConfig), &extraConfig)
+	if err != nil {
+		errMsg = "配置信息错误"
+		err = errors.New(errMsg)
+		return
+	}
+
+	if len(req.ChartEdbInfoList) <= 0 {
+		errMsg = "请选择指标"
 		err = errors.New(errMsg)
 		isSendEmail = false
 		return
 	}
-	//if req.CorrelationChartInfo.StartDate == "" || req.CorrelationChartInfo.EndDate == "" {
-	//	errMsg = "请填写开始结束日期"
-	//	err = errors.New(errMsg)
-	//	isSendEmail = false
-	//	return
-	//}
-	startDate, e := time.Parse(utils.FormatDate, req.CorrelationChartInfo.StartDate)
-	if e != nil {
-		errMsg = "开始日期格式有误"
+
+	extraConfig.SeriesName = strings.TrimSpace(extraConfig.SeriesName)
+	if extraConfig.SeriesName == "" && extraConfig.EdbInfoMode == 1 {
+		errMsg = "请输入指标系列名称"
 		err = errors.New(errMsg)
 		isSendEmail = false
 		return
 	}
-	var endDate time.Time
-	if req.CorrelationChartInfo.EndDate != `` {
-		endDate, e = time.Parse(utils.FormatDate, req.CorrelationChartInfo.EndDate)
-		if e != nil {
-			errMsg = "结束日期格式有误"
-			err = errors.New(errMsg)
-			isSendEmail = false
-			return
-		}
+	if len(req.ChartEdbInfoList) > 100 {
+		errMsg = "添加指标总数量不得超过100"
+		err = errors.New(errMsg)
+		isSendEmail = false
+		return
 	}
-	if len(req.CorrelationChartInfo.EdbInfoIdList) != 2 {
-		errMsg = "请选择AB指标"
+
+	if extraConfig.CalculateType > 5 || extraConfig.CalculateType < 0 {
+		errMsg = "计算方式参数错误"
 		err = errors.New(errMsg)
 		isSendEmail = false
 		return
@@ -802,7 +889,7 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	}
 
 	var edbInfoIdArr []int
-	for _, v := range req.CorrelationChartInfo.EdbInfoIdList {
+	for _, v := range req.ChartEdbInfoList {
 		edbInfoId := v.EdbInfoId
 		edbInfo, tmpErr := data_manage.GetEdbInfoById(edbInfoId)
 		if tmpErr != nil {
@@ -858,77 +945,58 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 			return
 		}
 	}
-
-	correlationChart := new(data_manage.ChartInfoCorrelation)
-	if e := correlationChart.GetItemById(chartItem.ChartInfoId); e != nil {
-		errMsg = "操作失败"
-		err = errors.New("图表区间计算信息不存在, Err: " + e.Error())
-		return
-	}
-
-	// 图表启用与否
-	disableVal := data.CheckIsDisableChart(edbInfoIdArr)
-
-	// 重新生成图表值, 并修改区间计算图表扩展信息
-	//edbInfoMappingA, e := data_manage.GetChartEdbMappingByEdbInfoId(req.CorrelationChartInfo.EdbInfoIdList[0].EdbInfoId)
-	//if e != nil {
-	//	errMsg = "获取失败"
-	//	err = errors.New("获取区间计算图表, A指标mapping信息失败, Err:" + e.Error())
-	//	return
-	//}
-	//edbInfoMappingB, e := data_manage.GetChartEdbMappingByEdbInfoId(req.CorrelationChartInfo.EdbInfoIdList[1].EdbInfoId)
-	//if e != nil {
-	//	errMsg = "获取失败"
-	//	err = errors.New("获取区间计算图表, B指标mapping信息失败, Err:" + e.Error())
-	//	return
-	//}
-	//periodData, correlationData, e := GetChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB, req.CorrelationChartInfo.LeadValue, req.CorrelationChartInfo.LeadUnit, req.CorrelationChartInfo.StartDate, req.CorrelationChartInfo.EndDate)
-	//if e != nil {
-	//	errMsg = "获取失败"
-	//	err = errors.New("获取区间计算图表, 图表计算值失败, Err:" + e.Error())
-	//	return
-	//}
-	//periodDataByte, e := json.Marshal(periodData)
-	//if e != nil {
-	//	errMsg = "获取失败"
-	//	err = errors.New("区间计算图表, X轴信息有误, Err:" + e.Error())
-	//	return
-	//}
-	//correlationDataByte, e := json.Marshal(correlationData[0].Value)
-	//if e != nil {
-	//	errMsg = "获取失败"
-	//	err = errors.New("区间计算图表, Y轴信息有误, Err:" + e.Error())
-	//	return
-	//}
-	correlationChart.LeadValue = req.CorrelationChartInfo.LeadValue
-	correlationChart.LeadUnit = req.CorrelationChartInfo.LeadUnit
-	correlationChart.CalculateValue = req.CorrelationChartInfo.CalculateValue
-	correlationChart.CalculateUnit = req.CorrelationChartInfo.CalculateUnit
-	correlationChart.StartDate = startDate
-	correlationChart.EndDate = endDate
-	correlationChart.EdbInfoIdFirst = req.CorrelationChartInfo.EdbInfoIdList[0].EdbInfoId
-	correlationChart.EdbInfoIdSecond = req.CorrelationChartInfo.EdbInfoIdList[1].EdbInfoId
-
-	// 滚动区间计算会有日期等信息
-	if chartItem.Source == utils.CHART_SOURCE_ROLLING_CORRELATION {
-		correlationChart.DateType = req.CorrelationChartInfo.DateType
-	}
-	//correlationChart.PeriodData = string(periodDataByte)
-	//correlationChart.CorrelationData = string(correlationDataByte)
-	correlationChart.ModifyTime = time.Now().Local()
-	//correlationUpdateCols := []string{"LeadValue", "LeadUnit", "StartDate", "EndDate", "EdbInfoIdFirst", "EdbInfoIdSecond", "PeriodData","CorrelationData", "ModifyTime"}
-	correlationUpdateCols := []string{"LeadValue", "LeadUnit", "CalculateValue", "CalculateUnit", "DateType", "StartDate", "EndDate", "EdbInfoIdFirst", "EdbInfoIdSecond", "ModifyTime"}
-
 	// 修改图表与指标mapping
-	req.ChartType = 9
-	err = data_manage.EditCorrelationChartInfoAndMapping(&req, edbInfoIdStr, "公历", 6, disableVal, ``,
-		correlationChart, correlationUpdateCols)
+	req.ChartType = 1
+	dateType := req.DateType
+	err = data_manage.EditRangeChartInfoAndMapping(&req, edbInfoIdStr, lang, "公历", dateType, 0, ``)
 	if err != nil {
 		errMsg = "保存失败"
 		err = errors.New("保存失败,Err:" + err.Error())
 		return
 	}
 
+	addSeries := false
+	chartSeriesOb := new(data_manage.FactorEdbSeriesChartMapping)
+	seriesMappingItem, err := chartSeriesOb.GetItemByChartInfoId(chartItem.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			err = nil
+			addSeries = true
+		} else {
+			err = fmt.Errorf("获取图表关联失败, Err: " + err.Error())
+			return
+		}
+	}
+	if extraConfig.EdbInfoMode == 1 {
+		if addSeries {
+			// 新增指标系列
+			err = AddSeries(edbInfoIdArr, chartItem.ChartInfoId, utils.CHART_SOURCE_RANGE_ANALYSIS, extraConfig, req.ExtraConfig)
+			if err != nil {
+				errMsg = "操作失败"
+				err = errors.New("新增区间计算图表失败, Err: " + err.Error())
+				return
+			}
+		} else {
+			err = EditSeries(seriesMappingItem, edbInfoIdArr, extraConfig, req.ExtraConfig, true)
+			if err != nil {
+				errMsg = "保存失败"
+				err = errors.New("保存失败,Err:" + err.Error())
+				return
+			}
+		}
+		// todo 编辑失败处理
+	} else if extraConfig.EdbInfoMode == 0 {
+		if !addSeries {
+			// 删除相关的系列
+			factorSeriesOb := new(data_manage.FactorEdbSeries)
+			err = factorSeriesOb.RemoveSeriesAndMappingByFactorEdbSeriesId(seriesMappingItem)
+			if err != nil {
+				errMsg = "保存失败"
+				err = errors.New("保存失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
 	resp := new(data_manage.AddChartInfoResp)
 	resp.ChartInfoId = chartItem.ChartInfoId
 	resp.UniqueCode = chartItem.UniqueCode
@@ -944,6 +1012,7 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	return
 }
 
+/*
 // CopyChartInfo 复制图表
 func CopyChartInfo(configId, classifyId int, chartName string, correlationChartInfoReq data_manage.CorrelationChartInfoReq, oldChartInfo *data_manage.ChartInfo, sysUser *system.Admin, lang string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
 	configSource := 2
@@ -1336,3 +1405,221 @@ func HandleEdbDateChange(date string, dateChange []*data_manage.EdbDateConfDateC
 
 	return
 }
+
+// 添加指标系列和数据
+func AddSeries(edbInfoIds []int, chartInfoId, chartInfoSource int, extraConf data_manage.ChartRangeAnalysisExtraConf, calculatesJson string) (err error) {
+	edbArr, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		err = fmt.Errorf("获取指标列表失败, Err: " + e.Error())
+		return
+	}
+	if len(edbArr) == 0 {
+		err = fmt.Errorf("获取指标列表失败, 指标不存在")
+		return
+	}
+	edbInfoType := edbArr[0].EdbInfoType
+	// 新增指标系列
+	seriesItem := new(data_manage.FactorEdbSeries)
+	seriesItem.SeriesName = extraConf.SeriesName
+	seriesItem.EdbInfoType = edbInfoType
+	seriesItem.CreateTime = time.Now().Local()
+	seriesItem.ModifyTime = time.Now().Local()
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
+	seriesItem.CalculateStep = calculatesJson
+	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	for _, v := range edbArr {
+		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
+			EdbInfoId:  v.EdbInfoId,
+			EdbCode:    v.EdbCode,
+			CreateTime: time.Now().Local(),
+			ModifyTime: time.Now().Local(),
+		})
+	}
+
+	seriesId, e := seriesItem.CreateSeriesAndMapping(seriesItem, mappings)
+	if e != nil {
+		err = fmt.Errorf("新增因子指标系列失败, Err: " + e.Error())
+		return
+	}
+
+	// 图表关联-此处添加的chart_info_id=0
+	seriesChartMapping := new(data_manage.FactorEdbSeriesChartMapping)
+	seriesChartMapping.CalculateType = data_manage.FactorEdbSeriesChartCalculateTypeRange
+	//新增图表和指标的映射关系
+	seriesChartMapping.CalculateData = ""
+	seriesChartMapping.FactorEdbSeriesId = seriesId
+	seriesChartMapping.ChartInfoId = chartInfoId
+	seriesChartMapping.Source = chartInfoSource
+	seriesChartMapping.CreateTime = time.Now().Local()
+	seriesChartMapping.ModifyTime = time.Now().Local()
+
+	if e = seriesChartMapping.Create(); e != nil {
+		err = fmt.Errorf("新增图表关联失败, Err: " + e.Error())
+		return
+	}
+
+	// todo 计算指标数据并存储
+	_, e = FactorEdbStepCalculateRange(seriesId, edbInfoIds, extraConf, false)
+	if e != nil {
+		err = fmt.Errorf("计算因子指标失败, Err: " + e.Error())
+		return
+	}
+
+	// 更新系列计算状态
+	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
+	seriesItem.ModifyTime = time.Now().Local()
+	if e = seriesItem.Update(cols); e != nil {
+		err = fmt.Errorf("更新因子指标系列计算状态失败, Err: " + e.Error())
+		return
+	}
+	return
+}
+
+func EditSeries(seriesMapping *data_manage.FactorEdbSeriesChartMapping, edbInfoIds []int, extraConf data_manage.ChartRangeAnalysisExtraConf, calculatesJson string, recalculate bool) (err error) {
+	seriesOb := new(data_manage.FactorEdbSeries)
+	seriesItem, e := seriesOb.GetItemById(seriesMapping.FactorEdbSeriesId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			err = fmt.Errorf("因子指标系列不存在, Err: " + e.Error())
+			return
+		}
+		err = fmt.Errorf("获取因子指标系列失败, Err: " + e.Error())
+		return
+	}
+
+	edbArr, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		err = fmt.Errorf("获取指标列表失败, Err: " + e.Error())
+		return
+	}
+	if len(edbArr) == 0 {
+		err = fmt.Errorf("指标列表为空")
+		return
+	}
+	var calculateResp data_manage.FactorEdbSeriesStepCalculateResp
+	calculateResp.SeriesId = seriesItem.FactorEdbSeriesId
+
+	// 如果不需要进行重新计算(比如只改了系列名称)那么只更新指标系列
+	seriesItem.SeriesName = extraConf.SeriesName
+	seriesItem.EdbInfoType = edbArr[0].EdbInfoType
+	seriesItem.ModifyTime = time.Now().Local()
+	updateCols := []string{seriesOb.Cols().SeriesName, seriesOb.Cols().EdbInfoType, seriesOb.Cols().ModifyTime}
+	if !recalculate {
+		if e = seriesItem.Update(updateCols); e != nil {
+			err = fmt.Errorf("更新因子指标系列失败, Err: " + e.Error())
+			return
+		}
+		return
+	}
+
+	// 更新系列信息和指标关联
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculating
+	seriesItem.CalculateStep = calculatesJson
+	updateCols = append(updateCols, seriesOb.Cols().CalculateState, seriesOb.Cols().CalculateStep)
+
+	mappings := make([]*data_manage.FactorEdbSeriesMapping, 0)
+	for _, v := range edbArr {
+		mappings = append(mappings, &data_manage.FactorEdbSeriesMapping{
+			EdbInfoId:  v.EdbInfoId,
+			EdbCode:    v.EdbCode,
+			CreateTime: time.Now().Local(),
+			ModifyTime: time.Now().Local(),
+		})
+	}
+	if e = seriesItem.EditSeriesAndMapping(seriesItem, mappings, updateCols); e != nil {
+		err = fmt.Errorf("更新因子指标系列信息失败, Err: %s", e.Error())
+		return
+	}
+
+	// todo 重新计算
+	_, e = FactorEdbStepCalculateRange(seriesItem.FactorEdbSeriesId, edbInfoIds, extraConf, false)
+	if e != nil {
+		err = fmt.Errorf("计算因子指标失败, Err: " + e.Error())
+		return
+	}
+
+	// 更新系列计算状态
+	cols := []string{seriesItem.Cols().CalculateState, seriesItem.Cols().ModifyTime}
+	seriesItem.CalculateState = data_manage.FactorEdbSeriesCalculated
+	seriesItem.ModifyTime = time.Now().Local()
+	if e = seriesItem.Update(cols); e != nil {
+		err = fmt.Errorf("更新因子指标系列计算状态失败, Err: %s", e.Error())
+		return
+	}
+	return
+}
+
+// FactorEdbStepCalculateRange 因子指标-区间计算
+func FactorEdbStepCalculateRange(seriesId int, edbArr []int, extraConf data_manage.ChartRangeAnalysisExtraConf, recalculate bool) (calculateResp data_manage.FactorEdbSeriesStepCalculateResp, err error) {
+	// todo 如果指标已保存,则用指标数据还是图表指标数据?
+	// 获取图表x轴y轴
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("StepCalculate计算失败, ErrMsg: %v", err)
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+		/*if len(calculateResp.Fail) > 0 {
+			tips := "StepCalculate计算失败, ErrMsg: "
+			for _, f := range calculateResp.Fail {
+				tips += fmt.Sprintf("code: %s, err: %s\n", f.EdbCode, f.ErrMsg)
+			}
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 2)
+		}*/
+	}()
+
+	edbInfoMappingList, e := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbArr)
+	if e != nil {
+		err = fmt.Errorf("获取区间计算图表, A指标mapping信息失败, Err:%v", e)
+		return
+	}
+
+	_, _, _, err = GetChartDataByEdbInfoList(0, "", "", edbInfoMappingList, &extraConf)
+	if err != nil {
+		err = fmt.Errorf("获取图表数据失败, ErrMsg: %v", err)
+		return
+	}
+
+	// 重新计算-先清除原数据
+	calculateDataOb := new(data_manage.FactorEdbSeriesCalculateDataQjjs)
+
+	cond := fmt.Sprintf("%s = ?", calculateDataOb.Cols().FactorEdbSeriesId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, seriesId)
+	if e := calculateDataOb.RemoveByCondition(cond, pars); e != nil {
+		err = fmt.Errorf("清除原数据失败, err: %v", e)
+		return
+	}
+
+	// 计算成功的保存结果
+	dataArr := make([]*data_manage.FactorEdbSeriesCalculateDataQjjs, 0)
+	for _, v := range edbInfoMappingList {
+		dataList := v.DataList.([]*data_manage.EdbDataList)
+		for _, dataItem := range dataList {
+			dataTime, _ := time.ParseInLocation(utils.FormatDate, dataItem.DataTime, time.Local)
+			dataArr = append(dataArr, &data_manage.FactorEdbSeriesCalculateDataQjjs{
+				FactorEdbSeriesId: seriesId,
+				EdbInfoId:         v.EdbInfoId,
+				EdbCode:           v.EdbCode,
+				DataTime:          dataTime,
+				Value:             dataItem.Value,
+				CreateTime:        time.Now().Local(),
+				ModifyTime:        time.Now().Local(),
+				DataTimestamp:     dataItem.DataTimestamp,
+			})
+		}
+	}
+	if len(dataArr) == 0 {
+		err = fmt.Errorf("计算结果无数据, seriesId: %d", seriesId)
+		return
+	}
+	if e = calculateDataOb.CreateMulti(dataArr); e != nil {
+		err = fmt.Errorf("保存计算结果失败, seriesId: %d, err: %v, ", seriesId, e)
+		return
+	}
+	return
+}