Browse Source

Merge branch 'feature/pool151_predict_calculate' of hongze/hongze_edb_lib into master

xyxie 2 years ago
parent
commit
532cd69b46

+ 16 - 0
controllers/base_from_calculate.go

@@ -604,9 +604,25 @@ func (this *CalculateController) BatchSave() {
 		}
 		edbInfo, err = models.AddCalculateLjzzy(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	case utils.DATA_SOURCE_CALCULATE_TBZ:
+		if req.Frequency != fromEdbInfo.Frequency {
+			br.Msg = "当前频度和原指标频度不一致"
+			return
+		}
+		if req.Unit != "无" {
+			br.Msg = "单位只允许为无,禁止选择其他单位"
+			return
+		}
 		sourName = "同比值"
 		edbInfo, err = models.AddCalculateTbz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	case utils.DATA_SOURCE_CALCULATE_TCZ:
+		if req.Frequency != fromEdbInfo.Frequency {
+			br.Msg = "当前频度和原指标频度不一致"
+			return
+		}
+		if req.Unit != fromEdbInfo.Unit {
+			br.Msg = "当前单位和原指标单位不一致"
+			return
+		}
 		sourName = "同差值"
 		edbInfo, err = models.AddCalculateTcz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS:

+ 274 - 19
controllers/base_from_predict_calculate.go

@@ -517,13 +517,8 @@ func (this *PredictCalculateController) CalculateBatchSave() {
 		return
 	}
 
-	if req.FromEdbInfoId <= 0 {
-		br.Msg = "请选择指标"
-		return
-	}
-
 	//加入缓存机制,避免创建同一个名称的指标 start
-	redisKey := fmt.Sprint("edb_info:calculate:batch:save:", req.Source, ":", req.EdbName)
+	redisKey := fmt.Sprint("edb_lib:predict_calculate:batch:save:", req.Source, ":", req.EdbName)
 	isExist := utils.Rc.IsExist(redisKey)
 	if isExist {
 		br.Msg = "指标正在处理,请勿重复提交"
@@ -560,19 +555,6 @@ func (this *PredictCalculateController) CalculateBatchSave() {
 		return
 	}
 
-	// 来源预测指标信息
-	fromEdbInfo, err := models.GetEdbInfoById(req.FromEdbInfoId)
-	if err != nil {
-		br.Msg = "获取指标信息失败"
-		br.ErrMsg = "获取指标信息失败:Err:" + err.Error()
-		return
-	}
-	if fromEdbInfo.EdbInfoType != 1 {
-		br.Msg = "来源指标不是预测指标"
-		br.ErrMsg = "来源指标不是预测指标"
-		return
-	}
-
 	//生成指标编码
 	randStr := utils.GetRandDigit(4)
 	edbCode := `C` + time.Now().Format("060102") + randStr
@@ -588,15 +570,159 @@ func (this *PredictCalculateController) CalculateBatchSave() {
 	var latestDateStr string // 最近实际数据的日期
 	var latestValue float64  // 最近实际数据的值
 
+	// 基础指标id
+	fromEdbInfoId := req.FromEdbInfoId
+
+	var formulaInt int
+	var nhccDate models.NhccDate // 拟合残差的日期
+	switch req.Source {
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ, utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ, utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX:
+		if req.Formula == "" {
+			br.Msg = "请填写N值"
+			return
+		}
+		formulaInt, _ = strconv.Atoi(req.Formula)
+		if formulaInt <= 0 {
+			br.Msg = "N值输入错误,请重新输入"
+			return
+		}
+	/*case utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ:
+		//直接拼接指标
+		//校验时间格式
+		_, err = time.ParseInLocation(utils.FormatDate, req.Formula, time.Local)
+		if err != nil {
+			br.Msg = "拼接日期有误,请重新输入"
+			return
+		}*/
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC: //拟合残差指标
+		//指标校验
+		if len(req.EdbInfoIdArr) != 2 {
+			br.Msg = "选择的指标异常,请重新选择"
+			return
+		}
+		fromEdbInfoId = req.EdbInfoIdArr[0].EdbInfoId
+
+		//校验时间格式
+		//数据格式:2022-11-01,2022-11-10
+		timeList := strings.Split(req.Formula, ",")
+		if len(timeList) != 2 {
+			br.Msg = "选择时间有误,请重新输入"
+			return
+		}
+		startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+		if err != nil {
+			br.Msg = "开始日期有误,请重新输入"
+			return
+		}
+		endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+		if err != nil {
+			br.Msg = "结束日期有误,请重新输入"
+			return
+		}
+		if utils.GetTimeSubDay(startDate, endDate) < 2 {
+			br.Msg = "日期间隔不得少于两天"
+			return
+		}
+		nhccDate.StartDate = startDate
+		nhccDate.EndDate = endDate
+	}
+	if fromEdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	// 来源预测指标信息
+	fromEdbInfo, err := models.GetEdbInfoById(fromEdbInfoId)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败:Err:" + err.Error()
+		return
+	}
+	if fromEdbInfo.EdbInfoType != 1 {
+		br.Msg = "来源指标不是预测指标"
+		br.ErrMsg = "来源指标不是预测指标"
+		return
+	}
+
 	if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_TBZ {
+		if req.EdbInfoId <=0 {
+			if req.Frequency != fromEdbInfo.Frequency {
+				br.Msg = "当前频度和原指标频度不一致"
+				return
+			}
+			if req.Unit != "无" {
+				br.Msg = "单位只允许为无,禁止选择其他单位"
+				return
+			}
+		}
 		sourName = "预测同比"
 		edbInfo, latestDateStr, latestValue, err, errMsg = models.SavePredictCalculateTbz(req.EdbInfoId, req.ClassifyId, req.EdbName, req.Frequency, req.Unit, req.Formula, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
 	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_TCZ {
+		if req.EdbInfoId <=0 {
+			if req.Frequency != fromEdbInfo.Frequency {
+				br.Msg = "当前频度和原指标频度不一致"
+				return
+			}
+			if req.Unit != fromEdbInfo.Unit {
+				br.Msg = "当前单位和原指标单位不一致"
+				return
+			}
+		}
 		sourName = "预测同差"
 		edbInfo, latestDateStr, latestValue, err, errMsg = models.SavePredictCalculateTcz(req.EdbInfoId, req.ClassifyId, req.EdbName, req.Frequency, req.Unit, req.Formula, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
 	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS {
 		sourName = "预测N数值移动平均计算"
 		edbInfo, latestDateStr, latestValue, err, errMsg = models.SavePredictCalculateNszydpjjs(req.EdbInfoId, req.ClassifyId, req.EdbName, req.Frequency, req.Unit, req.Formula, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_BP {
+		sourName = "预测变频"
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateBp(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ {
+		checkDataList, tmpErr := models.GetPredictEdbDataListAllByStartDate(fromEdbInfo, 0, "")
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			br.Msg = "判断环比值是否可计算失败"
+			br.ErrMsg = "判断环比值是否可计算失败,Err:" + tmpErr.Error()
+			return
+		}
+		for _, v := range checkDataList {
+			if v.Value <= 0 {
+				br.Msg = "原始数据中存在0或负数,该指标不能进行环比运算"
+				br.ErrMsg = "原始数据中出现0和负值时,提示该指标不能进行环比运算"
+				return
+			}
+		}
+		sourName = "预测环比值"
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateHbz(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName, formulaInt)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ {
+		sourName = "预测环差值"
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateHcz(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName, formulaInt)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY {
+		sourName = "预测累计值转月值"
+		if fromEdbInfo.Frequency != "月度" {
+			br.Msg = "请选择月度指标"
+			return
+		}
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateLjzzy(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT {
+		sourName = "预测时间移位"
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateTimeShift(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX {
+		sourName = "预测超季节性"
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateCjjx(&req, fromEdbInfo, edbCode, uniqueCode, adminId, adminName, formulaInt)
+	} else if req.Source == utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC {
+		sourName = "预测拟合残差"
+		secondEdbInfoReq := req.EdbInfoIdArr[1]
+		secondEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+		if tmpErr != nil {
+			br.Msg = "获取因变量的指标信息失败"
+			br.ErrMsg = "获取因变量的指标信息失败:Err:" + tmpErr.Error()
+			return
+		}
+
+		if fromEdbInfo.EdbInfoId == secondEdbInfo.EdbInfoId {
+			br.Msg = "两个指标不允许为同一个"
+			br.ErrMsg = "两个指标不允许为同一个"
+			return
+		}
+		edbInfo, latestDateStr, latestValue, err = models.SavePredictCalculateNhcc(&req, fromEdbInfo, secondEdbInfo, edbCode, uniqueCode, nhccDate, adminId, adminName)
 	} else {
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -708,6 +834,7 @@ func (this *PredictCalculateController) Refresh() {
 	}()
 	startDate := req.StartDate
 	var errMsg string
+	endDate := time.Now().Format(utils.FormatDate)
 	edbInfoId := edbInfo.EdbInfoId
 	source := edbInfo.Source
 
@@ -799,6 +926,134 @@ func (this *PredictCalculateController) Refresh() {
 			errMsg = "RefreshAllPredictCalculateNszydpjjs Err:" + err.Error()
 			break
 		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_BP: //刷新变频
+		calculateTbz, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateTbzDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculateTbz.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		endDate = time.Now().Format(utils.FormatDate)
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateBp(edbInfoId, source, fromEdbInfo, calculateTbz.EdbCode, startDate, endDate)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateBp Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ: //刷新环比值
+		calculateTbz, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateHbzDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculateTbz.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		startDate = `` //只要填写日期,就会出现问题,还是把日期给去掉吧
+		endDate = time.Now().Format(utils.FormatDate)
+		formulaInt, _ := strconv.Atoi(edbInfo.CalculateFormula)
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateHbz(edbInfoId, source, fromEdbInfo, calculateTbz.EdbCode, startDate, endDate, formulaInt)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateHbz Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ: //刷新环差值
+		calculateTbz, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateHczDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculateTbz.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		startDate = `` //只要填写日期,就会出现问题,还是把日期给去掉吧
+		endDate = time.Now().Format(utils.FormatDate)
+		formulaInt, _ := strconv.Atoi(edbInfo.CalculateFormula)
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateHcz(edbInfoId, source, fromEdbInfo, calculateTbz.EdbCode, startDate, endDate, formulaInt)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateHcz Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY: //刷新累计值转月值
+		calculateLjzzy, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateLjzzyDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculateLjzzy.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		endDate = ``   //只要填写日期,就会出现问题,还是把日期给去掉吧
+		startDate = `` //只要填写日期,就会出现问题,还是把日期给去掉吧
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateLjzzy(edbInfoId, source, fromEdbInfo, calculateLjzzy.EdbCode, startDate, endDate)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateLjzzy Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT:
+		calculate, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateTbzDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculate.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		//startDate = edbInfo.StartDate
+		startDate = `` //只要填写日期,就会出现问题,还是把日期给去掉吧
+		endDate = time.Now().Format(utils.FormatDate)
+		formulaInt, _ := strconv.Atoi(calculate.CalculateFormula)
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateTimeShift(edbInfoId, source, formulaInt, calculate.MoveType, fromEdbInfo, calculate.EdbCode, startDate, endDate, calculate.MoveFrequency)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllCalculateTimeShift Err:" + err.Error()
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ: //刷新累计值同比拼接
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateLjztbpj(edbInfo)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateLjztbpj Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ: //刷新直接拼接
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateZjpj(edbInfo)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateZjpj Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX: //超季节性
+		calculateCjjx, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateNszydpjjsDetail Err:" + err.Error()
+			break
+		}
+		fromEdbInfo, err := models.GetEdbInfoById(calculateCjjx.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		formulaInt, _ := strconv.Atoi(edbInfo.CalculateFormula)
+		startDate = `` //只要填写日期,就会出现问题,还是把日期给去掉吧
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateCjjx(edbInfoId, edbInfo.Source, fromEdbInfo, calculateCjjx.EdbCode, startDate, "", edbInfo.Calendar, formulaInt)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateCjjx Err:" + err.Error()
+			break
+		}
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC: //nhcc
+		latestDateStr, latestValue, err = models.RefreshAllPredictCalculateNhcc(edbInfo)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllPredictCalculateNhcc Err:" + err.Error()
+			break
+		}
 	default:
 		br.Msg = "来源异常,请联系相关开发!"
 		br.ErrMsg = "来源异常,请联系相关开发"

+ 3 - 0
models/db.go

@@ -47,6 +47,9 @@ func init() {
 		new(PredictEdbConfCalculateMapping),
 		new(PredictEdbRuleData),
 		new(EdbDataCalculateNhcc),
+		new(EdbDataPredictCalculateLjztbpj),
+		new(EdbDataPredictCalculateNhcc),
+		new(EdbDataPredictCalculateZjpj),
 	)
 
 	// 注册期货数据 数据表

+ 18 - 0
models/edb_data_table.go

@@ -85,6 +85,24 @@ func GetEdbDataTableName(source int) (tableName string) {
 		tableName = "edb_data_calculate_adjust"
 	case utils.DATA_SOURCE_SCI:
 		tableName = "edb_data_sci"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY:
+		tableName = "edb_data_predict_calculate_ljzzy"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT:
+		tableName = "edb_data_predict_calculate_time_shift"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ:
+		tableName = "edb_data_predict_calculate_zjpj"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ:
+		tableName = "edb_data_predict_calculate_ljztbpj"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC:
+		tableName = "edb_data_predict_calculate_nhcc"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX:
+		tableName = "edb_data_predict_calculate_cjjx"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ:
+		tableName = "edb_data_predict_calculate_hbz"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ:
+		tableName = "edb_data_predict_calculate_hcz"
+	case utils.DATA_SOURCE_PREDICT_CALCULATE_BP:
+		tableName = "edb_data_predict_calculate_bp"
 	default:
 		tableName = ""
 	}

+ 10 - 0
models/edb_info_calculate_mapping.go

@@ -64,6 +64,16 @@ func GetEdbInfoCalculateMappingDetail(edbInfoId int) (item *EdbInfoCalculateMapp
 	return
 }
 
+// GetEdbInfoCalculateMappingDetailByFromTag 获取单条关联指标
+func GetEdbInfoCalculateMappingDetailByFromTag(edbInfoId int, fromTag string) (item *EdbInfoCalculateMappingView, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT a.*,b.start_date,b.end_date,b.calculate_formula,b.move_type,b.move_frequency FROM edb_info_calculate_mapping AS a
+			INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
+			WHERE a.edb_info_id=? and a.from_tag=? `
+	err = o.Raw(sql, edbInfoId, fromTag).QueryRow(&item)
+	return
+}
+
 // EdbInfoCalculateDetail
 type EdbInfoCalculateDetail struct {
 	EdbInfoCalculateId int       `orm:"column(edb_info_calculate_id);pk"`

+ 385 - 0
models/predict_edb_data_calculate_bp.go

@@ -0,0 +1,385 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateBp 变频
+func SavePredictCalculateBp(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddPredictCalculateBp,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+	    edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_BP
+		edbInfo.SourceName = "预测变频"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.EdbType = 2
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//判断计算指标是否被更换
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+
+		count, e := GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if e != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + e.Error())
+			return
+		}
+		if count > 0 { // 指标未被替换,无需重新计算
+			return
+		}
+
+		//删除,计算指标关联的,基础指标的关联关系
+		sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+			return
+		}
+		//清空原有数据
+		sql = ` DELETE FROM edb_data_predict_calculate_bp WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+		//关联关系
+		{
+			calculateMappingItem := &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_BP,
+				SourceName:                "预测变频",
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+				FromEdbCode:               fromEdbInfo.EdbCode,
+				FromEdbName:               fromEdbInfo.EdbName,
+				FromSource:                fromEdbInfo.Source,
+				FromSourceName:            fromEdbInfo.SourceName,
+				FromTag:                   "",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateBp(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", 0)
+
+	return
+}
+
+func RefreshAllPredictCalculateBp(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllPredictCalculateBp,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateBp(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, 1)
+	return
+}
+
+// refreshAllPredictCalculateBp 刷新变频数据
+func refreshAllPredictCalculateBp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, order int) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	// 获取关联指标数据
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, order, "")
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+
+	var dateArr []string
+	dataMap := make(map[string]*EdbInfoSearchData)
+	fromDataMap := make(map[string]float64)
+	//来源指指标数据
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+		fromDataMap[v.DataTime] = v.Value
+	}
+	fmt.Println("source:", source)
+
+	//获取变频指标所有数据
+	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source)
+	if err != nil {
+		return
+	}
+	//计算指标的map
+	existDataMap := make(map[string]*EdbData, 0)
+
+	addSql := ` INSERT INTO edb_data_predict_calculate_bp(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	var lastValue float64   //最后数据的值(float64)
+	var lastValueStr string //最后数据的值(string)
+	//待删除的日期
+	removeDateList := make([]string, 0)
+	if len(existDataList) > 0 {
+		//第一个已经入库的日期
+		firstExistDataTimeStr := existDataList[0].DataTime //计算指标数据第一条的日期字符串
+		if len(dateArr) > 0 {
+			firstFromDataTimeStr := dateArr[0]                                                             //来源数据第一条的日期字符串
+			firstExistDataTime, _ := time.Parse(utils.FormatDate, firstExistDataTimeStr)                   //计算指标数据第一条的日期(time类型)
+			firstFromDataTime, _ := time.Parse(utils.FormatDate, firstFromDataTimeStr)                     //来源数据第一条的日期(time类型)
+			nowDateStr := time.Now().Format(utils.FormatDate)                                              //当天日期字符串
+			nowDate, _ := time.ParseInLocation(utils.FormatDate, nowDateStr, firstFromDataTime.Location()) //当天日期(time类型)
+
+			lastValue = fromDataMap[firstFromDataTimeStr]
+			lastValueStr = decimal.NewFromFloat(lastValue).String()
+			//第一步: 判断来源指标的开始时间与计算指标的开始时间是否相等,相等的话,那么就不需要对两个时间之间的数据做处理
+			if firstExistDataTimeStr != firstFromDataTimeStr {
+				if firstExistDataTime.Before(firstFromDataTime) { //如果计算指标第一条数据的开始时间 早于 来源指标的第一条开始时间,那么需要对两个时间之间的计算指标数据做 删除处理
+					for _, v := range existDataList {
+						if v.DataTime == firstFromDataTimeStr {
+							if tmpLastValue, ok := fromDataMap[firstFromDataTimeStr]; ok { //来源指标当天的数据
+								lastValue = tmpLastValue
+								lastValueStr = decimal.NewFromFloat(lastValue).String()
+							}
+							break
+						}
+						removeDateList = append(removeDateList, v.DataTime)
+					}
+				} else {
+					for _, v := range dateArr { //如果计算指标第一条数据的开始时间 晚于 来源指标的第一条开始时间,那么需要对两个时间之间的计算指标数据做 新增处理
+						vDataTime, _ := time.Parse(utils.FormatDate, v) //当前日期(time类型)
+						if firstExistDataTime.Equal(vDataTime) || firstExistDataTime.Before(vDataTime) {
+							if tmpLastValue, ok := fromDataMap[v]; ok { //来源指标当天的数据
+								lastValue = tmpLastValue
+								lastValueStr = decimal.NewFromFloat(lastValue).String()
+							}
+							break
+						}
+
+						currentDate, _ := time.Parse(utils.FormatDate, v)
+						timestamp := currentDate.UnixNano() / 1e6
+						timestampStr := fmt.Sprintf("%d", timestamp)
+						addSql += GetAddSql(edbInfoIdStr, edbCode, v, timestampStr, lastValueStr)
+						// 实际数据的值
+						if fromEdbInfo.LatestDate == v {
+							latestValue = lastValue
+						}
+						isAdd = true
+					}
+				}
+			}
+
+			//第二步 剩余数据每天修改
+
+			day := int(nowDate.Sub(firstExistDataTime).Hours() / float64(24))
+
+			//第三步: 已经入库的数据处理
+			for _, v := range existDataList {
+				existDataMap[v.DataTime] = v
+			}
+
+			for k := day; k >= 0; k-- {
+				needDay := nowDate.AddDate(0, 0, -k)
+				needDayStr := needDay.Format(utils.FormatDate)
+				tmpExistData, ok := existDataMap[needDayStr]
+				if ok {
+					if tmpLastValue, ok := fromDataMap[tmpExistData.DataTime]; ok { //来源指标当天的数据
+						lastValue = tmpLastValue
+						//lastValueStr = decimal.NewFromFloat(lastValue).String()
+						lastValueStr = fmt.Sprintf("%.4f", lastValue)
+					}
+					if fromEdbInfo.LatestDate == tmpExistData.DataTime {
+						latestValue = lastValue
+					}
+					//如果对应的值不匹配
+					if tmpExistData.Value != lastValueStr {
+						err = ModifyEdbDataById(source, tmpExistData.EdbDataId, lastValueStr)
+						if err != nil {
+							return
+						}
+					}
+				} else {
+					timestamp := needDay.UnixNano() / 1e6
+					timestampStr := fmt.Sprintf("%d", timestamp)
+					addSql += GetAddSql(edbInfoIdStr, edbCode, needDayStr, timestampStr, lastValueStr)
+					if fromEdbInfo.LatestDate == needDayStr {
+						latestValue = lastValue
+					}
+					isAdd = true
+				}
+			}
+		} else {
+			//如果没有来源指标数据,那么已经入库的计算指标数据需要全部删除
+			tableName := GetEdbDataTableName(source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ?`, tableName)
+			_, err = to.Raw(sql, edbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除所有的变频指标数据失败,Err:" + err.Error())
+				return
+			}
+
+			//for _, v := range existDataList {
+			//	removeDateList = append(removeDateList, v.DataTime)
+			//}
+		}
+	} else {
+		existMap := make(map[string]string)
+		dataLen := len(dataList)
+
+		for i := 0; i < dataLen; i++ {
+			//当期
+			currentItem := dataList[i]
+			currentDate, _ := time.Parse(utils.FormatDate, currentItem.DataTime)
+			var day int
+			var preItem *EdbInfoSearchData
+			var preDate time.Time
+			if i == 0 {
+				day = int(time.Now().Sub(currentDate).Hours() / float64(24))
+				preDate = time.Now()
+			} else {
+				j := i - 1
+				if j < dataLen {
+					preItem = dataList[j]
+					preDate, _ = time.Parse(utils.FormatDate, preItem.DataTime)
+					day = int(preDate.Sub(currentDate).Hours() / float64(24))
+					utils.FileLog.Info("preItem.DataTime:" + preItem.DataTime + ";currentItem.DataTime" + currentItem.DataTime)
+				}
+			}
+			for k := 0; k <= day; k++ {
+				needDay := preDate.AddDate(0, 0, -k)
+				needDayStr := needDay.Format(utils.FormatDate)
+				existKey := edbCode + needDayStr
+				if _, ok := existMap[existKey]; !ok {
+					timestamp := needDay.UnixNano() / 1e6
+					timestampStr := fmt.Sprintf("%d", timestamp)
+					valStr := decimal.NewFromFloat(currentItem.Value).String()
+					addSql += GetAddSql(edbInfoIdStr, edbCode, needDayStr, timestampStr, valStr)
+					if fromEdbInfo.LatestDate == needDayStr {
+						latestValue = currentItem.Value
+					}
+					isAdd = true
+				}
+				existMap[existKey] = needDayStr
+			}
+			existKey := edbCode + currentItem.DataTime
+			if _, ok := existMap[existKey]; !ok {
+				currentDate, _ := time.Parse(utils.FormatDate, currentItem.DataTime)
+				timestamp := currentDate.UnixNano() / 1e6
+				timestampStr := fmt.Sprintf("%d", timestamp)
+				valStr := decimal.NewFromFloat(currentItem.Value).String()
+				addSql += GetAddSql(edbInfoIdStr, edbCode, currentItem.DataTime, timestampStr, valStr)
+				if fromEdbInfo.LatestDate == currentItem.DataTime {
+					latestValue = currentItem.Value
+				}
+				isAdd = true
+			}
+			existMap[existKey] = currentItem.DataTime
+		}
+	}
+
+	// 删除不需要的指标数据
+	if len(removeDateList) > 0 {
+		removeDateStr := strings.Join(removeDateList, `","`)
+		removeDateStr = `"` + removeDateStr + `"`
+		//如果拼接指标变更了,那么需要删除所有的指标数据
+		tableName := GetEdbDataTableName(source)
+		sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+
+		_, err = to.Raw(sql, edbInfoId).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除不存在的变频指标数据失败,Err:" + err.Error())
+			return
+		}
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+	}
+	return
+}

+ 370 - 0
models/predict_edb_data_calculate_cjjx.go

@@ -0,0 +1,370 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateCjjx 超季节性
+func SavePredictCalculateCjjx(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string, formulaInt int) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateCjjx,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	fmt.Println("req.EdbInfoId:", req.EdbInfoId)
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX
+		edbInfo.SourceName = "预测超季节性"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.Calendar = req.Calendar
+		edbInfo.EdbType = 2
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		oldCalculateFormula := edbInfo.CalculateFormula //原先的n值
+		oldCalendar := edbInfo.Calendar                 //原先的公历、农历
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.Calendar = req.Calendar
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "Calendar", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//判断计算指标是否被更换
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 && oldCalculateFormula == req.Formula && oldCalendar == req.Calendar { // 指标未被替换,同时N值未修改,同时公历/农历未变更,无需重新计算
+			return
+		}
+
+		// 指标被替换,或者N值未修改,那么需要重新计算数据
+		//基础指标被替换了,需要删除原先的 计算指标关联的,基础指标的关联关系
+		if count <= 0 {
+			// 需要删除原先的 计算指标关联的,基础指标的关联关系
+			sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				return
+			}
+
+			// 添加新的关联关系
+			{
+				calculateMappingItem := &EdbInfoCalculateMapping{
+					EdbInfoCalculateMappingId: 0,
+					EdbInfoId:                 edbInfo.EdbInfoId,
+					Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_CJJX,
+					SourceName:                "预测超季节性",
+					EdbCode:                   edbInfo.EdbCode,
+					FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+					FromEdbCode:               fromEdbInfo.EdbCode,
+					FromEdbName:               fromEdbInfo.EdbName,
+					FromSource:                fromEdbInfo.Source,
+					FromSourceName:            fromEdbInfo.SourceName,
+					FromTag:                   "",
+					Sort:                      1,
+					CreateTime:                time.Now(),
+					ModifyTime:                time.Now(),
+				}
+				_, err = to.Insert(calculateMappingItem)
+				if err != nil {
+					return
+				}
+			}
+		}
+
+		//清空原有数据
+		tableName := GetEdbDataTableName(edbInfo.Source)
+		sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? `, tableName)
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateCjjx(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", edbInfo.Calendar, formulaInt)
+
+	return
+}
+
+// RefreshAllPredictCalculateCjjx 刷新全部超季节性数据
+func RefreshAllPredictCalculateCjjx(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, calendar string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllPredictCalculateCjjx,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 重新计算
+	latestDateStr, latestValue, err = refreshAllPredictCalculateCjjx(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, calendar, formulaInt)
+
+	return
+}
+
+// refreshAllPredictCalculateCjjx 刷新全部超季节性数据
+func refreshAllPredictCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, calendar string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	// 获取关联指标数据
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, 0, "")
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+	var dateArr []string
+	dataMap := make(map[string]*EdbInfoSearchData)
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+	}
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
+	if err != nil {
+		return
+	}
+	existDataMap := make(map[string]string)
+	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
+	for _, v := range existDataList {
+		existDataMap[edbCode+v.DataTime] = v.Value
+		removeDataTimeMap[v.DataTime] = 1
+	}
+
+	addSql := ` INSERT INTO edb_data_predict_calculate_cjjx(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+	//日度/周度/季度/月度
+	isCompatibility := false //是否向上下兼容35天
+	if utils.InArrayByStr([]string{"日度", "周度", "季度", "月度"}, fromEdbInfo.Frequency) {
+		isCompatibility = true
+	}
+
+	// 每个年份的日期数据需要平移的天数
+	moveDayMap := make(map[int]int, 0) // 每个年份的春节公历
+	var lastDataDay time.Time
+	if len(dataList) > 0 {
+		lastDataDay, _ = time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+	}
+	for _, av := range dateArr {
+		currentItem := dataMap[av]
+		if currentItem != nil {
+			pastValueList := make([]float64, 0) // 过去几期的数据
+			//当前日期
+			currentDate, tmpErr := time.Parse(utils.FormatDate, av)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			pastValueList = append(pastValueList, currentItem.Value)
+
+			for i := 1; i < formulaInt; i++ {
+				//前几年当天公历的日期
+				hisoryPreDate := currentDate.AddDate(-i, 0, 0)
+				moveDay := 0
+				if calendar == "农历" {
+					if tmpMoveDay, ok := moveDayMap[hisoryPreDate.Year()]; !ok {
+						moveDay, err = getMoveDay(lastDataDay, hisoryPreDate)
+						if err != nil {
+							return
+						}
+					} else {
+						moveDay = tmpMoveDay
+					}
+
+					// 移动天数到对应农历 的 公历 日期
+					hisoryPreDate = hisoryPreDate.AddDate(0, 0, moveDay)
+				}
+
+				hisoryPreDateStr := hisoryPreDate.Format(utils.FormatDate)
+				if findItem, ok := dataMap[hisoryPreDateStr]; ok { //上一年同期找到
+					pastValueList = append(pastValueList, findItem.Value)
+				} else if isCompatibility { // 如果需要兼容上下35天
+					nextDateDay := hisoryPreDate
+					preDateDay := hisoryPreDate
+					for i := 0; i < 35; i++ {
+						nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+						if findItem, ok := dataMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+							pastValueList = append(pastValueList, findItem.Value)
+							break
+						} else {
+							preDateDayStr := preDateDay.Format(utils.FormatDate)
+							if findItem, ok := dataMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+								pastValueList = append(pastValueList, findItem.Value)
+								break
+							}
+						}
+						nextDateDay = nextDateDay.AddDate(0, 0, 1)
+						preDateDay = preDateDay.AddDate(0, 0, -1)
+					}
+				}
+				if av == "2022-11-28" {
+					fmt.Println(moveDay)
+				}
+			}
+			if av == "2022-11-28" {
+				fmt.Println(pastValueList)
+			}
+
+			if len(pastValueList) == formulaInt {
+				delete(removeDataTimeMap, av) //将待删除的日期给移除
+
+				val := CjjxSub(currentItem.Value, pastValueList)
+				if existVal, ok := existDataMap[edbCode+av]; !ok {
+					timestamp := currentDate.UnixNano() / 1e6
+					timestampStr := fmt.Sprintf("%d", timestamp)
+					addSql += GetAddSql(edbInfoIdStr, edbCode, av, timestampStr, val)
+					isAdd = true
+				} else {
+					var existValDecimal decimal.Decimal
+					existValDecimal, err = decimal.NewFromString(existVal)
+					if err != nil {
+						return
+					}
+					existStr := existValDecimal.String()
+					if existStr != val {
+						sql = ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+						sql = fmt.Sprintf(sql, dataTableName)
+						_, err = to.Raw(sql, val, edbInfoId, av).Exec()
+						if err != nil {
+							return
+						}
+					}
+				}
+			}
+			existDataMap[edbCode+av] = av
+		}
+	}
+
+	//删除已经不存在的超季节性指标数据(由于该指标当日的数据删除了)
+	{
+		removeDateList := make([]string, 0)
+		for dateTime := range removeDataTimeMap {
+			removeDateList = append(removeDateList, dateTime)
+		}
+		removeNum := len(removeDateList)
+		if removeNum > 0 {
+			//如果拼接指标变更了,那么需要删除所有的指标数据
+			tableName := GetEdbDataTableName(source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, tableName)
+			_, err = to.Raw(sql, edbInfoId, removeDateList).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除不存在的超季节性指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//确定最终值
+	var finalLast EdbInfoSearchData
+	sql = ` SELECT data_time , value FROM edb_data_predict_calculate_cjjx WHERE edb_info_id=? and data_time<=? ORDER BY data_time DESC `
+	tmpErr := to.Raw(sql, edbInfoId, latestDateStr).QueryRow(&finalLast)
+	if tmpErr != nil {
+		if tmpErr.Error() != utils.ErrNoRow() {
+			err = tmpErr
+		}else{
+			latestDateStr = "0000-00-00"
+		}
+		return
+	}else{
+		latestDateStr = finalLast.DataTime
+		latestValue = finalLast.Value
+	}
+	return
+}

+ 268 - 0
models/predict_edb_data_calculate_hbz.go

@@ -0,0 +1,268 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateHbz 新增环比值指标
+func SavePredictCalculateHbz(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string, formulaInt int) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateHbz,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ
+		edbInfo.SourceName = "预测环比值"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.EdbType = 2
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		oldCalculateFormula := edbInfo.CalculateFormula
+		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ)
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+
+		//判断计算指标是否被更换
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 && strconv.Itoa(formulaInt) == oldCalculateFormula { // 指标未被替换,同时N值未修改,无需重新计算
+			return
+		}
+
+		//删除,计算指标关联的,基础指标的关联关系
+		if count <= 0 {
+			sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				return
+			}
+			//关联关系
+			{
+				calculateMappingItem := &EdbInfoCalculateMapping{
+					EdbInfoCalculateMappingId: 0,
+					EdbInfoId:                 edbInfo.EdbInfoId,
+					Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_HBZ,
+					SourceName:                "预测环比值",
+					EdbCode:                   edbInfo.EdbCode,
+					FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+					FromEdbCode:               fromEdbInfo.EdbCode,
+					FromEdbName:               fromEdbInfo.EdbName,
+					FromSource:                fromEdbInfo.Source,
+					FromSourceName:            fromEdbInfo.SourceName,
+					FromTag:                   "",
+					Sort:                      1,
+					CreateTime:                time.Now(),
+					ModifyTime:                time.Now(),
+				}
+				_, err = to.Insert(calculateMappingItem)
+				if err != nil {
+					return
+				}
+			}
+		}
+		//清空原有数据
+		sql := ` DELETE FROM %s WHERE edb_info_id = ? `
+		sql = fmt.Sprintf(sql, dataTableName)
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateHbz(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", formulaInt)
+	return
+}
+// RefreshAllPredictCalculateHbz 刷新所有环比值数据
+func RefreshAllPredictCalculateHbz(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllPredictCalculateHbz,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateHbz(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, formulaInt)
+	return
+}
+
+// refreshAllPredictCalculateHbz 刷新所有环比值数据
+func refreshAllPredictCalculateHbz(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	// 获取关联指标数据
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, 0, "")
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+	var dateArr []string
+	dataMap := make(map[string]*EdbInfoSearchData)
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+	}
+	fmt.Println("source:", source)
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source)
+	fmt.Println("dataTableName:", dataTableName)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
+	if err != nil {
+		return
+	}
+	existDataMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v.Value
+	}
+	addSql := ` INSERT INTO edb_data_predict_calculate_hbz(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+	existMap := make(map[string]string)
+	dataLen := len(dataList)
+	fmt.Println("dataLen:", dataLen)
+	for i := 0; i < dataLen; i++ {
+		j := i + formulaInt
+		if j < dataLen {
+			//当期
+			currentItem := dataList[i]
+			preItem := dataList[j]
+			if currentItem != nil && preItem != nil {
+				existKey := edbCode + currentItem.DataTime
+
+				if _, ok := existMap[existKey]; !ok {
+					currentDate, _ := time.Parse(utils.FormatDate, currentItem.DataTime)
+					timestamp := currentDate.UnixNano() / 1e6
+					timestampStr := fmt.Sprintf("%d", timestamp)
+					val := HbzDiv(currentItem.Value, preItem.Value)
+					if val != "" {
+						if fromEdbInfo.LatestDate == currentItem.DataTime {
+							latestValueDecimal, tmpErr := decimal.NewFromString(val)
+							if tmpErr != nil {
+								err = tmpErr
+								return
+							}
+							latestValue, _ = latestValueDecimal.Truncate(4).Float64() //保留4位小数
+						}
+						if existVal, findOk := existDataMap[currentItem.DataTime]; !findOk {
+							addSql += GetAddSql(edbInfoIdStr, edbCode, currentItem.DataTime, timestampStr, val)
+							isAdd = true
+						} else {
+							var existValDecimal decimal.Decimal
+							existValDecimal, err = decimal.NewFromString(existVal)
+							if err != nil {
+								return
+							}
+							existStr := existValDecimal.String()
+							if existStr != val {
+								sql = ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+								sql = fmt.Sprintf(sql, dataTableName)
+								_, err = to.Raw(sql, val, edbInfoId, currentItem.DataTime).Exec()
+								if err != nil {
+									return
+								}
+							}
+						}
+					}
+				}
+				existMap[existKey] = currentItem.DataTime
+			}
+		}
+	}
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			return
+		}
+	}
+	return
+}

+ 301 - 0
models/predict_edb_data_calculate_hcz.go

@@ -0,0 +1,301 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateHcz 新增环差值指标
+func SavePredictCalculateHcz(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string, formulaInt int) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateHcz,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ
+		edbInfo.SourceName = "预测环差值"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.EdbType = 2
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		oldCalculateFormula := edbInfo.CalculateFormula
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//判断计算指标是否被更换
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 && strconv.Itoa(formulaInt) == oldCalculateFormula { // 指标未被替换,同时N值未修改,无需重新计算
+			return
+		}
+
+		//删除,计算指标关联的,基础指标的关联关系
+		if count <= 0 {
+			sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				return
+			}
+			//关联关系
+			{
+				calculateMappingItem := &EdbInfoCalculateMapping{
+					EdbInfoCalculateMappingId: 0,
+					EdbInfoId:                 edbInfo.EdbInfoId,
+					Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_HCZ,
+					SourceName:                "预测环差值",
+					EdbCode:                   edbInfo.EdbCode,
+					FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+					FromEdbCode:               fromEdbInfo.EdbCode,
+					FromEdbName:               fromEdbInfo.EdbName,
+					FromSource:                fromEdbInfo.Source,
+					FromSourceName:            fromEdbInfo.SourceName,
+					FromTag:                   "",
+					Sort:                      1,
+					CreateTime:                time.Now(),
+					ModifyTime:                time.Now(),
+				}
+				_, err = to.Insert(calculateMappingItem)
+				if err != nil {
+					return
+				}
+			}
+		}
+		//清空原有数据
+		sql := ` DELETE FROM edb_data_predict_calculate_hcz WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateHcz(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "", formulaInt)
+
+	return
+}
+
+// RefreshAllPredictCalculateHcz 刷新所有环差值数据
+func RefreshAllPredictCalculateHcz(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("refreshAllPredictCalculateHcz,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateHcz(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate, formulaInt)
+	return
+}
+
+// refreshAllPredictCalculateHcz 刷新所有环差值数据
+func refreshAllPredictCalculateHcz(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, formulaInt int) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	// 获取关联指标数据
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, 0, "")
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+	var dateArr []string
+	dataMap := make(map[string]*EdbInfoSearchData)
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+	}
+	fmt.Println("source:", source)
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source)
+	fmt.Println("dataTableName:", dataTableName)
+
+	var existPars []interface{}
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	//if startDate != "" {
+	//	sql += " AND data_time>=? "
+	//	existPars = append(existPars, startDate)
+	//}
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId, existPars).QueryRows(&existDataList)
+	if err != nil {
+		return
+	}
+	existDataMap := make(map[string]string)
+	removeDateMap := make(map[string]string) //需要移除的日期
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v.Value
+		removeDateMap[v.DataTime] = v.DataTime
+	}
+	//fmt.Println("existDataMap:", existDataMap)
+	addSql := ` INSERT INTO edb_data_predict_calculate_hcz(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+	existMap := make(map[string]string)
+	dataLen := len(dataList)
+	fmt.Println("dataLen:", dataLen)
+	for i := 0; i < dataLen; i++ {
+		j := i + formulaInt
+		if j < dataLen {
+			//当期
+			currentItem := dataList[i]
+			preItem := dataList[j]
+			if currentItem != nil && preItem != nil {
+				existKey := edbCode + currentItem.DataTime
+				if _, ok := existMap[existKey]; !ok {
+
+					currentDate, _ := time.Parse(utils.FormatDate, currentItem.DataTime)
+					//fmt.Println(currentDate)
+					timestamp := currentDate.UnixNano() / 1e6
+					timestampStr := fmt.Sprintf("%d", timestamp)
+					val := HczDiv(currentItem.Value, preItem.Value)
+					if val != "" {
+						if fromEdbInfo.LatestDate == currentItem.DataTime {
+							latestValueDecimal, tmpErr := decimal.NewFromString(val)
+							if tmpErr != nil {
+								err = tmpErr
+								return
+							}
+							latestValue, _ = latestValueDecimal.Truncate(4).Float64() //保留4位小数
+						}
+						// 有计算出来值,那么就从待删除指标中移除
+						delete(removeDateMap, currentItem.DataTime)
+
+						if existVal, findOk := existDataMap[currentItem.DataTime]; !findOk {
+							addSql += GetAddSql(edbInfoIdStr, edbCode, currentItem.DataTime, timestampStr, val)
+							isAdd = true
+						} else {
+							var existValDecimal decimal.Decimal
+							existValDecimal, err = decimal.NewFromString(existVal)
+							if err != nil {
+								return
+							}
+							existStr := existValDecimal.String()
+							if existStr != val {
+								sql = ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+								sql = fmt.Sprintf(sql, dataTableName)
+								_, err = to.Raw(sql, val, edbInfoId, currentItem.DataTime).Exec()
+								if err != nil {
+									return
+								}
+							}
+						}
+					}
+				}
+				existMap[existKey] = currentItem.DataTime
+			}
+		}
+	}
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//fmt.Println(removeDateMap)
+	if len(removeDateMap) > 0 {
+		removeDateList := make([]string, 0) //需要移除的日期
+		for k := range removeDateMap {
+			removeDateList = append(removeDateList, k)
+		}
+		removeDateStr := strings.Join(removeDateList, `","`)
+		removeDateStr = `"` + removeDateStr + `"`
+		//如果拼接指标变更了,那么需要删除所有的指标数据
+		tableName := GetEdbDataTableName(source)
+		sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+
+		_, err = to.Raw(sql, edbInfoId).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除计算失败的计算指标数据失败,Err:" + err.Error())
+			return
+		}
+	}
+	return
+}

+ 606 - 0
models/predict_edb_data_calculate_ljztbpj.go

@@ -0,0 +1,606 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"sort"
+	"strings"
+	"time"
+)
+
+// EdbDataPredictCalculateLjztbpj 累计值同比拼接数据结构体
+type EdbDataPredictCalculateLjztbpj struct {
+	EdbDataId     int `orm:"column(edb_data_id);pk"`
+	EdbInfoId     int
+	EdbCode       string
+	DataTime      string
+	Value         float64
+	Status        int
+	CreateTime    time.Time
+	ModifyTime    time.Time
+	DataTimestamp int64
+}
+
+// SavePredictCalculateLjztbpj 新增累计值同比拼接数据
+func SavePredictCalculateLjztbpj(req *EdbInfoCalculateBatchSaveReq, firstEdbInfo, secondEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateLjztbpj,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	//最近开始的时间
+	var lastDateTime time.Time
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	//获取待拼接指标
+	{
+		/*var condition string
+		var pars []interface{}
+
+		//获取待拼接指标最近的个12月31日有值的年份
+		condition += " AND data_time like ? AND edb_info_id=? "
+		pars = append(pars, "%12-31", firstEdbInfo.EdbInfoId)
+
+		lastEdbData, tmpErr := GetLastEdbData(condition, pars, firstEdbInfo.Source)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}*/
+		var firstDataList []*EdbInfoSearchData
+		var lastEdbData *EdbInfoSearchData
+		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+		for _, v := range firstDataList {
+			if strings.Contains(v.DataTime, "-12-31") {
+				lastEdbData = v
+			}
+		}
+
+		if lastEdbData == nil {
+			err = errors.New("找不到最近的12月31号")
+			return
+		}
+		lastDateTime, _ = time.ParseInLocation(utils.FormatDate, lastEdbData.DataTime, time.Local)
+	}
+
+	if req.EdbInfoId <= 0 {
+		edbInfo = &EdbInfo{
+			EdbInfoType:      1,
+			SourceName:       "预测累计值同比拼接",
+			Source:           utils.DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ,
+			EdbCode:          edbCode,
+			EdbName:          req.EdbName,
+			EdbNameSource:    req.EdbName,
+			Frequency:        req.Frequency,
+			Unit:             req.Unit,
+			StartDate:        firstEdbInfo.StartDate,
+			EndDate:          firstEdbInfo.EndDate,
+			ClassifyId:       req.ClassifyId,
+			SysUserId:        sysUserId,
+			SysUserRealName:  sysUserRealName,
+			UniqueCode:       uniqueCode,
+			CreateTime:       time.Now(),
+			ModifyTime:       time.Now(),
+			CalculateFormula: lastDateTime.Format(utils.FormatDate),
+			EdbType:          2,
+		}
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//关联关系
+		{
+			existItemA = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+				FromEdbCode:               firstEdbInfo.EdbCode,
+				FromEdbName:               firstEdbInfo.EdbName,
+				FromSource:                firstEdbInfo.Source,
+				FromSourceName:            firstEdbInfo.SourceName,
+				FromTag:                   "A",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemA)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemA.EdbInfoCalculateMappingId = int(insertId)
+		}
+
+		//同比值指标
+		{
+			existItemB = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+				FromEdbCode:               secondEdbInfo.EdbCode,
+				FromEdbName:               secondEdbInfo.EdbName,
+				FromSource:                secondEdbInfo.Source,
+				FromSourceName:            secondEdbInfo.SourceName,
+				FromTag:                   "B",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemB)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemB.EdbInfoCalculateMappingId = int(insertId)
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		nowEdbInfo := *edbInfo // 现在的指标信息
+
+		sql := ``
+		//修改指标信息
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = lastDateTime.Format(utils.FormatDate)
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//查询出所有的关联指标
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId)
+		var existList []*EdbInfoCalculateMapping
+		existList, err = GetEdbInfoCalculateListByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		for _, existItem := range existList {
+			if existItem.FromTag == "A" {
+				existItemA = existItem
+			} else if existItem.FromTag == "B" {
+				existItemB = existItem
+			}
+		}
+		if existItemA == nil {
+			err = errors.New("原待拼接指标不存在")
+			return
+		}
+		if existItemB == nil {
+			err = errors.New("原同比值指标不存在")
+			return
+		}
+		// 是否需要删除数据重新计算
+		isNeedCalculateData := false
+
+		// 如果截止日期变更,那么需要重新计算
+		if lastDateTime.Format(utils.FormatDate) != nowEdbInfo.CalculateFormula {
+			isNeedCalculateData = true
+		}
+
+		//待拼接指标数据
+		//如果拼接指标变更了,那么需要删除所有的指标进行重新拼接
+		if existItemA.FromEdbInfoId != firstEdbInfo.EdbInfoId {
+			//删除之前的A指标关联关系
+			sql = ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+			_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemA.FromEdbInfoId).Exec()
+			if err != nil {
+				err = errors.New("删除拼接日期之前的指标关联关系失败,Err:" + err.Error())
+				return
+			}
+		}
+
+		//同比值指标
+		if existItemB.FromEdbInfoId != secondEdbInfo.EdbInfoId {
+			//删除之前的B指标关联关系
+			sql = ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+			_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemB.FromEdbInfoId).Exec()
+			if err != nil {
+				err = errors.New("删除拼接日期之后的指标关联关系失败,Err:" + err.Error())
+				return
+			}
+		}
+		//添加新的指标关系
+		if existItemA.FromEdbInfoId != firstEdbInfo.EdbInfoId {
+			existItemA = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+				FromEdbCode:               firstEdbInfo.EdbCode,
+				FromEdbName:               firstEdbInfo.EdbName,
+				FromSource:                firstEdbInfo.Source,
+				FromSourceName:            firstEdbInfo.SourceName,
+				FromTag:                   "A",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemA)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemA.EdbInfoCalculateMappingId = int(insertId)
+
+			isNeedCalculateData = true
+		}
+
+		//添加新的指标关系
+		if existItemB.FromEdbInfoId != secondEdbInfo.EdbInfoId {
+			existItemB = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+				FromEdbCode:               secondEdbInfo.EdbCode,
+				FromEdbName:               secondEdbInfo.EdbName,
+				FromSource:                secondEdbInfo.Source,
+				FromSourceName:            secondEdbInfo.SourceName,
+				FromTag:                   "B",
+				Sort:                      2,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+
+			insertId, tmpErr := to.Insert(existItemB)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemB.EdbInfoCalculateMappingId = int(insertId)
+
+			isNeedCalculateData = true
+		}
+
+		// 如果需要重新计算,那么先删除所有的指标数据,然后再重新计算
+		if isNeedCalculateData {
+			// 删除之前所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql = fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? `, tableName)
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				err = errors.New("删除所有的累计值同比拼接指标数据失败,Err:" + err.Error())
+				return
+			}
+		}else{
+			return
+		}
+	}
+
+	// 添加数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateLjztbpj(to, edbInfo, firstEdbInfo, secondEdbInfo, existItemB)
+
+	return
+}
+
+// RefreshAllPredictCalculateLjztbpj 刷新所有 累计值同比拼接 数据
+func RefreshAllPredictCalculateLjztbpj(edbInfo *EdbInfo) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateLjztbpj,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//查询关联指标信息
+	var existCondition string
+	var existPars []interface{}
+	existCondition += " AND edb_info_id=? "
+	existPars = append(existPars, edbInfo.EdbInfoId)
+	existList, err := GetEdbInfoCalculateListByCondition(existCondition, existPars)
+	if err != nil {
+		err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+		return
+	}
+
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	for _, existItem := range existList {
+		if existItem.FromTag == "A" {
+			existItemA = existItem
+		} else if existItem.FromTag == "B" {
+			existItemB = existItem
+		}
+	}
+	if existItemA == nil {
+		err = errors.New("原待拼接指标不存在")
+		return
+	}
+	if existItemB == nil {
+		err = errors.New("原同比值指标不存在")
+		return
+	}
+	fromEdbInfo, err := GetEdbInfoById(existItemA.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+
+	secondEdbInfo, err := GetEdbInfoById(existItemB.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+	// 刷新数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateLjztbpj(to, edbInfo, fromEdbInfo, secondEdbInfo, existItemB)
+	return
+}
+
+// refreshAllPredictCalculateLjztbpj 刷新所有 累计值同比拼接 数据
+func refreshAllPredictCalculateLjztbpj(to orm.TxOrmer, edbInfo, firstEdbInfo, secondEdbInfo *EdbInfo, existItemB *EdbInfoCalculateMapping) (latestDateStr string, latestValue float64, err error) {
+	//根据指标id获取全部的数据
+	var dataList []*EdbDataPredictCalculateLjztbpj
+	sql := ` SELECT * FROM edb_data_predict_calculate_ljztbpj WHERE edb_info_id=? ORDER BY data_time DESC `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).QueryRows(&dataList)
+	if err != nil {
+		return
+	}
+	latestDateStr = secondEdbInfo.LatestDate
+
+	//待拼接指标map
+	pjDataMap := make(map[string]float64)     //需要入库的数据
+	nowEdbDataMap := make(map[string]float64) //当前指标的数据(已经在库里了,不需要重新)
+	//拼接指标的日期切片数据
+	pjEdbDataTimeList := make([]string, 0)
+
+	dataMap := make(map[string]*EdbDataPredictCalculateLjztbpj)
+	for _, v := range dataList {
+		pjEdbDataTimeList = append(pjEdbDataTimeList, v.DataTime)
+		dataMap[v.DataTime] = v
+		nowEdbDataMap[v.DataTime] = v.Value
+	}
+
+	// 原数据开始计算日期
+	startCalculationDate, _ := time.ParseInLocation(utils.FormatDate, edbInfo.CalculateFormula, time.Local)
+
+	//待拼接指标
+	{
+		/*var condition string
+		var pars []interface{}
+
+		condition += " AND data_time <= ? AND edb_info_id=? "
+		pars = append(pars, startCalculationDate, existItemA.FromEdbInfoId)
+
+		//第一个指标的数据列表
+		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}*/
+		var firstDataList []*EdbInfoSearchData
+		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+
+		for _, v := range firstDataList {
+			if v.DataTime > startCalculationDate.Format(utils.FormatDate) {
+				continue
+			}
+			//时间戳
+			if edbData, ok := dataMap[v.DataTime]; ok {
+				if edbData.Value != v.Value {
+					//更新指标数据
+					edbData.Value = v.Value
+					_, _ = to.Update(edbData, "Value")
+				}
+			} else {
+				pjDataMap[v.DataTime] = v.Value
+				pjEdbDataTimeList = append(pjEdbDataTimeList, v.DataTime)
+			}
+
+			//将新的数据存入已入库指标map里面,以便后续计算
+			nowEdbDataMap[v.DataTime] = v.Value
+		}
+	}
+
+	//同比值指标map
+	tbzEdbDataMap := make(map[string]float64)
+
+	//同比值日期切片列表
+	tbzEdbDataTimeList := make([]string, 0)
+
+	//同比值指标
+	{
+		var condition string
+		pars := make([]interface{}, 0)
+
+		condition += " AND data_time > ? AND edb_info_id = ? "
+		pars = append(pars, startCalculationDate, existItemB.FromEdbInfoId)
+
+		//第二个指标的数据列表
+		secondDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		for _, v := range secondDataList {
+			tbzEdbDataMap[v.DataTime] = v.Value
+			tbzEdbDataTimeList = append(tbzEdbDataTimeList, v.DataTime)
+		}
+	}
+
+	sort.Strings(tbzEdbDataTimeList)
+
+	// 遍历现有的数据,判断拼接指标中是否存在该日期数据,如果拼接指标无此数据,那么需要删除该日期数据(日期的判断:需要在开始计算日期之后)
+	removeDateList := make([]string, 0)
+	for nowEdbDate := range nowEdbDataMap {
+		nowEdbDateTime, _ := time.ParseInLocation(utils.FormatDate, nowEdbDate, time.Local)
+		//校验日期 需要 大于 拼接前日期
+		if startCalculationDate.Before(nowEdbDateTime) {
+			if _, ok := tbzEdbDataMap[nowEdbDate]; !ok {
+				// 同比指标中,不存在该日期数据,那么需要移除 现有数据 中该日期的数据
+				removeDateList = append(removeDateList, nowEdbDate)
+			}
+		}
+	}
+
+	//待修改的指标数据map(index:日期,value:值)
+	updateEdbDataMap := make(map[string]float64)
+	for _, v := range tbzEdbDataTimeList {
+		tbzDataTime, _ := time.ParseInLocation(utils.FormatDate, v, time.Local)
+
+		//获取拼接指标上一年同一天的数据
+		var pjDataTime time.Time
+		if tbzDataTime.Month() == 2 {
+			pjDataTime = tbzDataTime.AddDate(0, -11, 0)
+			pjDataTime = time.Date(pjDataTime.Year(), pjDataTime.Month(), 1, 0, 0, 0, 0, time.Now().Location()).AddDate(0, 0, -1)
+		} else {
+			pjDataTime = tbzDataTime.AddDate(-1, 0, 0)
+		}
+
+		//校验现有数据中,是否存在该日期的数据,如果存在的话,那么就要去校验 最新计算数据 与 现有数据 是否一致
+		if nowEdbDataValue, isHas := nowEdbDataMap[v]; isHas {
+			//获取去年今日的数据,获取到后,然后是去修改该日期的数据
+			if lastYearEdbDataValue, ok := nowEdbDataMap[pjDataTime.Format(utils.FormatDate)]; ok {
+				tbzDataValue := tbzEdbDataMap[v] //同比值
+				currValue := lastYearEdbDataValue * (1 + tbzDataValue/100)
+				currValue, _ = decimal.NewFromFloat(currValue).Truncate(4).Float64() //保留4位小数
+				//如果计算出来的值与库里面的值不匹配,那么就去修改该值
+				if nowEdbDataValue != currValue {
+					//将计算后的数据存入待拼接指标map里面,以便后续计算
+					updateEdbDataMap[v] = currValue
+				}
+			}
+		} else {
+			//因为 现有数据中 不存在该日期数据,那么需要做新增数据处理
+			//如果去年今日存在该数据,那么就去计算当前的数据
+			if pjDataValue, ok := nowEdbDataMap[pjDataTime.Format(utils.FormatDate)]; ok {
+				tbzDataValue := tbzEdbDataMap[v] //同比值
+				currValue := pjDataValue * (1 + tbzDataValue/100)
+
+				currValue, _ = decimal.NewFromFloat(currValue).Truncate(4).Float64()
+				//将计算后的数据存入已入库指标map里面,以便后续计算
+				nowEdbDataMap[v] = currValue
+
+				//将计算后的数据存入待拼接指标map里面,以便后续入库
+				pjDataMap[v] = currValue
+				pjEdbDataTimeList = append(pjEdbDataTimeList, v)
+			}
+		}
+	}
+
+	//新增的数据入库
+	{
+		addDataList := make([]*EdbDataPredictCalculateLjztbpj, 0)
+		//日期排序下
+		sort.Strings(pjEdbDataTimeList)
+		//这么做的目的是为了让数据插入的时候,可以正序插入(业务上没啥卵用,就是为了让我看数据的时候舒服点,手动狗头-_-|)
+		for _, dataTime := range pjEdbDataTimeList {
+			if dataValue, ok := pjDataMap[dataTime]; ok {
+				//时间戳
+				currentDate, _ := time.Parse(utils.FormatDate, dataTime)
+				timestamp := currentDate.UnixNano() / 1e6
+
+				edbDataLjztbpj := &EdbDataPredictCalculateLjztbpj{
+					EdbInfoId:     edbInfo.EdbInfoId,
+					EdbCode:       edbInfo.EdbCode,
+					DataTime:      dataTime,
+					Value:         dataValue,
+					Status:        1,
+					CreateTime:    time.Now(),
+					ModifyTime:    time.Now(),
+					DataTimestamp: timestamp,
+				}
+				addDataList = append(addDataList, edbDataLjztbpj)
+			}
+		}
+
+		//数据入库
+		if len(addDataList) > 0 {
+			_, tmpErr := to.InsertMulti(len(addDataList), addDataList)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+		}
+	}
+
+	//删除已经不存在的累计同比拼接指标数据(由于同比值当日的数据删除了)
+	{
+		if len(removeDateList) > 0 {
+			removeDateStr := strings.Join(removeDateList, `","`)
+			removeDateStr = `"` + removeDateStr + `"`
+			//如果拼接指标变更了,那么需要删除所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				err = errors.New("删除不存在的累计值同比拼接指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	//修改现有的数据中对应的值
+	{
+		tableName := GetEdbDataTableName(edbInfo.Source)
+		for edbDate, edbDataValue := range updateEdbDataMap {
+			sql := fmt.Sprintf(` UPDATE  %s set value = ?,modify_time=now() WHERE edb_info_id = ? and data_time = ? `, tableName)
+			_, err = to.Raw(sql, edbDataValue, edbInfo.EdbInfoId, edbDate).Exec()
+			if err != nil {
+				err = errors.New("更新现有的累计值同比拼接指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	//确定最终值
+	var finalLast EdbInfoSearchData
+	sql = ` SELECT data_time , value FROM edb_data_predict_calculate_ljztbpj WHERE edb_info_id=? and data_time<=? ORDER BY data_time DESC `
+	tmpErr := to.Raw(sql, edbInfo.EdbInfoId, latestDateStr).QueryRow(&finalLast)
+	if tmpErr != nil {
+		if tmpErr.Error() != utils.ErrNoRow() {
+			err = tmpErr
+		}
+		return
+	}else{
+		latestDateStr = finalLast.DataTime
+		latestValue = finalLast.Value
+	}
+	return
+}

+ 350 - 0
models/predict_edb_data_calculate_ljzzy.go

@@ -0,0 +1,350 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateLjzzy 累计值转月
+func SavePredictCalculateLjzzy(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateLjzzy,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY
+		edbInfo.SourceName = "预测累计值转月值"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.EdbType = 2
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+
+		var count int
+		//判断计算指标是否被更换
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 { // 指标未被替换,无需重新计算
+			return
+		}
+
+		//删除,计算指标关联的,基础指标的关联关系
+		sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+
+		//清空原有数据
+		sql = ` DELETE FROM edb_data_predict_calculate_ljzzy WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+
+		//关联关系
+		{
+			calculateMappingItem := &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY,
+				SourceName:                "预测累计值转月值",
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+				FromEdbCode:               fromEdbInfo.EdbCode,
+				FromEdbName:               fromEdbInfo.EdbName,
+				FromSource:                fromEdbInfo.Source,
+				FromSourceName:            fromEdbInfo.SourceName,
+				FromTag:                   "",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateLjzzy(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, "", "")
+
+	return
+}
+
+// RefreshAllPredictCalculateLjzzy 刷新全部累计值转月数据
+func RefreshAllPredictCalculateLjzzy(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("refreshAllPredictCalculateLjzzy,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateLjzzy(to, edbInfoId, source, fromEdbInfo, edbCode, startDate, endDate)
+
+	return
+}
+
+func refreshAllPredictCalculateLjzzy(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, 1, startDate)
+	if err != nil {
+		return
+	}
+	latestDateStr = fromEdbInfo.LatestDate
+	yearMap := make(map[int]map[int]*EdbInfoSearchData)
+	dataLen := len(dataList)
+	for i := 0; i < dataLen; i++ {
+		item := dataList[i]
+		//日其中获取年
+		var itemDate time.Time
+		itemDate, err = time.Parse(utils.FormatDate, item.DataTime)
+		if err != nil {
+			return
+		}
+		year := itemDate.Year()
+		month := int(itemDate.Month())
+		if monthMap, yok := yearMap[year]; yok {
+			monthMap[month] = item
+			yearMap[year] = monthMap
+		} else {
+			monthMap = make(map[int]*EdbInfoSearchData)
+			monthMap[month] = item
+			yearMap[year] = monthMap
+		}
+	}
+
+	addSql := ` INSERT INTO edb_data_predict_calculate_ljzzy(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
+	if err != nil {
+		return
+	}
+	dataMap := make(map[string]string)
+	for _, v := range existDataList {
+		dataMap[v.DataTime] = v.Value
+	}
+	existDataMap := make(map[string]string)
+
+	for yk, yv := range yearMap {
+		_, oneMonthOk := yv[1]
+		_, twoMonthOk := yv[2]
+		if !oneMonthOk && !twoMonthOk {
+			continue
+		}
+		for i := 1; i <= 12; i++ {
+			fmt.Println(yk, i, yv[i])
+			dataCurrentItem := yv[i]
+			var date string
+			var val float64
+			if dataCurrentItem != nil {
+				if i == 1 || i == 2 {
+					if _, mok := yv[1]; mok { //1月有值
+						if i == 1 {
+							date = dataCurrentItem.DataTime
+							val, _ = decimal.NewFromFloat(dataCurrentItem.Value).Float64() //a.Div(b).Float64()
+						}
+						if i == 2 {
+							dataOneItem := yv[1]
+							date = dataCurrentItem.DataTime
+							twoMonth := decimal.NewFromFloat(dataCurrentItem.Value)
+							oneMonth := decimal.NewFromFloat(dataOneItem.Value)
+							val, _ = twoMonth.Sub(oneMonth).Float64()
+						}
+					} else { //1月无值
+						dataTwoItem := yv[2]
+						if i == 1 {
+							date = strconv.Itoa(yk) + "-01-31"
+							a := decimal.NewFromFloat(dataTwoItem.Value)
+							b := decimal.NewFromFloat(2.0)
+							val, _ = a.Div(b).Float64()
+						}
+						if i == 2 {
+							//1月无值:1月=2月/2
+							{
+								date = strconv.Itoa(yk) + "-01-31"
+								a := decimal.NewFromFloat(dataTwoItem.Value)
+								b := decimal.NewFromFloat(2.0)
+								val, _ = a.Div(b).Float64()
+								tmpSql, newAdd, tmpErr := calculateLjzzy(edbInfoId, date, edbInfoIdStr, edbCode, dataTableName, addSql, val, dataMap, existDataMap, to)
+								if !isAdd {
+									isAdd = newAdd
+								}
+								addSql = tmpSql
+								if tmpErr != nil {
+									err = tmpErr
+									return
+								}
+							}
+							//end 1月无值
+
+							date = dataCurrentItem.DataTime
+							a := decimal.NewFromFloat(dataTwoItem.Value)
+							b := decimal.NewFromFloat(2.0)
+							val, _ = a.Div(b).Float64()
+						}
+					}
+				} else {
+					dataPreItem := yv[i-1]
+					if dataPreItem != nil {
+						date = dataCurrentItem.DataTime
+						//val =  dataCurrentItem.Value - dataPreItem.Value
+						a := decimal.NewFromFloat(dataCurrentItem.Value)
+						b := decimal.NewFromFloat(dataPreItem.Value)
+						val, _ = a.Sub(b).Float64()
+					}
+				}
+			}
+			if date != "" {
+				//saveValue := utils.SubFloatToString(val, 4)
+				////判断数据是否存在
+				//if existVal, ok := dataMap[date]; !ok {
+				//	dataTime, _ := time.Parse(utils.FormatDate, date)
+				//	timestamp := dataTime.UnixNano() / 1e6
+				//	timeStr := fmt.Sprintf("%d", timestamp)
+				//	if _, existOk := existDataMap[date]; !existOk {
+				//		addSql += GetAddSql(edbInfoIdStr, edbCode, date, timeStr, saveValue)
+				//		isAdd = true
+				//	}
+				//	existDataMap[date] = date
+				//} else {
+				//	if existVal != saveValue {
+				//		sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+				//		sql = fmt.Sprintf(sql, dataTableName)
+				//		_, err = to.Raw(sql, saveValue, edbInfoId, date).Exec()
+				//		if err != nil {
+				//			return err
+				//		}
+				//	}
+				//}
+				tmpSql, newAdd, tmpErr := calculateLjzzy(edbInfoId, date, edbInfoIdStr, edbCode, dataTableName, addSql, val, dataMap, existDataMap, to)
+				if !isAdd {
+					isAdd = newAdd
+				}
+				addSql = tmpSql
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+			}
+		}
+	}
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			fmt.Println("refreshAllPredictCalculateLjzzy add Err", err.Error())
+			return
+		}
+	}
+
+	//确定最终值
+	var finalLast EdbInfoSearchData
+	sql = ` SELECT data_time , value FROM edb_data_predict_calculate_ljzzy WHERE edb_info_id=? and data_time<=? ORDER BY data_time DESC `
+	tmpErr := to.Raw(sql, edbInfoId, latestDateStr).QueryRow(&finalLast)
+	if tmpErr != nil {
+		if tmpErr.Error() != utils.ErrNoRow() {
+			err = tmpErr
+		}
+		return
+	}else{
+		latestDateStr = finalLast.DataTime
+		latestValue = finalLast.Value
+	}
+	return
+}

+ 647 - 0
models/predict_edb_data_calculate_nhcc.go

@@ -0,0 +1,647 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"math"
+	"strings"
+	"time"
+)
+
+// EdbDataPredictCalculateNhcc 拟合残差数据结构体
+type EdbDataPredictCalculateNhcc struct {
+	EdbDataId     int `orm:"column(edb_data_id);pk"`
+	EdbInfoId     int
+	EdbCode       string
+	DataTime      string
+	Value         float64
+	Status        int
+	CreateTime    time.Time
+	ModifyTime    time.Time
+	DataTimestamp int64
+}
+
+// SavePredictCalculateNhcc 新增拟合残差数据
+func SavePredictCalculateNhcc(req *EdbInfoCalculateBatchSaveReq, firstEdbInfo, secondEdbInfo *EdbInfo, edbCode, uniqueCode string, nhccDate NhccDate, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateNhcc,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	if req.EdbInfoId <= 0 {
+		edbInfo = &EdbInfo{
+			EdbInfoType:      1,
+			SourceName:       "预测拟合残差",
+			Source:           utils.DATA_SOURCE_PREDICT_CALCULATE_NHCC,
+			EdbCode:          edbCode,
+			EdbName:          req.EdbName,
+			EdbNameSource:    req.EdbName,
+			Frequency:        req.Frequency,
+			Unit:             req.Unit,
+			StartDate:        firstEdbInfo.StartDate,
+			EndDate:          firstEdbInfo.EndDate,
+			ClassifyId:       req.ClassifyId,
+			SysUserId:        sysUserId,
+			SysUserRealName:  sysUserRealName,
+			UniqueCode:       uniqueCode,
+			CreateTime:       time.Now(),
+			ModifyTime:       time.Now(),
+			CalculateFormula: req.Formula,
+			EdbType:          2,
+		}
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//第一个指标
+		{
+			existItemA = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+				FromEdbCode:               firstEdbInfo.EdbCode,
+				FromEdbName:               firstEdbInfo.EdbName,
+				FromSource:                firstEdbInfo.Source,
+				FromSourceName:            firstEdbInfo.SourceName,
+				FromTag:                   "A",
+				MoveValue:                 req.EdbInfoIdArr[0].MoveValue,
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemA)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemA.EdbInfoCalculateMappingId = int(insertId)
+		}
+
+		//第二个指标
+		{
+			existItemB = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+				FromEdbCode:               secondEdbInfo.EdbCode,
+				FromEdbName:               secondEdbInfo.EdbName,
+				FromSource:                secondEdbInfo.Source,
+				FromSourceName:            secondEdbInfo.SourceName,
+				FromTag:                   "B",
+				MoveValue:                 req.EdbInfoIdArr[1].MoveValue,
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemB)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemB.EdbInfoCalculateMappingId = int(insertId)
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		nowEdbInfo := *edbInfo // 现在的指标信息
+
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId)
+
+		//查询出所有的关联指标
+		var existList []*EdbInfoCalculateMapping
+		existList, err = GetEdbInfoCalculateListByCondition(existCondition, existPars)
+		if err != nil {
+			err = fmt.Errorf("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		for _, existItem := range existList {
+			if existItem.FromTag == "A" {
+				existItemA = existItem
+			} else if existItem.FromTag == "B" {
+				existItemB = existItem
+			}
+		}
+		if existItemA == nil {
+			err = errors.New("原自变量指标不存在")
+			return
+		}
+		if existItemB == nil {
+			err = errors.New("原因变量指标不存在")
+			return
+		}
+		// 是否需要删除数据重新计算
+		isNeedCalculateData := false
+
+		// 如果截止日期变更,那么需要重新计算
+		if req.Formula != nowEdbInfo.CalculateFormula {
+			isNeedCalculateData = true
+		}
+		var isDeleteA, isDeleteB bool
+		// 如果指标变了,那么需要删除关系
+		{
+			if existItemA.FromEdbInfoId != firstEdbInfo.EdbInfoId {
+				//删除之前的A指标关联关系
+				sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+				_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemA.FromEdbInfoId).Exec()
+				if err != nil {
+					err = fmt.Errorf("删除指标A关联关系失败,Err:" + err.Error())
+					return
+				}
+				isDeleteA = true
+			}
+			//并重新计算
+			if existItemB.FromEdbInfoId != secondEdbInfo.EdbInfoId {
+				//删除之前的B指标关联关系
+				sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+				_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemB.FromEdbInfoId).Exec()
+				if err != nil {
+					err = fmt.Errorf("删除指标B关联关系失败,Err:" + err.Error())
+					return
+				}
+				isDeleteB = true
+			}
+		}
+		//第一个指标数据
+		{
+			// 如果指标变了,那么需要删除关系,并重新计算
+			if isDeleteA {
+				//添加新的指标关系
+				{
+					existItemA = &EdbInfoCalculateMapping{
+						EdbInfoCalculateMappingId: 0,
+						EdbInfoId:                 edbInfo.EdbInfoId,
+						Source:                    edbInfo.Source,
+						SourceName:                edbInfo.SourceName,
+						EdbCode:                   edbInfo.EdbCode,
+						FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+						FromEdbCode:               firstEdbInfo.EdbCode,
+						FromEdbName:               firstEdbInfo.EdbName,
+						FromSource:                firstEdbInfo.Source,
+						FromSourceName:            firstEdbInfo.SourceName,
+						FromTag:                   "A",
+						MoveValue:                 req.EdbInfoIdArr[0].MoveValue,
+						Sort:                      1,
+						CreateTime:                time.Now(),
+						ModifyTime:                time.Now(),
+					}
+					insertId, tmpErr := to.Insert(existItemA)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					existItemA.EdbInfoCalculateMappingId = int(insertId)
+
+					isNeedCalculateData = true
+				}
+			} else if existItemA.MoveValue != req.EdbInfoIdArr[0].MoveValue {
+				// 如果平移天数不一致的话,
+				existItemA.ModifyTime = time.Now()
+				existItemA.MoveValue = req.EdbInfoIdArr[0].MoveValue
+				_, err = to.Update(existItemA, "ModifyTime", "MoveValue")
+				if err != nil {
+					return
+				}
+				isNeedCalculateData = true
+			}
+		}
+
+		//第二个指标数据
+		{
+			// 如果指标变了,那么需要删除关系,并重新计算
+			if isDeleteB {
+				// 添加新的指标关联关系
+				existItemB = &EdbInfoCalculateMapping{
+					EdbInfoCalculateMappingId: 0,
+					EdbInfoId:                 edbInfo.EdbInfoId,
+					Source:                    edbInfo.Source,
+					SourceName:                edbInfo.SourceName,
+					EdbCode:                   edbInfo.EdbCode,
+					FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+					FromEdbCode:               secondEdbInfo.EdbCode,
+					FromEdbName:               secondEdbInfo.EdbName,
+					FromSource:                secondEdbInfo.Source,
+					FromSourceName:            secondEdbInfo.SourceName,
+					FromTag:                   "B",
+					MoveValue:                 req.EdbInfoIdArr[1].MoveValue,
+					Sort:                      2,
+					CreateTime:                time.Now(),
+					ModifyTime:                time.Now(),
+				}
+				insertId, tmpErr := to.Insert(existItemB)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				existItemB.EdbInfoCalculateMappingId = int(insertId)
+
+				isNeedCalculateData = true
+			} else if existItemB.MoveValue != req.EdbInfoIdArr[1].MoveValue {
+				// 如果平移天数不一致的话,
+				existItemB.ModifyTime = time.Now()
+				existItemB.MoveValue = req.EdbInfoIdArr[1].MoveValue
+				_, err = to.Update(existItemB, "ModifyTime", "MoveValue")
+				if err != nil {
+					return
+				}
+				isNeedCalculateData = true
+			}
+		}
+
+		// 如果需要重新计算,那么先删除所有的指标数据,然后再重新计算
+		if isNeedCalculateData {
+			// 删除之前所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? `, tableName)
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除历史数据失败,Err:" + err.Error())
+				return
+			}
+		}else{
+			return
+		}
+	}
+
+	//拼接数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateNhcc(to, edbInfo, firstEdbInfo, secondEdbInfo, existItemA, existItemB, nhccDate)
+
+	return
+}
+
+// RefreshAllPredictCalculateNhcc 刷新所有 拟合残差 数据
+func RefreshAllPredictCalculateNhcc(edbInfo *EdbInfo) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllPredictCalculateNhcc,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	//查询关联指标信息
+	var existCondition string
+	var existPars []interface{}
+	existCondition += " AND edb_info_id=? "
+	existPars = append(existPars, edbInfo.EdbInfoId)
+	existList, err := GetEdbInfoCalculateListByCondition(existCondition, existPars)
+	if err != nil {
+		err = fmt.Errorf("判断指标是否改变失败,Err:" + err.Error())
+		return
+	}
+
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	for _, existItem := range existList {
+		if existItem.FromTag == "A" {
+			existItemA = existItem
+		} else if existItem.FromTag == "B" {
+			existItemB = existItem
+		}
+	}
+	if existItemA == nil {
+		err = errors.New("原自变量指标不存在")
+		return
+	}
+	if existItemB == nil {
+		err = errors.New("原因变量指标不存在")
+		return
+	}
+
+	fromEdbInfo, err := GetEdbInfoById(existItemA.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+
+	secondEdbInfo, err := GetEdbInfoById(existItemB.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+	timeList := strings.Split(edbInfo.CalculateFormula, ",")
+	startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+	if err != nil {
+		return
+	}
+	endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+	if err != nil {
+		return
+	}
+	if endDate.Sub(startDate).Hours() < 48 {
+		return
+	}
+	nhccDate := NhccDate{
+		StartDate: startDate,
+		EndDate:   endDate,
+	}
+	// 刷新数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateNhcc(to, edbInfo, fromEdbInfo, secondEdbInfo, existItemA, existItemB, nhccDate)
+
+	return
+}
+
+// refreshAllPredictCalculateNhcc 刷新所有 拟合残差 数据
+func refreshAllPredictCalculateNhcc(to orm.TxOrmer, edbInfo, firstEdbInfo, secondEdbInfo *EdbInfo, existItemA, existItemB *EdbInfoCalculateMapping, nhccDate NhccDate) (latestDateStr string, latestValue float64, err error) {
+	var dataList []*EdbDataPredictCalculateNhcc
+	sql := ` SELECT * FROM edb_data_predict_calculate_nhcc WHERE edb_info_id=? ORDER BY data_time DESC `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).QueryRows(&dataList)
+	if err != nil {
+		return
+	}
+	// 计算最新的实际值的日期
+	latestDateA, _ := time.ParseInLocation(utils.FormatDate, firstEdbInfo.LatestDate, time.Local)
+	if existItemA.MoveValue != 0 {
+		latestDateA = latestDateA.AddDate(0, 0, existItemA.MoveValue)
+	}
+
+	latestDateB, _ := time.ParseInLocation(utils.FormatDate, secondEdbInfo.LatestDate, time.Local)
+	if existItemB.MoveValue != 0 {
+		latestDateB = latestDateA.AddDate(0, 0, existItemB.MoveValue)
+	}
+
+	if latestDateA.Before(latestDateB) {
+		latestDateStr = latestDateA.Format(utils.FormatDate)
+	}else{
+		latestDateStr = latestDateB.Format(utils.FormatDate)
+	}
+
+	var dateArr []string
+	dataMap := make(map[string]*EdbDataPredictCalculateNhcc)
+	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+		removeDataTimeMap[v.DataTime] = 1
+	}
+
+	addDataList := make([]*EdbDataPredictCalculateNhcc, 0)
+
+	//第一个指标
+	aDataList := make([]EdbInfoSearchData, 0)
+	aDataMap := make(map[string]float64)
+	{
+		/*var condition string
+		var pars []interface{}
+
+		condition += " AND edb_info_id=? "
+		pars = append(pars, existItemA.FromEdbInfoId)
+
+		//第一个指标的数据列表
+		firstDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemA.FromSource, 0)
+		if tmpErr != nil {
+
+			return tmpErr
+		}*/
+		var firstDataList []*EdbInfoSearchData
+		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+		aDataList, aDataMap = handleNhccData(firstDataList, existItemA.MoveValue)
+	}
+
+	//第二个指标
+	bDataList := make([]EdbInfoSearchData, 0)
+	secondDataList := make([]*EdbInfoSearchData, 0)
+	bDataMap := make(map[string]float64)
+	{
+		/*condition = ``
+		pars = make([]interface{}, 0)
+
+		condition += "  AND edb_info_id = ? "
+		pars = append(pars, existItemB.FromEdbInfoId)
+
+		//第二个指标的数据列表
+		secondDataList, err = GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+		if err != nil {
+			return
+		}*/
+		secondDataList, err = GetPredictEdbDataListAllByStartDate(secondEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+		bDataList, bDataMap = handleNhccData(secondDataList, existItemB.MoveValue)
+	}
+
+	if len(aDataList) <= 0 {
+		err = errors.New("指标A没有数据")
+		return
+	}
+	if len(bDataList) <= 0 {
+		err = errors.New("指标B没有数据")
+		return
+	}
+	// 拟合残差计算的结束日期判断
+	{
+		endAData := aDataList[len(aDataList)-1]
+		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, endAData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果A指标的最新数据日期早于拟合残差的结束日期,那么就用A指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+		endBData := bDataList[len(bDataList)-1]
+		tmpEndDate, tmpErr = time.ParseInLocation(utils.FormatDate, endBData.DataTime, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 如果B指标的最新数据日期早于拟合残差的结束日期,那么就用B指标的最新数据日期
+		if tmpEndDate.Before(nhccDate.EndDate) {
+			nhccDate.EndDate = tmpEndDate
+		}
+	}
+
+	// 计算线性方程公式
+	var a, b float64
+	{
+		coordinateData := make([]Coordinate, 0)
+		for i := nhccDate.StartDate; i.Before(nhccDate.EndDate) || i.Equal(nhccDate.EndDate); i = i.AddDate(0, 0, 1) {
+			dateStr := i.Format(utils.FormatDate)
+			xValue, ok := aDataMap[dateStr]
+			if !ok {
+				err = errors.New("指标A日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+				return
+			}
+			yValue, ok := bDataMap[dateStr]
+			if !ok {
+				err = errors.New("指标B日期:" + dateStr + "数据异常,导致计算线性方程公式失败")
+				return
+			}
+			tmpCoordinate := Coordinate{
+				X: xValue,
+				Y: yValue,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate)
+		}
+		a, b = getLinearResult(coordinateData)
+	}
+
+	if math.IsNaN(a) || math.IsNaN(b) {
+		err = errors.New("线性方程公式生成失败")
+		return
+	}
+	//fmt.Println("a:", a, ";======b:", b)
+
+	//计算B’
+	newBDataMap := make(map[string]float64)
+	{
+		//B’=aA+b
+		aDecimal := decimal.NewFromFloat(a)
+		bDecimal := decimal.NewFromFloat(b)
+		for _, aData := range aDataList {
+			xDecimal := decimal.NewFromFloat(aData.Value)
+			val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).RoundCeil(4).Float64()
+			newBDataMap[aData.DataTime] = val
+		}
+
+	}
+
+	// Delta=B-B‘
+	for _, bData := range secondDataList {
+		currDate := bData.DataTime
+		//校验待删除日期数据里面是否存在该元素,如果存在的话,那么移除该元素
+		if _, ok := removeDataTimeMap[currDate]; ok {
+			delete(removeDataTimeMap, currDate)
+		}
+
+		b2Val, ok := newBDataMap[currDate]
+		if !ok {
+			// 如果B`不存在数据,那么就退出当前循环
+			continue
+		}
+		bDecimal := decimal.NewFromFloat(bData.Value)
+		b2Decimal := decimal.NewFromFloat(b2Val)
+
+		val, _ := bDecimal.Sub(b2Decimal).RoundCeil(4).Float64()
+		// 判断之前有没有该数据
+		existData, ok := dataMap[currDate]
+		if !ok { //不存在那么就添加吧
+			currentDate, _ := time.Parse(utils.FormatDate, currDate)
+			timestamp := currentDate.UnixNano() / 1e6
+			edbDataNhcc := &EdbDataPredictCalculateNhcc{
+				EdbInfoId:     edbInfo.EdbInfoId,
+				EdbCode:       edbInfo.EdbCode,
+				DataTime:      currDate,
+				Value:         val,
+				Status:        1,
+				CreateTime:    time.Now(),
+				ModifyTime:    time.Now(),
+				DataTimestamp: timestamp,
+			}
+			addDataList = append(addDataList, edbDataNhcc)
+		} else {
+			// 如果有的话,还需要判断值是否一致,一致则不处理,不一致则修改
+			if existData.Value != val {
+				existData.Value = val
+				_, err = to.Update(existData, "Value")
+				if err != nil {
+					return
+				}
+			}
+		}
+	}
+
+	//删除已经不存在的拟合残差指标数据(由于该指标当日的数据删除了)
+	{
+		removeDateList := make([]string, 0)
+		for dateTime := range removeDataTimeMap {
+			removeDateList = append(removeDateList, dateTime)
+		}
+		removeNum := len(removeDateList)
+		if removeNum > 0 {
+			//如果拼接指标变更了,那么需要删除所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, tableName)
+			_, err = to.Raw(sql, edbInfo.EdbInfoId, removeDateList).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除不存在的拟合残差指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	//数据入库
+	if len(addDataList) > 0 {
+		tmpAddDataList := make([]*EdbDataPredictCalculateNhcc, 0)
+		i := 0
+		for _, v := range addDataList {
+			tmpAddDataList = append(tmpAddDataList, v)
+			i++
+			if i >= 500 {
+				_, err = to.InsertMulti(len(tmpAddDataList), tmpAddDataList)
+				if err != nil {
+					return
+				}
+				i = 0
+				tmpAddDataList = make([]*EdbDataPredictCalculateNhcc, 0)
+			}
+		}
+
+		if len(tmpAddDataList) > 0 {
+			_, err = to.InsertMulti(len(tmpAddDataList), tmpAddDataList)
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	//确定最终值
+	var finalLast EdbInfoSearchData
+	sql = ` SELECT data_time , value FROM edb_data_predict_calculate_nhcc WHERE edb_info_id=? and data_time<=? ORDER BY data_time DESC `
+	tmpErr := to.Raw(sql, edbInfo.EdbInfoId, latestDateStr).QueryRow(&finalLast)
+	if tmpErr != nil {
+		if tmpErr.Error() != utils.ErrNoRow() {
+			err = tmpErr
+		}
+		return
+	}else{
+		latestDateStr = finalLast.DataTime
+		latestValue = finalLast.Value
+	}
+	return
+}

+ 2 - 0
models/predict_edb_data_calculate_nszydbpjjs.go

@@ -112,6 +112,8 @@ func SavePredictCalculateNszydpjjs(reqEdbInfoId, classifyId int, edbName, freque
 			err = errors.New(errMsg)
 			return
 		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
 		oldCalculateFormula := edbInfo.CalculateFormula //原先的n值
 
 		edbInfo.EdbName = edbName

+ 35 - 0
models/predict_edb_data_calculate_tbz.go

@@ -105,6 +105,41 @@ func SavePredictCalculateTbz(reqEdbInfoId, classifyId int, edbName, frequency, u
 			err = errors.New(errMsg)
 			return
 		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		//修改指标信息
+		edbInfo.EdbName = edbName
+		edbInfo.EdbNameSource = edbName
+		edbInfo.Frequency = frequency
+		edbInfo.Unit = unit
+		edbInfo.ClassifyId = classifyId
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//判断计算指标是否被更换
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, fromEdbInfo.EdbInfoId)
+
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 { // 指标未被替换,无需重新计算
+			return
+		}
+		//删除,计算指标关联的,基础指标的关联关系
+		sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
 
 		// 删除该指标所有的同比数据
 		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_PREDICT_CALCULATE_TBZ)

+ 37 - 0
models/predict_edb_data_calculate_tcz.go

@@ -105,6 +105,43 @@ func SavePredictCalculateTcz(reqEdbInfoId, classifyId int, edbName, frequency, u
 			err = errors.New(errMsg)
 			return
 		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		//修改指标信息
+		edbInfo.EdbName = edbName
+		edbInfo.EdbNameSource = edbName
+		edbInfo.Frequency = frequency
+		edbInfo.Unit = unit
+		edbInfo.ClassifyId = classifyId
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, fromEdbInfo.EdbInfoId)
+
+		//判断计算指标是否被更换
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+		if count > 0 { // 指标未被替换,无需重新计算
+			return
+		}
+
+		//删除,计算指标关联的,基础指标的关联关系
+		sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+		_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+
 
 		// 删除该指标所有的同差数据
 		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_PREDICT_CALCULATE_TCZ)

+ 291 - 0
models/predict_edb_data_calculate_time_shift.go

@@ -0,0 +1,291 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SavePredictCalculateTimeShift 时间移位
+func SavePredictCalculateTimeShift(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateTimeShift,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.EdbInfoType = 1
+		edbInfo.Source = utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT
+		edbInfo.SourceName = "预测时间移位"
+		edbInfo.EdbCode = edbCode
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.SysUserId = sysUserId
+		edbInfo.SysUserRealName = sysUserRealName
+		edbInfo.CreateTime = time.Now()
+		edbInfo.ModifyTime = time.Now()
+		edbInfo.UniqueCode = uniqueCode
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.EdbType = 2
+		edbInfo.MoveType = req.MoveType
+		edbInfo.MoveFrequency = req.MoveFrequency
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//关联关系
+		{
+			calculateMappingItem := new(EdbInfoCalculateMapping)
+			calculateMappingItem.CreateTime = time.Now()
+			calculateMappingItem.ModifyTime = time.Now()
+			calculateMappingItem.Sort = 1
+			calculateMappingItem.EdbCode = edbCode
+			calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+			calculateMappingItem.FromEdbInfoId = fromEdbInfo.EdbInfoId
+			calculateMappingItem.FromEdbCode = fromEdbInfo.EdbCode
+			calculateMappingItem.FromEdbName = fromEdbInfo.EdbName
+			calculateMappingItem.FromSource = fromEdbInfo.Source
+			calculateMappingItem.FromSourceName = fromEdbInfo.SourceName
+			calculateMappingItem.FromTag = ""
+			calculateMappingItem.Source = edbInfo.Source
+			calculateMappingItem.SourceName = edbInfo.SourceName
+			_, err = to.Insert(calculateMappingItem)
+			if err != nil {
+				return
+			}
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+		oldEdbInfo := *edbInfo //旧的指标信息
+
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.MoveType = req.MoveType
+		edbInfo.MoveFrequency = req.MoveFrequency
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "MoveType", "MoveFrequency", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		//判断计算指标是否被更换
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? AND from_edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId, req.FromEdbInfoId)
+
+		var count int
+		count, err = GetEdbInfoCalculateCountByCondition(existCondition, existPars)
+		if err != nil {
+			err = errors.New("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+
+		if count <= 0 || req.MoveType != oldEdbInfo.MoveType || req.MoveFrequency != oldEdbInfo.MoveFrequency || req.Formula != oldEdbInfo.CalculateFormula {
+			//如果是依赖指标变更,那么需要删除对应的关联指标,并添加新的关系
+			if count <= 0 {
+				//删除,计算指标关联的,基础指标的关联关系
+				sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? `
+				_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+				if err != nil {
+					err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+					return
+				}
+				//关联关系
+				{
+					calculateMappingItem := &EdbInfoCalculateMapping{
+						EdbInfoCalculateMappingId: 0,
+						EdbInfoId:                 edbInfo.EdbInfoId,
+						Source:                    utils.DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT,
+						SourceName:                "预测时间移位",
+						EdbCode:                   edbInfo.EdbCode,
+						FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+						FromEdbCode:               fromEdbInfo.EdbCode,
+						FromEdbName:               fromEdbInfo.EdbName,
+						FromSource:                fromEdbInfo.Source,
+						FromSourceName:            fromEdbInfo.SourceName,
+						FromTag:                   "",
+						Sort:                      1,
+						CreateTime:                time.Now(),
+						ModifyTime:                time.Now(),
+					}
+					_, err = to.Insert(calculateMappingItem)
+					if err != nil {
+						return
+					}
+				}
+			}
+
+			//清空原有数据
+			sql := ` DELETE FROM edb_data_predict_calculate_time_shift WHERE edb_info_id = ? `
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				return
+			}
+		}else{
+			return
+		}
+	}
+
+	formulaInt, _ := strconv.Atoi(req.Formula)
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateTimeShift(to, edbInfo.EdbInfoId, edbInfo.Source, formulaInt, edbInfo.MoveType, fromEdbInfo, edbInfo.EdbCode, "", "", edbInfo.MoveFrequency)
+
+	return
+}
+
+// refreshAllPredictCalculateTimeShift 刷新所有时间移位数据
+func RefreshAllPredictCalculateTimeShift(edbInfoId, source, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("refreshAllPredictCalculateTimeShift,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//计算数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateTimeShift(to, edbInfoId, source, formulaInt, moveType, fromEdbInfo, edbCode, startDate, endDate, moveFrequency)
+	return
+}
+
+// refreshAllPredictCalculateTimeShift 刷新所有时间移位数据
+func refreshAllPredictCalculateTimeShift(to orm.TxOrmer, edbInfoId, source, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string) (latestDateStr string, latestValue float64, err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	dataList, err := GetPredictEdbDataListAllByStartDate(fromEdbInfo, 0, startDate)
+	if err != nil {
+		return
+	}
+	var shiftDay int
+	switch moveFrequency {
+	case "天":
+		shiftDay = formulaInt
+	case "周":
+		shiftDay = formulaInt * 7
+	case "月":
+		shiftDay = formulaInt * 30
+	case "季":
+		shiftDay = formulaInt * 90
+	case "年":
+		shiftDay = formulaInt * 365
+	default:
+		shiftDay = formulaInt
+	}
+
+	if moveType == 2 {
+		shiftDay = -shiftDay
+	}
+	latestDate, _ := time.Parse(utils.FormatDate, fromEdbInfo.LatestDate)
+	latestDateStr = latestDate.AddDate(0, 0, shiftDay).Format(utils.FormatDate)
+
+	var dateArr []string
+	dataMap := make(map[string]*EdbInfoSearchData)
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+	}
+
+	fmt.Println("source:", source)
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source)
+	fmt.Println("dataTableName:", dataTableName)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
+	if err != nil {
+		return
+	}
+	existDataMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v.Value
+	}
+	fmt.Println("existDataMap:", existDataMap)
+	addSql := ` INSERT INTO edb_data_predict_calculate_time_shift(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	existMap := make(map[string]string)
+	dataLen := len(dataList)
+	for i := 0; i < dataLen; i++ {
+		//当期
+		currentItem := dataList[i]
+		existKey := edbCode + currentItem.DataTime
+		if _, ok := existMap[existKey]; !ok {
+			currentDate, _ := time.Parse(utils.FormatDate, currentItem.DataTime)
+			newDate := currentDate.AddDate(0, 0, shiftDay)
+
+			timestamp := newDate.UnixNano() / 1e6
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			valStr := decimal.NewFromFloat(currentItem.Value).RoundCeil(4).String()
+			if latestDateStr == newDate.Format(utils.FormatDate) {
+				latestValue = currentItem.Value
+			}
+			if existVal, ok := existDataMap[newDate.Format(utils.FormatDate)]; !ok {
+				isAdd = true
+				addSql += GetAddSql(edbInfoIdStr, edbCode, newDate.Format(utils.FormatDate), timestampStr, valStr)
+			} else {
+				var existValDecimal decimal.Decimal
+				existValDecimal, err = decimal.NewFromString(existVal)
+				if err != nil {
+					return
+				}
+				existStr := existValDecimal.String()
+				if existStr != valStr {
+					sql = ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+					sql = fmt.Sprintf(sql, dataTableName)
+					_, err = to.Raw(sql, valStr, edbInfoId, newDate.Format(utils.FormatDate)).Exec()
+					if err != nil {
+						return
+					}
+				}
+			}
+		}
+		existMap[existKey] = currentItem.DataTime
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			return
+		}
+	}
+	return
+}

+ 503 - 0
models/predict_edb_data_calculate_zjpj.go

@@ -0,0 +1,503 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"hongze/hongze_edb_lib/utils"
+	"strings"
+	"time"
+)
+
+// EdbDataPredictCalculateZjpj 直接拼接数据结构体
+type EdbDataPredictCalculateZjpj struct {
+	EdbDataId     int `orm:"column(edb_data_id);pk"`
+	EdbInfoId     int
+	EdbCode       string
+	DataTime      string
+	Value         float64
+	Status        int
+	CreateTime    time.Time
+	ModifyTime    time.Time
+	DataTimestamp int64
+}
+
+// SavePredictCalculateZjpj 新增直接拼接数据
+func SavePredictCalculateZjpj(req *EdbInfoCalculateBatchSaveReq, firstEdbInfo, secondEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("SavePredictCalculateZjpj,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	if req.EdbInfoId <= 0 {
+		edbInfo = &EdbInfo{
+			EdbInfoType:      1,
+			SourceName:       "预测直接拼接",
+			Source:           utils.DATA_SOURCE_PREDICT_CALCULATE_ZJPJ,
+			EdbCode:          edbCode,
+			EdbName:          req.EdbName,
+			EdbNameSource:    req.EdbName,
+			Frequency:        req.Frequency,
+			Unit:             req.Unit,
+			StartDate:        firstEdbInfo.StartDate,
+			EndDate:          firstEdbInfo.EndDate,
+			ClassifyId:       req.ClassifyId,
+			SysUserId:        sysUserId,
+			SysUserRealName:  sysUserRealName,
+			UniqueCode:       uniqueCode,
+			CreateTime:       time.Now(),
+			ModifyTime:       time.Now(),
+			CalculateFormula: req.Formula,
+			EdbType:          2,
+		}
+		newEdbInfoId, tmpErr := to.Insert(edbInfo)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		edbInfo.EdbInfoId = int(newEdbInfoId)
+		//关联关系
+		//第一个指标
+		{
+			existItemA = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+				FromEdbCode:               firstEdbInfo.EdbCode,
+				FromEdbName:               firstEdbInfo.EdbName,
+				FromSource:                firstEdbInfo.Source,
+				FromSourceName:            firstEdbInfo.SourceName,
+				FromTag:                   "A",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemA)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemA.EdbInfoCalculateMappingId = int(insertId)
+		}
+
+		//第二个指标
+		{
+			existItemB = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+				FromEdbCode:               secondEdbInfo.EdbCode,
+				FromEdbName:               secondEdbInfo.EdbName,
+				FromSource:                secondEdbInfo.Source,
+				FromSourceName:            secondEdbInfo.SourceName,
+				FromTag:                   "B",
+				Sort:                      1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemB)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemB.EdbInfoCalculateMappingId = int(insertId)
+		}
+	} else {
+		edbInfo, err = GetEdbInfoById(req.EdbInfoId)
+		if err != nil {
+			return
+		}
+		latestDateStr = edbInfo.LatestDate
+		latestValue = edbInfo.LatestValue
+
+		nowEdbInfo := *edbInfo // 现在的指标信息
+
+		//修改指标信息
+		edbInfo.EdbName = req.EdbName
+		edbInfo.EdbNameSource = req.EdbName
+		edbInfo.Frequency = req.Frequency
+		edbInfo.Unit = req.Unit
+		edbInfo.ClassifyId = req.ClassifyId
+		edbInfo.CalculateFormula = req.Formula
+		edbInfo.ModifyTime = time.Now()
+		_, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
+		if err != nil {
+			return
+		}
+
+		var existCondition string
+		var existPars []interface{}
+		existCondition += " AND edb_info_id=? "
+		existPars = append(existPars, edbInfo.EdbInfoId)
+
+		//查询出所有的关联指标
+		var existList []*EdbInfoCalculateMapping
+		existList, err = GetEdbInfoCalculateListByCondition(existCondition, existPars)
+		if err != nil {
+			err = fmt.Errorf("判断指标是否改变失败,Err:" + err.Error())
+			return
+		}
+
+		for _, existItem := range existList {
+			if existItem.FromTag == "A" {
+				existItemA = existItem
+			} else if existItem.FromTag == "B" {
+				existItemB = existItem
+			}
+		}
+		if existItemA == nil {
+			err = errors.New("原拼接日期之前的指标不存在")
+			return
+		}
+		if existItemB == nil {
+			err = errors.New("原拼接日期之后的指标不存在")
+			return
+		}
+
+		// 是否需要删除数据重新计算
+		isNeedCalculateData := false
+
+		// 如果截止日期变更,那么需要重新计算
+		if req.Formula != nowEdbInfo.CalculateFormula {
+			isNeedCalculateData = true
+		}
+		//第一个指标数据
+		{
+			// 如果指标变了,那么需要删除关系,并重新计算
+			if existItemA.FromEdbInfoId != firstEdbInfo.EdbInfoId {
+				//删除之前的A指标关联关系
+				sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+				_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemA.FromEdbInfoId).Exec()
+				if err != nil {
+					err = fmt.Errorf("删除拼接日期之前的指标关联关系失败,Err:" + err.Error())
+					return
+				}
+			}
+		}
+
+		//第二个指标数据
+		{
+			// 如果指标变了,那么需要删除关系,并重新计算
+			if existItemB.FromEdbInfoId != secondEdbInfo.EdbInfoId {
+				//删除之前的B指标关联关系
+				sql := ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id = ? and from_edb_info_id = ?`
+				_, err = to.Raw(sql, edbInfo.EdbInfoId, existItemB.FromEdbInfoId).Exec()
+				if err != nil {
+					err = fmt.Errorf("删除拼接日期之后的指标关联关系失败,Err:" + err.Error())
+					return
+				}
+			}
+		}
+		if existItemA.FromEdbInfoId != firstEdbInfo.EdbInfoId {
+			//添加新的指标关系
+			{
+				existItemA = &EdbInfoCalculateMapping{
+					EdbInfoCalculateMappingId: 0,
+					EdbInfoId:                 edbInfo.EdbInfoId,
+					Source:                    edbInfo.Source,
+					SourceName:                edbInfo.SourceName,
+					EdbCode:                   edbInfo.EdbCode,
+					FromEdbInfoId:             firstEdbInfo.EdbInfoId,
+					FromEdbCode:               firstEdbInfo.EdbCode,
+					FromEdbName:               firstEdbInfo.EdbName,
+					FromSource:                firstEdbInfo.Source,
+					FromSourceName:            firstEdbInfo.SourceName,
+					FromTag:                   "A",
+					Sort:                      1,
+					CreateTime:                time.Now(),
+					ModifyTime:                time.Now(),
+				}
+				insertId, tmpErr := to.Insert(existItemA)
+				if tmpErr != nil {
+					err = tmpErr
+					return
+				}
+				existItemA.EdbInfoCalculateMappingId = int(insertId)
+
+				isNeedCalculateData = true
+			}
+		}
+
+		if existItemB.FromEdbInfoId != secondEdbInfo.EdbInfoId {
+			// 添加新的指标关联关系
+			existItemB = &EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 edbInfo.EdbInfoId,
+				Source:                    edbInfo.Source,
+				SourceName:                edbInfo.SourceName,
+				EdbCode:                   edbInfo.EdbCode,
+				FromEdbInfoId:             secondEdbInfo.EdbInfoId,
+				FromEdbCode:               secondEdbInfo.EdbCode,
+				FromEdbName:               secondEdbInfo.EdbName,
+				FromSource:                secondEdbInfo.Source,
+				FromSourceName:            secondEdbInfo.SourceName,
+				FromTag:                   "B",
+				Sort:                      2,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			insertId, tmpErr := to.Insert(existItemB)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existItemB.EdbInfoCalculateMappingId = int(insertId)
+
+			isNeedCalculateData = true
+		}
+		// 如果需要重新计算,那么先删除所有的指标数据,然后再重新计算
+		if isNeedCalculateData {
+			// 删除之前所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? `, tableName)
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除历史数据失败,Err:" + err.Error())
+				return
+			}
+		}else{
+			return
+		}
+	}
+
+	//拼接数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateZjpj(to, edbInfo, firstEdbInfo, secondEdbInfo)
+
+	return
+}
+
+// RefreshAllPredictCalculateZjpj 刷新所有 直接拼接 数据
+func RefreshAllPredictCalculateZjpj(edbInfo *EdbInfo) (latestDateStr string, latestValue float64, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	defer func() {
+		if err != nil {
+			fmt.Println("refreshAllPredictCalculateZjpj,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	//查询关联指标信息
+	var existCondition string
+	var existPars []interface{}
+	existCondition += " AND edb_info_id=? "
+	existPars = append(existPars, edbInfo.EdbInfoId)
+	existList, err := GetEdbInfoCalculateListByCondition(existCondition, existPars)
+	if err != nil {
+		err = fmt.Errorf("判断指标是否改变失败,Err:" + err.Error())
+		return
+	}
+
+	var existItemA, existItemB *EdbInfoCalculateMapping
+	for _, existItem := range existList {
+		if existItem.FromTag == "A" {
+			existItemA = existItem
+		} else if existItem.FromTag == "B" {
+			existItemB = existItem
+		}
+	}
+	if existItemA == nil {
+		err = errors.New("原拼接日期之前的指标不存在")
+		return
+	}
+	if existItemB == nil {
+		err = errors.New("原拼接日期之后的指标不存在")
+		return
+	}
+
+	fromEdbInfo, err := GetEdbInfoById(existItemA.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+
+	secondEdbInfo, err := GetEdbInfoById(existItemB.FromEdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("GetEdbInfoById Err:" + err.Error())
+		return
+	}
+	// 刷新数据
+	latestDateStr, latestValue, err = refreshAllPredictCalculateZjpj(to, edbInfo, fromEdbInfo, secondEdbInfo)
+
+	return
+}
+
+// refreshAllPredictCalculateZjpj 刷新所有 直接拼接 数据
+func refreshAllPredictCalculateZjpj(to orm.TxOrmer, edbInfo, firstEdbInfo, secondEdbInfo *EdbInfo) (latestDateStr string, latestValue float64, err error) {
+	//查询当前指标现有的数据
+	var dataList []*EdbDataPredictCalculateZjpj
+	sql := ` SELECT * FROM edb_data_predict_calculate_zjpj WHERE edb_info_id=? ORDER BY data_time DESC `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).QueryRows(&dataList)
+	if err != nil {
+		return
+	}
+	if edbInfo.CalculateFormula <= secondEdbInfo.LatestDate {
+		latestDateStr = secondEdbInfo.LatestDate
+	}else{
+		if edbInfo.CalculateFormula >= firstEdbInfo.LatestDate {
+			latestDateStr = firstEdbInfo.LatestDate
+		}else {
+			latestDateStr = edbInfo.CalculateFormula
+		}
+	}
+	var dateArr []string
+	dataMap := make(map[string]*EdbDataPredictCalculateZjpj)
+	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
+	for _, v := range dataList {
+		dateArr = append(dateArr, v.DataTime)
+		dataMap[v.DataTime] = v
+		removeDataTimeMap[v.DataTime] = 1
+	}
+
+	addDataList := make([]*EdbDataPredictCalculateZjpj, 0)
+	//第一个指标
+	{
+		var firstDataList []*EdbInfoSearchData
+		firstDataList, err = GetPredictEdbDataListAllByStartDate(firstEdbInfo, 0, "")
+		if err != nil {
+			return
+		}
+
+		for _, v := range firstDataList {
+			if v.DataTime >= edbInfo.CalculateFormula {
+				continue
+			}
+			//校验待删除日期数据里面是否存在该元素,如果存在的话,那么移除该元素
+			if _, ok := removeDataTimeMap[v.DataTime]; ok {
+				delete(removeDataTimeMap, v.DataTime)
+			}
+			if latestDateStr == v.DataTime {
+				latestValue = v.Value
+			}
+			//时间戳
+			if edbData, ok := dataMap[v.DataTime]; ok {
+				if edbData.Value != v.Value {
+					//更新指标数据
+					edbData.Value = v.Value
+					_, _ = to.Update(edbData, "Value")
+				}
+			} else {
+				//时间戳
+				currentDate, _ := time.Parse(utils.FormatDate, v.DataTime)
+				timestamp := currentDate.UnixNano() / 1e6
+
+				edbDataZjpj := &EdbDataPredictCalculateZjpj{
+					EdbInfoId:     edbInfo.EdbInfoId,
+					EdbCode:       edbInfo.EdbCode,
+					DataTime:      v.DataTime,
+					Value:         v.Value,
+					Status:        1,
+					CreateTime:    time.Now(),
+					ModifyTime:    time.Now(),
+					DataTimestamp: timestamp,
+				}
+				addDataList = append(addDataList, edbDataZjpj)
+			}
+		}
+	}
+
+	//第二个指标
+	{
+		/*condition := ``
+		pars := make([]interface{}, 0)
+
+		condition += " AND data_time >= ? AND edb_info_id = ? "
+		pars = append(pars, edbInfo.CalculateFormula, existItemB.FromEdbInfoId)
+
+		//第二个指标的数据列表
+		secondDataList, tmpErr := GetEdbDataListAllByTo(to, condition, pars, existItemB.FromSource, 0)
+		if tmpErr != nil {
+			return tmpErr
+		}*/
+		var secondDataList []*EdbInfoSearchData
+		secondDataList, err = GetPredictEdbDataListAllByStartDate(secondEdbInfo, 0, edbInfo.CalculateFormula)
+		if err != nil {
+			return
+		}
+		for _, v := range secondDataList {
+			//校验待删除日期数据里面是否存在该元素,如果存在的话,那么移除该元素
+			if _, ok := removeDataTimeMap[v.DataTime]; ok {
+				delete(removeDataTimeMap, v.DataTime)
+			}
+			if latestDateStr == v.DataTime {
+				latestValue = v.Value
+			}
+			if edbData, ok := dataMap[v.DataTime]; ok {
+				if edbData.Value != v.Value {
+					//更新指标数据
+					edbData.Value = v.Value
+					edbData.ModifyTime = time.Now()
+					_, tmpErr := to.Update(edbData, "Value", "ModifyTime")
+					if tmpErr != nil {
+						fmt.Println("tmpErr:", tmpErr)
+						err = tmpErr
+						return
+					}
+				}
+			} else {
+				//时间戳
+				currentDate, _ := time.Parse(utils.FormatDate, v.DataTime)
+				timestamp := currentDate.UnixNano() / 1e6
+
+				edbDataZjpj := &EdbDataPredictCalculateZjpj{
+					EdbInfoId:     edbInfo.EdbInfoId,
+					EdbCode:       edbInfo.EdbCode,
+					DataTime:      v.DataTime,
+					Value:         v.Value,
+					Status:        1,
+					CreateTime:    time.Now(),
+					ModifyTime:    time.Now(),
+					DataTimestamp: timestamp,
+				}
+				addDataList = append(addDataList, edbDataZjpj)
+			}
+		}
+	}
+
+	//删除已经不存在的累计同比拼接指标数据(由于同比值当日的数据删除了)
+	{
+		removeDateList := make([]string, 0)
+		for dateTime := range removeDataTimeMap {
+			removeDateList = append(removeDateList, dateTime)
+		}
+		if len(removeDateList) > 0 {
+			removeDateStr := strings.Join(removeDateList, `","`)
+			removeDateStr = `"` + removeDateStr + `"`
+			//如果拼接指标变更了,那么需要删除所有的指标数据
+			tableName := GetEdbDataTableName(edbInfo.Source)
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (%s) `, tableName, removeDateStr)
+
+			_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+			if err != nil {
+				err = fmt.Errorf("删除不存在的直接拼接指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	//数据入库
+	if len(addDataList) > 0 {
+		_, tmpErr := to.InsertMulti(len(addDataList), addDataList)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+	return
+}

+ 9 - 0
utils/constants.go

@@ -70,6 +70,15 @@ const (
 	DATA_SOURCE_PREDICT_CALCULATE_NSZYDPJJS            //预测指标 - N数值移动平均计算 -> 39
 	DATA_SOURCE_CALCULATE_ADJUST                       //数据调整->40
 	DATA_SOURCE_SCI                                    //卓创数据(红桃三)->41
+	DATA_SOURCE_PREDICT_CALCULATE_LJZZY                //预测指标 - 累计值转月->42
+	DATA_SOURCE_PREDICT_CALCULATE_HBZ                  //预测指标 - 环比值->43
+	DATA_SOURCE_PREDICT_CALCULATE_HCZ                  //预测指标 - 环差值->44
+	DATA_SOURCE_PREDICT_CALCULATE_BP                   //预测指标 - 变频->45
+	DATA_SOURCE_PREDICT_CALCULATE_TIME_SHIFT           //预测指标 - 时间移位->46
+	DATA_SOURCE_PREDICT_CALCULATE_ZJPJ                 //预测指标 - 直接拼接->47
+	DATA_SOURCE_PREDICT_CALCULATE_LJZTBPJ              //预测指标 - 累计值同比拼接->48
+	DATA_SOURCE_PREDICT_CALCULATE_CJJX                 //预测指标 - 超季节性->49
+	DATA_SOURCE_PREDICT_CALCULATE_NHCC                 //预测指标 - 计算指标(拟合残差)->50
 )
 
 //基础数据初始化日期