Browse Source

Merge branch 'chart/13.8' into debug

# Conflicts:
#	models/edb_data_table.go
#	utils/constants.go
Roc 2 năm trước cách đây
mục cha
commit
9999ec1ab1

+ 34 - 5
controllers/base_from_calculate.go

@@ -543,7 +543,7 @@ func (this *CalculateController) BatchSave() {
 		}
 	}
 
-	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS} // 不需要传入来源指标id的 指标类型
+	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS, utils.DATA_SOURCE_CALCULATE_CORRELATION} // 不需要传入来源指标id的 指标类型
 	if fromEdbInfoId <= 0 && !utils.InArrayByInt(notNeedFromEdbSourceList, req.Source) {
 		br.Msg = "请选择指标"
 		return
@@ -605,6 +605,7 @@ func (this *CalculateController) BatchSave() {
 	var sourName string
 	var edbInfoId int
 	var edbInfo *models.EdbInfo
+	var errMsg string
 	switch req.Source {
 	case utils.DATA_SOURCE_CALCULATE_LJZZY:
 		sourName = "累计值转月值"
@@ -767,6 +768,16 @@ func (this *CalculateController) BatchSave() {
 		}
 		sourName = utils.DATA_SOURCE_NAME_CALCULATE_KSZS
 		edbInfo, err = models.AddCalculateKszs(&req, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_CORRELATION:
+		//关联的指标信息
+		if len(req.EdbInfoIdArr) < 2 {
+			br.Msg = "指标数量不能小于2个,请重新选择"
+			br.ErrMsg = "指标数量不能小于2个,请重新选择"
+			br.IsSendEmail = false
+			return
+		}
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+		edbInfo, err, errMsg = models.AddCalculateCorrelation(&req, edbCode, uniqueCode, sysUserId, sysUserName)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -774,7 +785,10 @@ func (this *CalculateController) BatchSave() {
 	}
 	if err != nil {
 		br.Msg = "生成" + sourName + "失败"
-		br.Msg = "生成" + sourName + "失败 Err:" + err.Error()
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "生成" + sourName + "失败 Err:" + err.Error()
 		return
 	}
 
@@ -807,7 +821,7 @@ func (this *CalculateController) BatchSave() {
 	}
 
 	// 更新指标最大最小值
-	err, errMsg := models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	err, errMsg = models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = err.Error()
@@ -989,7 +1003,7 @@ func (this *CalculateController) BatchEdit() {
 		}
 	}
 
-	var sourName string
+	var sourName, errMsg string
 	var edbInfoId int
 
 	switch req.Source {
@@ -1143,6 +1157,16 @@ func (this *CalculateController) BatchEdit() {
 		}
 		sourName = utils.DATA_SOURCE_NAME_CALCULATE_KSZS
 		err = models.EditCalculateKszs(edbInfo, &req)
+	case utils.DATA_SOURCE_CALCULATE_CORRELATION:
+		//关联的指标信息
+		if len(req.EdbInfoIdArr) < 2 {
+			br.Msg = "指标数量不能小于2个,请重新选择"
+			br.ErrMsg = "指标数量不能小于2个,请重新选择"
+			br.IsSendEmail = false
+			return
+		}
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+		err, errMsg = models.EditCalculateCorrelation(edbInfo, &req)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -1151,6 +1175,9 @@ func (this *CalculateController) BatchEdit() {
 	}
 	if err != nil {
 		br.Msg = "生成" + sourName + "失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
 		br.Msg = "生成" + sourName + "失败 Err:" + err.Error()
 		return
 	}
@@ -1183,7 +1210,7 @@ func (this *CalculateController) BatchEdit() {
 	}
 
 	// 更新指标最大最小值
-	err, errMsg := models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	err, errMsg = models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
 	if err != nil {
 		br.Msg = errMsg
 		br.ErrMsg = err.Error()
@@ -1557,6 +1584,8 @@ func (this *CalculateController) Refresh() {
 			errMsg = "RefreshAllCalculateKszs Err:" + err.Error()
 			break
 		}
+	case utils.DATA_SOURCE_CALCULATE_CORRELATION:
+		err, errMsg = models.RefreshAllCalculateCorrelation(edbInfo)
 	default:
 		br.Msg = "来源异常,请联系相关开发!"
 		br.ErrMsg = "来源异常,请联系相关开发"

+ 1 - 1
models/edb_data_calculate_cjjx.go

@@ -254,7 +254,7 @@ func refreshAllCalculateCjjx(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo
 
 	// 通过插值法补全所有数据(包含周末)
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(dataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(dataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 532 - 0
models/edb_data_calculate_correlation.go

@@ -0,0 +1,532 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// AddCalculateCorrelation 扩散指数
+func AddCalculateCorrelation(req *EdbInfoCalculateBatchSaveReq, edbCode, uniqueCode string, sysUserId int, sysUserRealName string) (edbInfo *EdbInfo, err error, errMsg string) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateCorrelation,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId > 0 {
+		err = errors.New("无法新增")
+		return
+	}
+
+	edbInfo = new(EdbInfo)
+	edbInfo.Source = utils.DATA_SOURCE_CALCULATE_CORRELATION
+	edbInfo.SourceName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+	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)
+
+	var edbInfoA, edbInfoB *EdbInfo
+	//关联关系
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if v.FromTag == `A` {
+			edbInfoA = tmpEdbInfo
+		}
+		if v.FromTag == `B` {
+			edbInfoB = tmpEdbInfo
+		}
+
+		calculateMappingItem := new(EdbInfoCalculateMapping)
+		calculateMappingItem.CreateTime = time.Now()
+		calculateMappingItem.ModifyTime = time.Now()
+		calculateMappingItem.Sort = 1
+		calculateMappingItem.EdbCode = edbCode
+		calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+		calculateMappingItem.FromEdbInfoId = tmpEdbInfo.EdbInfoId
+		calculateMappingItem.FromEdbCode = tmpEdbInfo.EdbCode
+		calculateMappingItem.FromEdbName = tmpEdbInfo.EdbName
+		calculateMappingItem.FromSource = tmpEdbInfo.Source
+		calculateMappingItem.FromSourceName = tmpEdbInfo.SourceName
+		calculateMappingItem.FromTag = v.FromTag
+		calculateMappingItem.Source = edbInfo.Source
+		calculateMappingItem.SourceName = edbInfo.SourceName
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+	}
+
+	if edbInfoA == nil || edbInfoB == nil {
+		errMsg = "指标异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	if edbInfoA.EdbInfoId == edbInfoB.EdbInfoId {
+		errMsg = "两个指标不允许为同一个"
+		err = errors.New(errMsg)
+		return
+	}
+
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err, errMsg = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfoA, edbInfoB, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+// EditCalculateCorrelation 修改扩散指数数据
+func EditCalculateCorrelation(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq) (err error, errMsg string) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateCorrelation,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
+	}
+
+	//删除,计算指标关联的,基础指标的关联关系
+	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
+	}
+
+	var edbInfoA, edbInfoB *EdbInfo
+	//关联关系
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		if v.FromTag == `A` {
+			edbInfoA = tmpEdbInfo
+		}
+		if v.FromTag == `B` {
+			edbInfoB = tmpEdbInfo
+		}
+
+		calculateMappingItem := new(EdbInfoCalculateMapping)
+		calculateMappingItem.CreateTime = time.Now()
+		calculateMappingItem.ModifyTime = time.Now()
+		calculateMappingItem.Sort = 1
+		calculateMappingItem.EdbCode = edbInfo.EdbCode
+		calculateMappingItem.EdbInfoId = edbInfo.EdbInfoId
+		calculateMappingItem.FromEdbInfoId = tmpEdbInfo.EdbInfoId
+		calculateMappingItem.FromEdbCode = tmpEdbInfo.EdbCode
+		calculateMappingItem.FromEdbName = tmpEdbInfo.EdbName
+		calculateMappingItem.FromSource = tmpEdbInfo.Source
+		calculateMappingItem.FromSourceName = tmpEdbInfo.SourceName
+		calculateMappingItem.FromTag = v.FromTag
+		calculateMappingItem.Source = edbInfo.Source
+		calculateMappingItem.SourceName = edbInfo.SourceName
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+
+	}
+
+	if edbInfoA == nil || edbInfoB == nil {
+		errMsg = "指标异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	if edbInfoA.EdbInfoId == edbInfoB.EdbInfoId {
+		errMsg = "两个指标不允许为同一个"
+		err = errors.New(errMsg)
+		return
+	}
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err, errMsg = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfoA, edbInfoB, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+func RefreshAllCalculateCorrelation(edbInfo *EdbInfo) (err error, errMsg string) {
+	edbInfoCalculateDetailList, err := GetEdbInfoCalculateDetailList(edbInfo.EdbInfoId)
+	if err != nil {
+		return
+	}
+	var edbInfoA, edbInfoB *EdbInfo
+	for _, v := range edbInfoCalculateDetailList {
+		tmpEdbInfo, _ := GetEdbInfoById(v.FromEdbInfoId)
+		if v.FromTag == `A` {
+			edbInfoA = tmpEdbInfo
+		}
+		if v.FromTag == `B` {
+			edbInfoB = tmpEdbInfo
+		}
+	}
+
+	if edbInfoA == nil || edbInfoB == nil {
+		errMsg = "指标异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	if edbInfoA.EdbInfoId == edbInfoB.EdbInfoId {
+		errMsg = "两个指标不允许为同一个"
+		err = errors.New(errMsg)
+		return
+	}
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateCorrelation,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err, errMsg = refreshAllCalculateCorrelation(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfoA, edbInfoB, edbInfo.EdbCode, edbInfo.CalculateFormula)
+
+	return
+}
+
+// CorrelationConfig 扩散指数配置
+type CorrelationConfig struct {
+	DateType  int      `description:"扩散指标日期;1:全部指标日期并集;2:部分指标日期并集"`
+	CheckList []string `description:"选中的数据,A,B,C"`
+}
+
+type EdbCalculateFormula struct {
+	BaseCalculateValue int    `description:"基础计算窗口"`
+	BaseCalculateUnit  string `description:"基础计算频度"`
+	LeadValue          int    `description:"领先期数"`
+	LeadUnit           string `description:"频度"`
+	CalculateValue     int    `description:"计算窗口"`
+	CalculateUnit      string `description:"计算频度"`
+}
+
+// refreshAllCalculateCorrelation 刷新扩散指数数据
+func refreshAllCalculateCorrelation(to orm.TxOrmer, edbInfoId, source int, edbInfoA, edbInfoB *EdbInfo, edbCode, calculateFormula string) (err error, errMsg string) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_CORRELATION)
+
+	//获取扩散指数指标所有数据
+	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 correlationConf EdbCalculateFormula
+	fmt.Println("calculateFormula:", calculateFormula)
+	err = json.Unmarshal([]byte(calculateFormula), &correlationConf)
+	if err != nil {
+		return
+	}
+	frequencyDaysMap := map[string]int{
+		"天": 1, "周": 7, "月": 30, "季": 90, "年": 365,
+	}
+	moveUnitDays, ok := frequencyDaysMap[correlationConf.CalculateUnit]
+	if !ok {
+		errMsg = `错误的分析周期`
+		err = errors.New(errMsg)
+		return
+	}
+	startDate := time.Now().AddDate(0, 0, -correlationConf.CalculateValue*moveUnitDays).Format(utils.FormatDate)
+	endDate := time.Now().Format(utils.FormatDate)
+	correlationChartDataMap, err := GetRollingCorrelationChartDataByEdbInfo(edbInfoA, edbInfoB, correlationConf.LeadValue, correlationConf.LeadUnit, correlationConf.CalculateValue, correlationConf.CalculateUnit, startDate, endDate)
+
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	for currDateStr, val := range correlationChartDataMap {
+		currDate, tmpErr := time.ParseInLocation(utils.FormatDate, currDateStr, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		currVal, _ := decimal.NewFromFloat(val).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
+				}
+			}
+		} 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
+}
+
+// GetRollingCorrelationChartDataByEdbInfo 滚动相关性计算
+func GetRollingCorrelationChartDataByEdbInfo(edbInfoMappingA, edbInfoMappingB *EdbInfo, leadValue int, leadUnit string, calculateValue int, calculateUnit string, startDate, endDate string) (dateData map[string]float64, err error) {
+	dateData = make(map[string]float64)
+	baseEdbInfo := edbInfoMappingA
+	changeEdbInfo := edbInfoMappingB
+
+	// 获取时间基准指标在时间区间内的值
+	aDataList := make([]*EdbInfoSearchData, 0)
+	switch baseEdbInfo.EdbInfoType {
+	case 0:
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, baseEdbInfo.EdbInfoId)
+
+		//获取来源指标的数据
+		aDataList, err = GetEdbDataListAll(condition, pars, baseEdbInfo.Source, 1)
+	case 1:
+		aDataList, err = GetPredictEdbDataListAllByStartDate(baseEdbInfo, 1, "")
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标base类型异常", baseEdbInfo.EdbInfoType))
+	}
+
+	// 获取变频指标所有日期的值, 插值法完善数据
+	bDataList := make([]*EdbInfoSearchData, 0)
+	switch changeEdbInfo.EdbInfoType {
+	case 0:
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, changeEdbInfo.EdbInfoId)
+
+		//获取来源指标的数据
+		bDataList, err = GetEdbDataListAll(condition, pars, changeEdbInfo.Source, 1)
+	case 1:
+		bDataList, err = GetPredictEdbDataListAllByStartDate(changeEdbInfo, 1, "")
+	default:
+		err = errors.New(fmt.Sprint("获取失败,指标change类型异常", baseEdbInfo.EdbInfoType))
+		return
+	}
+
+	// 数据平移变频指标领先/滞后的日期(单位天)
+	frequencyDaysMap := map[string]int{
+		"天": 1, "周": 7, "月": 30, "季": 90, "年": 365,
+	}
+	// 2023-03-17 时间序列始终以指标A为基准, 始终是B进行平移
+	//baseDataList := make([]*data_manage.EdbDataList, 0)
+	baseDataMap := make(map[string]float64)
+	changeDataList := make([]*EdbInfoSearchData, 0)
+	changeDataMap := make(map[string]float64)
+
+	// A指标不管三七二十一,先变个频再说
+	{
+		_, e := HandleDataByLinearRegression(aDataList, baseDataMap)
+		if e != nil {
+			err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+			return
+		}
+		//baseDataList = tmpNewChangeDataList
+	}
+	// A指标不管三七二十一,先变个频再说
+	{
+		tmpNewChangeDataList, e := HandleDataByLinearRegression(bDataList, changeDataMap)
+		if e != nil {
+			err = fmt.Errorf("获取变频指标插值法Map失败, Err: %s", e.Error())
+			return
+		}
+		changeDataList = tmpNewChangeDataList
+
+		// 平移下日期
+		moveUnitDays := frequencyDaysMap[leadUnit]
+		_, changeDataMap = MoveDataDaysToNewDataList(changeDataList, leadValue*moveUnitDays)
+	}
+
+	// 计算计算时,需要多少个日期内数据
+	calculateDay := frequencyDaysMap[calculateUnit] * calculateValue
+
+	// 计算 每个日期的相关性值
+	{
+		startDateTime, _ := time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		endDateTime, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+
+		for currDay := startDateTime; !currDay.After(endDateTime); currDay = currDay.AddDate(0, 0, 1) {
+			coordinateData := make([]utils.Coordinate, 0)
+			// 取出对应的基准日期的值
+			for i := 0; i < calculateDay; i++ {
+				iDay := currDay.AddDate(0, 0, i).Format(utils.FormatDate)
+				tmpCoordinate := utils.Coordinate{
+					X: baseDataMap[iDay],
+					Y: changeDataMap[iDay],
+				}
+				coordinateData = append(coordinateData, tmpCoordinate)
+			}
+
+			// 公式计算出领先/滞后频度对应点的相关性系数
+			var ratio float64
+			if len(coordinateData) > 0 {
+				ratio = utils.ComputeCorrelation(coordinateData)
+			}
+			dateData[currDay.AddDate(0, 0, calculateDay).Format(utils.FormatDate)] = ratio
+		}
+	}
+	return
+}
+
+// MoveDataDaysToNewDataList 平移指标数据生成新的数据序列
+func MoveDataDaysToNewDataList(dataList []*EdbInfoSearchData, moveDay int) (newDataList []EdbInfoSearchData, dateDataMap map[string]float64) {
+	dateMap := make(map[time.Time]float64)
+	var minDate, maxDate time.Time
+	dateDataMap = make(map[string]float64)
+
+	for _, v := range dataList {
+		currDate, _ := time.ParseInLocation(utils.FormatDate, v.DataTime, time.Local)
+		if minDate.IsZero() || currDate.Before(minDate) {
+			minDate = currDate
+		}
+		if maxDate.IsZero() || currDate.After(maxDate) {
+			maxDate = currDate
+		}
+		dateMap[currDate] = v.Value
+	}
+
+	// 处理领先、滞后数据
+	newDateMap := make(map[time.Time]float64)
+	for currDate, value := range dateMap {
+		newDate := currDate.AddDate(0, 0, moveDay)
+		newDateMap[newDate] = value
+	}
+	minDate = minDate.AddDate(0, 0, moveDay)
+	maxDate = maxDate.AddDate(0, 0, moveDay)
+
+	// 获取日期相差日
+	dayNum := utils.GetTimeSubDay(minDate, maxDate)
+
+	for i := 0; i <= dayNum; i++ {
+		currDate := minDate.AddDate(0, 0, i)
+		tmpValue, ok := newDateMap[currDate]
+		if !ok {
+			//找不到数据,那么就用前面的数据吧
+			if len(newDataList)-1 < 0 {
+				tmpValue = 0
+			} else {
+				tmpValue = newDataList[len(newDataList)-1].Value
+			}
+		}
+		tmpData := EdbInfoSearchData{
+			DataTime: currDate.Format(utils.FormatDate),
+			Value:    tmpValue,
+		}
+		dateDataMap[tmpData.DataTime] = tmpData.Value
+		newDataList = append(newDataList, tmpData)
+	}
+	return
+}

+ 1 - 1
models/edb_data_calculate_nh.go

@@ -232,7 +232,7 @@ func refreshAllCalculateNh(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *E
 
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(fromDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(fromDataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 2 - 0
models/edb_data_table.go

@@ -119,6 +119,8 @@ func GetEdbDataTableName(source int) (tableName string) {
 		tableName = "edb_data_baiinfo"
 	case utils.DATA_SOURCE_STOCK_PLANT:
 		tableName = "edb_data_stock_plant"
+	case utils.DATA_SOURCE_CALCULATE_CORRELATION:
+		tableName = "edb_data_calculate_correlation"
 	default:
 		tableName = ""
 	}

+ 15 - 1
models/handle_data.go

@@ -9,7 +9,7 @@ import (
 )
 
 // HandleDataByLinearRegression 插值法补充数据(线性方程式)
-func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (err error) {
+func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDataMap map[string]float64) (newList []*EdbInfoSearchData, err error) {
 	if len(edbInfoDataList) < 2 {
 		return
 	}
@@ -21,6 +21,11 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 		// 第一个数据就给过滤了,给后面的试用
 		if startEdbInfoData == nil {
 			startEdbInfoData = v
+			newList = append(newList, &EdbInfoSearchData{
+				EdbDataId: v.EdbDataId,
+				DataTime:  v.DataTime,
+				Value:     v.Value,
+			})
 			continue
 		}
 
@@ -33,6 +38,11 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 		// 如果相差一天,那么过滤
 		if betweenDay <= 1 {
 			startEdbInfoData = v
+			newList = append(newList, &EdbInfoSearchData{
+				EdbDataId: v.EdbDataId,
+				DataTime:  v.DataTime,
+				Value:     v.Value,
+			})
 			continue
 		}
 
@@ -68,6 +78,10 @@ func HandleDataByLinearRegression(edbInfoDataList []*EdbInfoSearchData, handleDa
 
 				val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).Round(4).Float64()
 				handleDataMap[tmpDataTime.Format(utils.FormatDate)] = val
+				newList = append(newList, &EdbInfoSearchData{
+					DataTime: tmpDataTime.Format(utils.FormatDate),
+					Value:    val,
+				})
 			}
 		}
 

+ 1 - 1
models/predict_edb_data_calculate_nh.go

@@ -216,7 +216,7 @@ func refreshAllPredictCalculateNh(to orm.TxOrmer, edbInfoId, source int, fromEdb
 	}
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(fromDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(fromDataList, handleDataMap)
 	if err != nil {
 		return
 	}

+ 2 - 2
models/predict_edb_info_rule.go

@@ -690,7 +690,7 @@ func GetChartPredictEdbInfoDataListByRuleSeason(edbInfoId int, yearsList []int,
 
 	// 插值法数据处理
 	handleDataMap := make(map[string]float64)
-	err = HandleDataByLinearRegression(allDataList, handleDataMap)
+	_, err = HandleDataByLinearRegression(allDataList, handleDataMap)
 	if err != nil {
 		return
 	}
@@ -828,7 +828,7 @@ func GetChartPredictEdbInfoDataListByRuleSeason(edbInfoId int, yearsList []int,
 		existMap[currentDateStr] = val
 
 		// 继续使用插值法补充新预测日期的数据之间的值
-		err = HandleDataByLinearRegression([]*EdbInfoSearchData{
+		_, err = HandleDataByLinearRegression([]*EdbInfoSearchData{
 			lastDayData, tmpData,
 		}, handleDataMap)
 		if err != nil {

+ 2 - 0
utils/constants.go

@@ -87,6 +87,7 @@ const (
 	DATA_SOURCE_PREDICT_CALCULATE_KSZS                  //预测指标 - 计算指标(扩散指数)->56
 	DATA_SOURCE_BAIINFO                                 //百川盈孚 ->57
 	DATA_SOURCE_STOCK_PLANT                             //存量装置 ->58
+	DATA_SOURCE_CALCULATE_CORRELATION                   //相关性计算->59
 )
 
 // 指标来源的中文展示
@@ -149,6 +150,7 @@ const (
 	DATA_SOURCE_NAME_PREDICT_CALCULATE_KSZS       = `预测扩散指数`            //预测指标 - 计算指标(扩散指数)->56
 	DATA_SOURCE_NAME_BAIINFO                      = `百川盈孚`              //百川盈孚 ->57
 	DATA_SOURCE_NAME_STOCK_PLANT                  = `存量装置`              //存量装置 ->58
+	DATA_SOURCE_NAME_CALCULATE_CORRELATION        = `相关性计算`             //相关性计算->59
 )
 
 // 基础数据初始化日期