Browse Source

fix:新增降频指标,将原来的变频指标变更为升频

Roc 2 years ago
parent
commit
dc7be1e0f3

+ 37 - 13
controllers/base_from_calculate.go

@@ -640,12 +640,7 @@ func (this *CalculateController) BatchSave() {
 		sourName = "环差值"
 		edbInfo, err = models.AddCalculateHcz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName, formulaInt)
 	case utils.DATA_SOURCE_CALCULATE_BP:
-		//if fromEdbInfo.Frequency == "日度" {
-		//	br.Msg = "日度指标,无法进行变频操作"
-		//	br.ErrMsg = "日度指标,无法进行变频操作:edbcode:" + fromEdbInfo.EdbCode
-		//	return
-		//}
-		sourName = "变频"
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_BP
 		edbInfo, err = models.AddCalculateBp(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	case utils.DATA_SOURCE_CALCULATE_TIME_SHIFT:
 		sourName = "时间移位"
@@ -736,8 +731,11 @@ func (this *CalculateController) BatchSave() {
 			br.Msg = "频度异常,不允许低频降频到高频"
 			return
 		}
-		sourName = "降频"
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_JP
 		edbInfo, err = models.AddCalculateJp(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_NH:
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_NH
+		edbInfo, err = models.AddCalculateNh(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -1002,7 +1000,7 @@ func (this *CalculateController) BatchEdit() {
 		sourName = "环差值"
 		err = models.EditCalculateHcz(edbInfo, &req, fromEdbInfo, formulaInt, edbInfo.CalculateFormula)
 	case utils.DATA_SOURCE_CALCULATE_BP:
-		sourName = "变频"
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_BP
 		err = models.EditCalculateBp(edbInfo, &req, fromEdbInfo)
 	case utils.DATA_SOURCE_CALCULATE_TIME_SHIFT:
 		sourName = "时间移位"
@@ -1092,8 +1090,15 @@ func (this *CalculateController) BatchEdit() {
 			br.Msg = "频度异常,不允许低频降频到高频"
 			return
 		}
-		sourName = "降频"
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_JP
 		err = models.EditCalculateJp(edbInfo, &req, fromEdbInfo)
+	case utils.DATA_SOURCE_CALCULATE_NH:
+		if !models.CheckFrequency(fromEdbInfo.Frequency, req.Frequency) {
+			br.Msg = "频度异常,不允许低频降频到高频"
+			return
+		}
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_NH
+		err = models.EditCalculateNh(edbInfo, &req, fromEdbInfo)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -1351,7 +1356,7 @@ func (this *CalculateController) Refresh() {
 			errMsg = "RefreshAllCalculateHcz Err:" + err.Error()
 			break
 		}
-	case utils.DATA_SOURCE_CALCULATE_BP: //刷新
+	case utils.DATA_SOURCE_CALCULATE_BP: //刷新
 		calculateTbz, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
 		if err != nil {
 			errMsg = "GetEdbInfoCalculateTbzDetail Err:" + err.Error()
@@ -1462,14 +1467,14 @@ func (this *CalculateController) Refresh() {
 			errMsg = "RefreshAllCalculateLjzzy Err:" + err.Error()
 			break
 		}
-	case utils.DATA_SOURCE_CALCULATE_JP: //刷新
-		calculateTbz, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+	case utils.DATA_SOURCE_CALCULATE_JP: //刷新
+		calculateMapping, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
 		if err != nil {
 			errMsg = "GetEdbInfoCalculateTbzDetail Err:" + err.Error()
 			break
 		}
 
-		fromEdbInfo, err := models.GetEdbInfoById(calculateTbz.FromEdbInfoId)
+		fromEdbInfo, err := models.GetEdbInfoById(calculateMapping.FromEdbInfoId)
 		if err != nil {
 			errMsg = "GetEdbInfoById Err:" + err.Error()
 			break
@@ -1481,6 +1486,25 @@ func (this *CalculateController) Refresh() {
 			errMsg = "RefreshAllCalculateBp Err:" + err.Error()
 			break
 		}
+	case utils.DATA_SOURCE_CALCULATE_NH: //刷新年化
+		calculateMapping, err := models.GetEdbInfoCalculateMappingDetail(edbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoCalculateTbzDetail Err:" + err.Error()
+			break
+		}
+
+		fromEdbInfo, err := models.GetEdbInfoById(calculateMapping.FromEdbInfoId)
+		if err != nil {
+			errMsg = "GetEdbInfoById Err:" + err.Error()
+			break
+		}
+		//startDate = edbInfo.StartDate
+		endDate = time.Now().Format(utils.FormatDate)
+		err = models.RefreshAllCalculateNh(edbInfoId, source, fromEdbInfo, edbInfo.EdbCode)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllCalculateBp Err:" + err.Error()
+			break
+		}
 	default:
 		br.Msg = "来源异常,请联系相关开发!"
 		br.ErrMsg = "来源异常,请联系相关开发"

+ 2 - 2
models/base_from_calculate.go

@@ -590,7 +590,7 @@ type EdbInfoCalculateBatchSaveReq struct {
 	ClassifyId       int    `description:"分类id"`
 	Formula          string `description:"N值/移动天数"`
 	FromEdbInfoId    int    `description:"计算来源指标id"`
-	Source           int    `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:频"`
+	Source           int    `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:频"`
 	CalculateFormula string `description:"计算公式"`
 	EdbInfoIdArr     []struct {
 		EdbInfoId int    `description:"指标id"`
@@ -611,7 +611,7 @@ type EdbInfoCalculateBatchEditReq struct {
 	Formula       string `description:"N值"`
 	EdbInfoId     int    `description:"编辑指标id"`
 	FromEdbInfoId int    `description:"计算来源指标id"`
-	Source        int    `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:频"`
+	Source        int    `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:频"`
 	MoveType      int    `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency string `description:"移动频度:天/周/月/季/年"`
 	EdbInfoIdArr  []struct {

+ 9 - 9
models/edb_data_calculate_bp.go

@@ -11,7 +11,7 @@ import (
 	"time"
 )
 
-// AddCalculateBp 
+// AddCalculateBp 
 func AddCalculateBp(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
@@ -29,7 +29,7 @@ func AddCalculateBp(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edb
 	if req.EdbInfoId <= 0 {
 		edbInfo = new(EdbInfo)
 		edbInfo.Source = utils.DATA_SOURCE_CALCULATE_BP
-		edbInfo.SourceName = "变频"
+		edbInfo.SourceName = utils.DATA_SOURCE_NAME_CALCULATE_BP
 		edbInfo.EdbCode = edbCode
 		edbInfo.EdbName = req.EdbName
 		edbInfo.EdbNameSource = req.EdbName
@@ -91,7 +91,7 @@ func AddCalculateBp(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edb
 	return
 }
 
-// EditCalculateBp 修改频数据
+// EditCalculateBp 修改频数据
 func EditCalculateBp(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEdbInfo *EdbInfo) (err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
@@ -153,7 +153,7 @@ func EditCalculateBp(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEd
 			EdbInfoCalculateMappingId: 0,
 			EdbInfoId:                 edbInfo.EdbInfoId,
 			Source:                    utils.DATA_SOURCE_CALCULATE_BP,
-			SourceName:                "变频",
+			SourceName:                utils.DATA_SOURCE_NAME_CALCULATE_BP,
 			EdbCode:                   edbInfo.EdbCode,
 			FromEdbInfoId:             fromEdbInfo.EdbInfoId,
 			FromEdbCode:               fromEdbInfo.EdbCode,
@@ -177,7 +177,7 @@ func EditCalculateBp(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEd
 	return
 }
 
-// RefreshAllCalculateBpBak 刷新所有频数据
+// RefreshAllCalculateBpBak 刷新所有频数据
 func RefreshAllCalculateBpBak(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrm()
 	to, err := o.Begin()
@@ -339,7 +339,7 @@ func RefreshAllCalculateBp(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode,
 	return
 }
 
-// refreshAllCalculateBp 刷新频数据
+// refreshAllCalculateBp 刷新频数据
 func refreshAllCalculateBp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate string, order int) (err error) {
 	edbInfoIdStr := strconv.Itoa(edbInfoId)
 
@@ -373,7 +373,7 @@ func refreshAllCalculateBp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 	}
 	fmt.Println("source:", source)
 
-	//获取频指标所有数据
+	//获取频指标所有数据
 	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source)
 	if err != nil {
 		return
@@ -474,7 +474,7 @@ func refreshAllCalculateBp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 			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())
+				err = fmt.Errorf("删除所有的频指标数据失败,Err:" + err.Error())
 				return
 			}
 
@@ -541,7 +541,7 @@ func refreshAllCalculateBp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 
 		_, err = to.Raw(sql, edbInfoId).Exec()
 		if err != nil {
-			err = fmt.Errorf("删除不存在的频指标数据失败,Err:" + err.Error())
+			err = fmt.Errorf("删除不存在的频指标数据失败,Err:" + err.Error())
 			return
 		}
 	}

+ 7 - 7
models/edb_data_calculate_jp.go

@@ -56,7 +56,7 @@ func AddCalculateJp(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edb
 	if req.EdbInfoId <= 0 {
 		edbInfo = new(EdbInfo)
 		edbInfo.Source = utils.DATA_SOURCE_CALCULATE_JP
-		edbInfo.SourceName = "降频"
+		edbInfo.SourceName = utils.DATA_SOURCE_NAME_CALCULATE_JP
 		edbInfo.EdbCode = edbCode
 		edbInfo.EdbName = req.EdbName
 		edbInfo.EdbNameSource = req.EdbName
@@ -182,7 +182,7 @@ func EditCalculateJp(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEd
 			EdbInfoCalculateMappingId: 0,
 			EdbInfoId:                 edbInfo.EdbInfoId,
 			Source:                    utils.DATA_SOURCE_CALCULATE_JP,
-			SourceName:                "降频",
+			SourceName:                utils.DATA_SOURCE_NAME_CALCULATE_JP,
 			EdbCode:                   edbInfo.EdbCode,
 			FromEdbInfoId:             fromEdbInfo.EdbInfoId,
 			FromEdbCode:               fromEdbInfo.EdbCode,
@@ -292,7 +292,7 @@ func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 		// 将当前数据加入到 weekDayDataList
 		if tmpData, ok := dataMap[tmpStartDataTime.Format(utils.FormatDate)]; ok {
 			tmpValue := decimal.NewFromFloat(tmpData.Value)
-			tmpValueFloat, _ := tmpValue.Truncate(4).Float64()
+			tmpValueFloat, _ := tmpValue.Round(4).Float64()
 			weekDayDataList = append(weekDayDataList, tmpValueFloat)
 		}
 		// 如果下个节点的日期不存在,那么就先给赋值(兼容时间区间内只有一组数据的情况)
@@ -373,7 +373,7 @@ func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 					sumValDeci = sumValDeci.Add(tmpValDeci)
 				}
 				lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
-				currVal, _ = sumValDeci.Div(lenDeci).Truncate(4).Float64()
+				currVal, _ = sumValDeci.Div(lenDeci).Round(4).Float64()
 			}
 		}
 
@@ -386,7 +386,7 @@ func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 				err = tmpErr
 				return
 			}
-			existVal, _ := existValDeci.Truncate(4).Float64()
+			existVal, _ := existValDeci.Round(4).Float64()
 			// 判断降频数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
 			if existVal != currVal {
 				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))
@@ -425,7 +425,7 @@ func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 					sumValDeci = sumValDeci.Add(tmpValDeci)
 				}
 				lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
-				currVal, _ = sumValDeci.Div(lenDeci).Truncate(4).Float64()
+				currVal, _ = sumValDeci.Div(lenDeci).Round(4).Float64()
 			}
 		}
 
@@ -438,7 +438,7 @@ func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 				err = tmpErr
 				return
 			}
-			existVal, _ := existValDeci.Truncate(4).Float64()
+			existVal, _ := existValDeci.Round(4).Float64()
 			// 判断降频数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
 			if existVal != currVal {
 				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))

+ 432 - 0
models/edb_data_calculate_nh.go

@@ -0,0 +1,432 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// AddCalculateNh 年化
+func AddCalculateNh(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbInfo, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateNh,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.Source = utils.DATA_SOURCE_CALCULATE_NH
+		edbInfo.SourceName = utils.DATA_SOURCE_NAME_CALCULATE_NH
+		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
+		}
+		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_NH)
+		fmt.Println("dataTableName:" + dataTableName)
+		deleteSql := ` DELETE FROM %s WHERE edb_info_id=? `
+		deleteSql = fmt.Sprintf(deleteSql, dataTableName)
+		_, err = to.Raw(deleteSql, req.EdbInfoId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//计算数据
+	err = refreshAllCalculateNh(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode)
+
+	return
+}
+
+// EditCalculateNh 修改年化数据
+func EditCalculateNh(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq, fromEdbInfo *EdbInfo) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateNh,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//修改指标信息
+	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)
+
+	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 {
+		err = errors.New("删除计算指标关联关系失败,Err:" + err.Error())
+		return
+	}
+	//清空原有数据
+	tableName := GetEdbDataTableName(edbInfo.Source)
+	sql = ` DELETE FROM ` + tableName + ` 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_CALCULATE_NH,
+			SourceName:                utils.DATA_SOURCE_NAME_CALCULATE_NH,
+			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
+		}
+	}
+
+	//计算数据
+	err = refreshAllCalculateNh(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode)
+
+	return
+}
+
+func RefreshAllCalculateNh(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode string) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateNh,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err = refreshAllCalculateNh(to, edbInfoId, source, fromEdbInfo, edbCode)
+
+	return
+}
+
+// refreshAllCalculateNh 刷新年化数据
+func refreshAllCalculateNh(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode string) (err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_NH)
+
+	//获取年化指标所有数据
+	existDataList, err := GetAllEdbDataListByTo(to, edbInfoId, source)
+	if err != nil {
+		return
+	}
+	//计算指标的map
+	existDataMap := make(map[string]*EdbData, 0)
+	removeDateMap := make(map[string]string)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v
+		removeDateMap[v.DataTime] = ``
+	}
+
+	//计算数据
+	var condition string
+	var pars []interface{}
+	condition += " AND edb_info_id=? "
+	pars = append(pars, fromEdbInfo.EdbInfoId)
+
+	//获取来源指标的数据
+	fromDataList, err := GetEdbDataListAllByTo(to, condition, pars, fromEdbInfo.Source, 1)
+	if err != nil {
+		return err
+	}
+
+	// 插值法数据处理
+	handleDataMap := make(map[string]float64)
+	err = handleDataByLinearRegression(fromDataList, handleDataMap)
+	if err != nil {
+		return
+	}
+
+	lenFromDataList := len(fromDataList)
+	// 如果来源指标没有数据,那么就直接返回得了
+	if lenFromDataList <= 0 {
+		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
+		}
+		return
+	}
+	// 每年的最后一天的数据值
+	yearLastValMap := make(map[int]float64)
+	startDataTime, _ := time.ParseInLocation(utils.FormatDate, fromDataList[0].DataTime, time.Local)
+	endDataTime, _ := time.ParseInLocation(utils.FormatDate, fromDataList[lenFromDataList-1].DataTime, time.Local)
+	for i := startDataTime.Year(); i <= endDataTime.Year(); i++ {
+		tmpDateStr := fmt.Sprintf("%d-12-31", i)
+		if tmpVal, ok := handleDataMap[tmpDateStr]; ok {
+			yearLastValMap[i] = tmpVal
+		}
+	}
+
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+	//来源指指标数据
+	for _, v := range fromDataList {
+		currDateStr := v.DataTime
+		currDate, _ := time.ParseInLocation(utils.FormatDate, currDateStr, time.Local)
+
+		perValMap := make(map[time.Time]float64)
+		//前3年当日的数据
+		for i := 1; i <= 3; i++ {
+			tmpDateTime := currDate.AddDate(-i, 0, 0)
+			if tmpVal, ok := handleDataMap[tmpDateTime.Format(utils.FormatDate)]; ok {
+				perValMap[tmpDateTime] = tmpVal
+			}
+		}
+		lenPerValMap := len(perValMap)
+		// 如果数据少于2年,那么就不参与计算,结束当前循环,进入下一个循环
+		if lenPerValMap < 2 {
+			continue
+		}
+
+		// N年 当前值占全年比重 的值列表
+		divValList := make([]decimal.Decimal, 0)
+		for tmpDateTime, tmpVal := range perValMap {
+			yearLastVal, ok2 := yearLastValMap[tmpDateTime.Year()]
+			// 如果当年最后一天没有数据
+			if !ok2 {
+				continue
+			}
+
+			// 当前值占全年比重
+			divVal := decimal.NewFromFloat(tmpVal).Div(decimal.NewFromFloat(yearLastVal))
+			divValList = append(divValList, divVal)
+		}
+
+		lenDivValList := len(divValList)
+		// 如果 N年 当前值占全年比重 的值 小于 2个,那么就不参与计算,结束当前循环,进入下一个循环
+		if lenDivValList < 2 {
+			continue
+		}
+
+		divValSum := decimal.NewFromFloat(0)
+		for _, divVal := range divValList {
+			divValSum = divValSum.Add(divVal)
+		}
+
+		// 当前计算出来的结果
+		currVal, _ := decimal.NewFromFloat(v.Value).Div(divValSum.Div(decimal.NewFromInt(int64(lenDivValList)))).Round(4).Float64()
+
+		// 判断年化指标是否存在数据
+		if existData, ok := existDataMap[currDateStr]; ok {
+			// 处理年化数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Round(4).Float64()
+			// 判断年化数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := currDate.UnixNano() / 1e6
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, currDateStr, timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+
+		delete(removeDateMap, currDateStr)
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+	}
+
+	// 移除不存在的日期数据
+	if len(removeDateMap) > 0 {
+		removeDateList := make([]string, 0) //需要移除的日期
+		for k := range removeDateMap {
+			removeDateList = append(removeDateList, k)
+		}
+		removeDateStr := strings.Join(removeDateList, `","`)
+		removeDateStr = `"` + removeDateStr + `"`
+		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
+}
+
+// handleDataByLinearRegression 插值法补充数据(线性方程式)
+func handleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (err error) {
+	if len(edbInfoDataList) < 2 {
+		return
+	}
+
+	var startEdbInfoData *EdbInfoSearchData
+	for _, v := range edbInfoDataList {
+		handleDataMap[v.DataTime] = v.Value
+
+		// 第一个数据就给过滤了,给后面的试用
+		if startEdbInfoData == nil {
+			startEdbInfoData = v
+			continue
+		}
+
+		// 获取两条数据之间相差的天数
+		startDataTime, _ := time.ParseInLocation(utils.FormatDate, startEdbInfoData.DataTime, time.Local)
+		currDataTime, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+		betweenHour := int(currDataTime.Sub(startDataTime).Hours())
+		betweenDay := betweenHour / 24
+
+		// 如果相差一天,那么过滤
+		if betweenDay <= 1 {
+			startEdbInfoData = v
+			continue
+		}
+
+		// 生成线性方程式
+		var a, b float64
+		{
+			coordinateData := make([]utils.Coordinate, 0)
+			tmpCoordinate1 := utils.Coordinate{
+				X: 1,
+				Y: startEdbInfoData.Value,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate1)
+			tmpCoordinate2 := utils.Coordinate{
+				X: float64(betweenDay) + 1,
+				Y: v.Value,
+			}
+			coordinateData = append(coordinateData, tmpCoordinate2)
+
+			a, b = utils.GetLinearResult(coordinateData)
+			if math.IsNaN(a) || math.IsNaN(b) {
+				err = errors.New("线性方程公式生成失败")
+				return
+			}
+		}
+
+		// 生成对应的值
+		{
+			for i := 1; i < betweenDay; i++ {
+				tmpDataTime := startDataTime.AddDate(0, 0, i)
+				aDecimal := decimal.NewFromFloat(a)
+				xDecimal := decimal.NewFromInt(int64(i) + 1)
+				bDecimal := decimal.NewFromFloat(b)
+
+				val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
+				handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
+			}
+		}
+
+		startEdbInfoData = v
+	}
+
+	return
+}

+ 1 - 1
models/edb_data_calculate_nhcc.go

@@ -668,7 +668,7 @@ func handleNhccData(dataList []*EdbInfoSearchData, moveDay int) (newDataList []E
 	minDate = minDate.AddDate(0, 0, moveDay)
 	maxDate = maxDate.AddDate(0, 0, moveDay)
 
-	// 开始
+	// 开始
 	dayNum := utils.GetTimeSubDay(minDate, maxDate)
 
 	for i := 0; i <= dayNum; i++ {

+ 2 - 0
models/edb_data_table.go

@@ -87,6 +87,8 @@ func GetEdbDataTableName(source int) (tableName string) {
 		tableName = "edb_data_sci"
 	case utils.DATA_SOURCE_CALCULATE_JP:
 		tableName = "edb_data_calculate_jp"
+	case utils.DATA_SOURCE_CALCULATE_NH:
+		tableName = "edb_data_calculate_nh"
 	default:
 		tableName = ""
 	}

+ 45 - 0
utils/calculate.go

@@ -0,0 +1,45 @@
+package utils
+
+// Series is a container for a series of data
+type Series []Coordinate
+
+// Coordinate holds the data in a series
+type Coordinate struct {
+	X, Y float64
+}
+
+// GetLinearResult 生成线性方程式
+func GetLinearResult(s []Coordinate) (gradient, intercept float64) {
+	if len(s) <= 1 {
+		return
+	}
+
+	// Placeholder for the math to be done
+	var sum [5]float64
+
+	// Loop over data keeping index in place
+	i := 0
+	for ; i < len(s); i++ {
+		sum[0] += s[i].X
+		sum[1] += s[i].Y
+		sum[2] += s[i].X * s[i].X
+		sum[3] += s[i].X * s[i].Y
+		sum[4] += s[i].Y * s[i].Y
+	}
+
+	// Find gradient and intercept
+	f := float64(i)
+	gradient = (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
+	intercept = (sum[1] / f) - (gradient * sum[0] / f)
+
+	//fmt.Println("gradient:", gradient, ";intercept:", intercept)
+	// Create the new regression series
+	//for j := 0; j < len(s); j++ {
+	//	regressions = append(regressions, Coordinate{
+	//		X: s[j].X,
+	//		Y: s[j].X*gradient + intercept,
+	//	})
+	//}
+
+	return
+}

+ 60 - 3
utils/constants.go

@@ -42,7 +42,7 @@ const (
 	DATA_SOURCE_YS                                      //有色
 	DATA_SOURCE_CALCULATE_HBZ                           //环比值->12
 	DATA_SOURCE_CALCULATE_HCZ                           //环差值->13
-	DATA_SOURCE_CALCULATE_BP                            //变频->14
+	DATA_SOURCE_CALCULATE_BP                            //变频,2023-2-10 13:56:01调整为"升频"->14
 	DATA_SOURCE_GL                                      //钢联->15
 	DATA_SOURCE_ZZ                                      //郑商所->16
 	DATA_SOURCE_DL                                      //大商所->17
@@ -73,13 +73,70 @@ const (
 	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_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
-	DATA_SOURCE_CALCULATE_JP                            //变频->51
+	DATA_SOURCE_CALCULATE_JP                            //降频->51
+	DATA_SOURCE_CALCULATE_NH                            //年化->52
+)
+
+// 指标来源的中文展示
+const (
+	DATA_SOURCE_NAME_THS                          = `同花顺`               //同花顺
+	DATA_SOURCE_NAME_WIND                         = `wind`              //wind
+	DATA_SOURCE_NAME_PB                           = `彭博`                //彭博
+	DATA_SOURCE_NAME_CALCULATE                    = `指标运算`              //指标运算
+	DATA_SOURCE_NAME_CALCULATE_LJZZY              = `累计值转月值`            //累计值转月
+	DATA_SOURCE_NAME_CALCULATE_TBZ                = `同比值`               //同比值
+	DATA_SOURCE_NAME_CALCULATE_TCZ                = `同差值`               //同差值
+	DATA_SOURCE_NAME_CALCULATE_NSZYDPJJS          = `N数值移动平均计算`         //N数值移动平均计算
+	DATA_SOURCE_NAME_MANUAL                       = `手工数据`              //手工指标
+	DATA_SOURCE_NAME_LZ                           = `隆众`                //隆众
+	DATA_SOURCE_NAME_YS                           = `SMM`               //有色
+	DATA_SOURCE_NAME_CALCULATE_HBZ                = `环比值`               //环比值->12
+	DATA_SOURCE_NAME_CALCULATE_HCZ                = `环差值`               //环差值->13
+	DATA_SOURCE_NAME_CALCULATE_BP                 = `升频`                //变频,2023-2-10 13:56:01调整为"升频"->14
+	DATA_SOURCE_NAME_GL                           = `钢联`                //钢联->15
+	DATA_SOURCE_NAME_ZZ                           = `郑商所`               //郑商所->16
+	DATA_SOURCE_NAME_DL                           = `大商所`               //大商所->17
+	DATA_SOURCE_NAME_SH                           = `上期所`               //上期所->18
+	DATA_SOURCE_NAME_CFFEX                        = `中金所`               //中金所->19
+	DATA_SOURCE_NAME_SHFE                         = `上期能源`              //上期能源->20
+	DATA_SOURCE_NAME_GIE                          = `欧洲天然气`             //欧洲天然气->21
+	DATA_SOURCE_NAME_CALCULATE_TIME_SHIFT         = `时间移位`              //时间移位->22
+	DATA_SOURCE_NAME_CALCULATE_ZJPJ               = `直接拼接`              //直接拼接->23
+	DATA_SOURCE_NAME_CALCULATE_LJZTBPJ            = `累计值同比拼接`           //累计值同比拼接->24
+	DATA_SOURCE_NAME_LT                           = `路透`                //路透->25
+	DATA_SOURCE_NAME_COAL                         = `中国煤炭网`             //煤炭网->26
+	DATA_SOURCE_NAME_PYTHON                       = `代码运算`              //python代码->27
+	DATA_SOURCE_NAME_PB_FINANCE                   = `彭博财务`              //彭博财务数据->28
+	DATA_SOURCE_NAME_GOOGLE_TRAVEL                = `our world in data` //谷歌出行数据->29
+	DATA_SOURCE_NAME_PREDICT                      = `预测指标`              //普通预测指标->30
+	DATA_SOURCE_NAME_PREDICT_CALCULATE            = `预测指标运算`            //预测指标运算->31
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_TBZ        = `预测同比`              //预测指标 - 同比值->32
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_TCZ        = `预测同差`              //预测指标 - 同差值->33
+	DATA_SOURCE_NAME_MYSTEEL_CHEMICAL             = `钢联化工`              //钢联化工->34
+	DATA_SOURCE_NAME_CALCULATE_CJJX               = `超季节性`              //超季节性->35
+	DATA_SOURCE_NAME_EIA_STEO                     = `EIA STERO报告`       //eia stero报告->36
+	DATA_SOURCE_NAME_CALCULATE_NHCC               = `拟合残差`              //计算指标(拟合残差)->37
+	DATA_SOURCE_NAME_COM_TRADE                    = `UN`                //联合国商品贸易数据->38
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_NSZYDPJJS  = `预测N数值移动平均计算`       //预测指标 - N数值移动平均计算 -> 39
+	DATA_SOURCE_NAME_CALCULATE_ADJUST             = `数据调整`              //数据调整->40
+	DATA_SOURCE_NAME_SCI                          = `SCI`               //卓创数据(红桃三)->41
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_LJZZY      = `预测累计值转月值`          //预测指标 - 累计值转月->42
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_HBZ        = `预测环比值`             //预测指标 - 环比值->43
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_HCZ        = `预测环差值`             //预测指标 - 环差值->44
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_BP         = `预测升频`              //预测指标 - 升频->45
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_TIME_SHIFT = `预测时间移位`            //预测指标 - 时间移位->46
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_ZJPJ       = `预测直接拼接`            //预测指标 - 直接拼接->47
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_LJZTBPJ    = `预测累计值同比拼接`         //预测指标 - 累计值同比拼接->48
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_CJJX       = `预测超季节性`            //预测指标 - 超季节性->49
+	DATA_SOURCE_NAME_PREDICT_CALCULATE_NHCC       = `预测拟合残差`            //预测指标 - 计算指标(拟合残差)->50
+	DATA_SOURCE_NAME_CALCULATE_JP                 = `降频`                //降频->51
+	DATA_SOURCE_NAME_CALCULATE_NH                 = `年化`                //年化->52
 )
 
 // 基础数据初始化日期