瀏覽代碼

Merge remote-tracking branch 'origin/chart/13.0' into debug

# Conflicts:
#	models/edb_data_table.go
#	utils/constants.go
Roc 2 年之前
父節點
當前提交
4bfad18db3
共有 5 個文件被更改,包括 657 次插入86 次删除
  1. 47 4
      controllers/base_from_calculate.go
  2. 464 0
      models/edb_data_calculate_jp.go
  3. 3 1
      models/edb_data_table.go
  4. 88 27
      utils/common.go
  5. 55 54
      utils/constants.go

+ 47 - 4
controllers/base_from_calculate.go

@@ -85,7 +85,7 @@ func (this *CalculateController) Add() {
 		//设置3分钟缓存
 		utils.Rc.SetNX(redisKey, 1, time.Second*300)
 		defer func() {
-			utils.Rc.Delete(redisKey)
+			_ = utils.Rc.Delete(redisKey)
 		}()
 	}
 
@@ -536,6 +536,11 @@ func (this *CalculateController) BatchSave() {
 		}
 		nhccDate.StartDate = startDate
 		nhccDate.EndDate = endDate
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if req.Formula != "期末值" && req.Formula != "平均值" {
+			br.Msg = "数据取值类型错误:" + req.Formula
+			return
+		}
 	}
 
 	if fromEdbInfoId <= 0 {
@@ -552,7 +557,7 @@ func (this *CalculateController) BatchSave() {
 		//设置3分钟缓存
 		utils.Rc.SetNX(redisKey, 1, time.Second*300)
 		defer func() {
-			utils.Rc.Delete(redisKey)
+			_ = utils.Rc.Delete(redisKey)
 		}()
 	}
 	//加入缓存机制,避免创建同一个名称的指标 end
@@ -742,6 +747,13 @@ func (this *CalculateController) BatchSave() {
 			return
 		}
 		edbInfo, err = models.AddCalculateNhcc(&req, fromEdbInfo, secondEdbInfo, edbCode, uniqueCode, nhccDate, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if !models.CheckFrequency(fromEdbInfo.Frequency, req.Frequency) {
+			br.Msg = "频度异常,不允许低频降频到高频"
+			return
+		}
+		sourName = "降频"
+		edbInfo, err = models.AddCalculateJp(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -941,6 +953,11 @@ func (this *CalculateController) BatchEdit() {
 		}
 		nhccDate.StartDate = startDate
 		nhccDate.EndDate = endDate
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if req.Formula != "期末值" && req.Formula != "平均值" {
+			br.Msg = "数据取值类型错误:" + req.Formula
+			return
+		}
 	}
 
 	// 获取基础指标信息
@@ -1086,6 +1103,13 @@ func (this *CalculateController) BatchEdit() {
 			return
 		}
 		err = models.EditCalculateNhcc(&req, edbInfo, fromEdbInfo, secondEdbInfo, nhccDate)
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if !models.CheckFrequency(fromEdbInfo.Frequency, req.Frequency) {
+			br.Msg = "频度异常,不允许低频降频到高频"
+			return
+		}
+		sourName = "降频"
+		err = models.EditCalculateJp(edbInfo, &req, fromEdbInfo)
 	default:
 		br.Msg = "无效计算方式"
 		br.ErrMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
@@ -1192,7 +1216,7 @@ func (this *CalculateController) Refresh() {
 	// 刷新指标
 	utils.Rc.SetNX(cacheKey, 1, 1*time.Minute)
 	defer func() {
-		utils.Rc.Delete(cacheKey)
+		_ = utils.Rc.Delete(cacheKey)
 	}()
 
 	startDate := req.StartDate
@@ -1454,6 +1478,25 @@ func (this *CalculateController) Refresh() {
 			errMsg = "RefreshAllCalculateLjzzy Err:" + err.Error()
 			break
 		}
+	case utils.DATA_SOURCE_CALCULATE_JP: //刷新变频
+		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
+		}
+		//startDate = edbInfo.StartDate
+		endDate = time.Now().Format(utils.FormatDate)
+		err = models.RefreshAllCalculateJp(edbInfoId, source, fromEdbInfo, edbInfo.EdbCode, edbInfo.Frequency, edbInfo.CalculateFormula)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			errMsg = "RefreshAllCalculateBp Err:" + err.Error()
+			break
+		}
 	default:
 		br.Msg = "来源异常,请联系相关开发!"
 		br.ErrMsg = "来源异常,请联系相关开发"
@@ -1535,7 +1578,7 @@ func (this *CalculateController) SaveAdjust() {
 		//设置3分钟缓存
 		utils.Rc.SetNX(redisKey, 1, time.Second*300)
 		defer func() {
-			utils.Rc.Delete(redisKey)
+			_ = utils.Rc.Delete(redisKey)
 		}()
 	}
 

+ 464 - 0
models/edb_data_calculate_jp.go

@@ -0,0 +1,464 @@
+package models
+
+import (
+	"errors"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"hongze/hongze_edb_lib/utils"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// CheckFrequency 判断是否可以降频
+func CheckFrequency(fromEdbFrequency, edbFrequency string) (ok bool) {
+	frequencyList := make([]string, 0)
+	switch fromEdbFrequency {
+	case "日度":
+		frequencyList = []string{"日度"}
+	case "周度":
+		frequencyList = []string{"日度", "周度"}
+	case "旬度":
+		frequencyList = []string{"日度", "周度", "旬度"}
+	case "月度":
+		frequencyList = []string{"日度", "周度", "旬度", "月度"}
+	case "季度":
+		frequencyList = []string{"日度", "周度", "旬度", "月度", "季度"}
+	default:
+		return
+	}
+
+	// 如果存在,那么就标识不允许降频
+	if utils.InArrayByStr(frequencyList, edbFrequency) {
+		return
+	}
+	ok = true
+
+	return
+}
+
+// AddCalculateJp 降频
+func AddCalculateJp(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("AddCalculateJp,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId <= 0 {
+		edbInfo = new(EdbInfo)
+		edbInfo.Source = utils.DATA_SOURCE_CALCULATE_JP
+		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
+		}
+		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_JP)
+		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 = refreshAllCalculateJp(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, edbInfo.Frequency, fromEdbInfo.Frequency, edbInfo.CalculateFormula)
+
+	return
+}
+
+// EditCalculateJp 修改降频数据
+func EditCalculateJp(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("EditCalculateJp,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_JP,
+			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
+		}
+	}
+
+	//计算数据
+	err = refreshAllCalculateJp(to, edbInfo.EdbInfoId, edbInfo.Source, fromEdbInfo, edbInfo.EdbCode, edbInfo.Frequency, fromEdbInfo.Frequency, edbInfo.CalculateFormula)
+
+	return
+}
+
+func RefreshAllCalculateJp(edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, edbFrequency, formula string) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("RefreshAllCalculateJp,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err = refreshAllCalculateJp(to, edbInfoId, source, fromEdbInfo, edbCode, edbFrequency, fromEdbInfo.Frequency, formula)
+
+	return
+}
+
+// refreshAllCalculateJp 刷新降频数据
+func refreshAllCalculateJp(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode, edbFrequency, fromEdbFrequency, formula string) (err error) {
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+
+	//计算数据
+	var condition string
+	var pars []interface{}
+	condition += " AND edb_info_id=? "
+	pars = append(pars, fromEdbInfo.EdbInfoId)
+
+	//if startDate != "" {
+	//	condition += " AND data_time>=? "
+	//	pars = append(pars, startDate)
+	//}
+	//if endDate != "" {
+	//	condition += " AND data_time<=? "
+	//	pars = append(pars, endDate)
+	//}
+	//获取来源指标的数据
+	dataList, err := GetEdbDataListAllByTo(to, condition, pars, fromEdbInfo.Source, 1)
+	if err != nil {
+		return err
+	}
+	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)
+	//existDataMap := make(map[string]string, 0)
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v
+	}
+
+	tableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_JP)
+	addSql := ` INSERT INTO ` + tableName + ` (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)
+	if dataLen <= 0 {
+		return
+	}
+	startDataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[0].DataTime, time.Local)
+	endDataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[dataLen-1].DataTime, time.Local)
+
+	var lastValue float64     // 最近的值
+	var nextEndDate time.Time // 下一个节点的日期
+	weekDayDataList := make([]float64, 0)
+	for tmpStartDataTime := startDataTime; !tmpStartDataTime.After(endDataTime); tmpStartDataTime = tmpStartDataTime.AddDate(0, 0, 1) {
+		// 将当前数据加入到 weekDayDataList
+		if tmpData, ok := dataMap[tmpStartDataTime.Format(utils.FormatDate)]; ok {
+			tmpValue := decimal.NewFromFloat(tmpData.Value)
+			tmpValueFloat, _ := tmpValue.Truncate(4).Float64()
+			weekDayDataList = append(weekDayDataList, tmpValueFloat)
+		}
+		// 如果下个节点的日期不存在,那么就先给赋值(兼容时间区间内只有一组数据的情况)
+		if nextEndDate.IsZero() {
+			nextEndDate = utils.GetFrequencyEndDay(tmpStartDataTime, edbFrequency)
+		}
+
+		// 日期处理过滤
+		switch edbFrequency {
+		case "周度":
+			if tmpStartDataTime.Weekday() != 0 {
+				//不是周日,代表需要进入下一个循环获取数据并计算
+				continue
+			} else {
+				//记录下一个结束节点的日期
+				nextEndDate = tmpStartDataTime.AddDate(0, 0, 7)
+			}
+		case "旬度":
+			nextDay := tmpStartDataTime.AddDate(0, 0, 1)
+			if nextDay.Day() != 1 && nextDay.Day() != 11 && nextDay.Day() != 21 {
+				//不是每月10、20、最后一天,代表需要进入下一个循环获取数据并计算
+				continue
+			} else {
+				//记录下一个结束节点的日期
+				if nextDay.Day() == 1 || nextDay.Day() == 11 {
+					//月初或者月末的时候,加10天就好了
+					nextEndDate = nextDay.AddDate(0, 0, 9)
+				} else {
+					tmpNextMonth := nextDay.AddDate(0, 1, 0)
+					nextEndDate = time.Date(tmpNextMonth.Year(), tmpNextMonth.Month(), 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
+				}
+			}
+		case "月度":
+			nextDay := tmpStartDataTime.AddDate(0, 0, 1)
+			if nextDay.Day() != 1 {
+				//不是每月最后一天,代表需要进入下一个循环获取数据并计算
+				continue
+			} else {
+				//记录下一个结束节点的日期
+				nextEndDate = nextDay.AddDate(0, 1, -1)
+			}
+		case "季度":
+			nextDay := tmpStartDataTime.AddDate(0, 0, 1)
+			if (nextDay.Month() == 1 || nextDay.Month() == 4 || nextDay.Month() == 7 || nextDay.Month() == 10) && nextDay.Day() == 1 {
+				//记录下一个结束节点的日期
+				nextEndDate = nextDay.AddDate(0, 3, -1)
+			} else {
+				//不是3,6,9,12 月份的最后一天,代表需要进入下一个循环获取数据并计算
+				continue
+			}
+		case "年度":
+			if tmpStartDataTime.Month() == 12 && tmpStartDataTime.Day() == 31 {
+				//记录下一个结束节点的日期
+				nextEndDate = tmpStartDataTime.AddDate(1, 0, 0)
+			} else {
+				//不是每年的12-31日,代表需要进入下一个循环获取数据并计算
+				continue
+			}
+		default:
+			err = errors.New("错误的频度:" + edbFrequency)
+			return
+		}
+
+		// 当前时间段内的数据计算,得出实际值
+		var currVal float64
+		lenWeekDayDataList := len(weekDayDataList)
+		// 如果这个时间区间内没有数据,那么就采用上一个时间区间的值
+		if len(weekDayDataList) <= 0 {
+			currVal = lastValue
+		} else {
+			if formula == "期末值" {
+				currVal = weekDayDataList[lenWeekDayDataList-1]
+			} else {
+				// 平均值
+				sumValDeci := decimal.NewFromFloat(0)
+				for _, v := range weekDayDataList {
+					tmpValDeci := decimal.NewFromFloat(v)
+					sumValDeci = sumValDeci.Add(tmpValDeci)
+				}
+				lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
+				currVal, _ = sumValDeci.Div(lenDeci).Truncate(4).Float64()
+			}
+		}
+
+		// 判断降频指标是否存在数据
+		if existData, ok := existDataMap[tmpStartDataTime.Format(utils.FormatDate)]; ok {
+			// 处理降频数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Truncate(4).Float64()
+			// 判断降频数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := tmpStartDataTime.UnixNano() / 1e6
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, tmpStartDataTime.Format(utils.FormatDate), timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+
+		// 一轮结束后,数据清空
+		weekDayDataList = make([]float64, 0)
+	}
+
+	// 最后已有的日期处理完成后,需要对剩余不在时间段内的数据做处理
+	if len(weekDayDataList) > 0 {
+		// 当前时间段内的数据计算,得出实际值
+		var currVal float64
+		lenWeekDayDataList := len(weekDayDataList)
+		// 如果这个时间区间内没有数据,那么就采用上一个时间区间的值
+		if len(weekDayDataList) < 0 {
+			currVal = lastValue
+		} else {
+			if formula == "期末值" {
+				currVal = weekDayDataList[lenWeekDayDataList-1]
+			} else {
+				// 平均值
+				sumValDeci := decimal.NewFromFloat(0)
+				for _, v := range weekDayDataList {
+					tmpValDeci := decimal.NewFromFloat(v)
+					sumValDeci = sumValDeci.Add(tmpValDeci)
+				}
+				lenDeci := decimal.NewFromInt(int64(lenWeekDayDataList))
+				currVal, _ = sumValDeci.Div(lenDeci).Truncate(4).Float64()
+			}
+		}
+
+		// 判断降频指标是否存在数据
+		if existData, ok := existDataMap[nextEndDate.Format(utils.FormatDate)]; ok {
+			// 处理降频数据的值
+			existValStr := existData.Value
+			existValDeci, tmpErr := decimal.NewFromString(existValStr)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			existVal, _ := existValDeci.Truncate(4).Float64()
+			// 判断降频数据的值 与 当前计算出来的结果, 如果两个数据结果不相等的话,那么就修改咯
+			if existVal != currVal {
+				err = ModifyEdbDataById(source, existData.EdbDataId, fmt.Sprint(currVal))
+				if err != nil {
+					return err
+				}
+			}
+		} else {
+			// 直接入库
+			timestamp := nextEndDate.UnixNano() / 1e6
+			timestampStr := fmt.Sprintf("%d", timestamp)
+			addSql += GetAddSql(edbInfoIdStr, edbCode, nextEndDate.Format(utils.FormatDate), timestampStr, fmt.Sprint(currVal))
+			isAdd = true
+		}
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+	}
+
+	return
+}

+ 3 - 1
models/edb_data_table.go

@@ -4,7 +4,7 @@ import (
 	"hongze/hongze_edb_lib/utils"
 )
 
-//指标数据->存储表
+// 指标数据->存储表
 func GetEdbDataTableName(source int) (tableName string) {
 	switch source {
 	case utils.DATA_SOURCE_THS:
@@ -103,6 +103,8 @@ func GetEdbDataTableName(source int) (tableName string) {
 		tableName = "edb_data_predict_calculate_hcz"
 	case utils.DATA_SOURCE_PREDICT_CALCULATE_BP:
 		tableName = "edb_data_predict_calculate_bp"
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		tableName = "edb_data_calculate_jp"
 	default:
 		tableName = ""
 	}

+ 88 - 27
utils/common.go

@@ -27,7 +27,7 @@ import (
 	"time"
 )
 
-//随机数种子
+// 随机数种子
 var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
 
 func GetRandString(size int) string {
@@ -64,13 +64,13 @@ func StringsToJSON(str string) string {
 	return jsons
 }
 
-//序列化
+// 序列化
 func ToString(v interface{}) string {
 	data, _ := json.Marshal(v)
 	return string(data)
 }
 
-//md5加密
+// md5加密
 func MD5(data string) string {
 	m := md5.Sum([]byte(data))
 	return hex.EncodeToString(m[:])
@@ -98,7 +98,7 @@ func GetToday(format string) string {
 	return today
 }
 
-//获取今天剩余秒数
+// 获取今天剩余秒数
 func GetTodayLastSecond() time.Duration {
 	today := GetToday(FormatDate) + " 23:59:59"
 	end, _ := time.ParseInLocation(FormatDateTime, today, time.Local)
@@ -120,7 +120,7 @@ func GetBrithDate(idcard string) string {
 	return GetToday(FormatDate)
 }
 
-//处理性别
+// 处理性别
 func WhichSexByIdcard(idcard string) string {
 	var sexs = [2]string{"女", "男"}
 	length := len(idcard)
@@ -134,7 +134,7 @@ func WhichSexByIdcard(idcard string) string {
 	return "男"
 }
 
-//截取小数点后几位
+// 截取小数点后几位
 func SubFloatToString(f float64, m int) string {
 	n := strconv.FormatFloat(f, 'f', -1, 64)
 	if n == "" {
@@ -153,20 +153,20 @@ func SubFloatToString(f float64, m int) string {
 	return newn[0] + "." + newn[1][:m]
 }
 
-//截取小数点后几位
+// 截取小数点后几位
 func SubFloatToFloat(f float64, m int) float64 {
 	newn := SubFloatToString(f, m)
 	newf, _ := strconv.ParseFloat(newn, 64)
 	return newf
 }
 
-//截取小数点后几位
+// 截取小数点后几位
 func SubFloatToFloatStr(f float64, m int) string {
 	newn := SubFloatToString(f, m)
 	return newn
 }
 
-//获取相差时间-年
+// 获取相差时间-年
 func GetYearDiffer(start_time, end_time string) int {
 	t1, _ := time.ParseInLocation("2006-01-02", start_time, time.Local)
 	t2, _ := time.ParseInLocation("2006-01-02", end_time, time.Local)
@@ -177,7 +177,7 @@ func GetYearDiffer(start_time, end_time string) int {
 	return age
 }
 
-//获取相差时间-秒
+// 获取相差时间-秒
 func GetSecondDifferByTime(start_time, end_time time.Time) int64 {
 	diff := end_time.Unix() - start_time.Unix()
 	return diff
@@ -204,7 +204,7 @@ func StrListToString(strList []string) (str string) {
 	return ""
 }
 
-//Token
+// Token
 func GetToken() string {
 	randStr := GetRandString(64)
 	token := MD5(randStr + Md5Key)
@@ -212,18 +212,18 @@ func GetToken() string {
 	return strings.ToUpper(token + GetRandString(tokenLen))
 }
 
-//数据没有记录
+// 数据没有记录
 func ErrNoRow() string {
 	return "<QuerySeter> no row found"
 }
 
-//判断文件是否存在
+// 判断文件是否存在
 func FileIsExist(filePath string) bool {
 	_, err := os.Stat(filePath)
 	return err == nil || os.IsExist(err)
 }
 
-//获取图片扩展名
+// 获取图片扩展名
 func GetImgExt(file string) (ext string, err error) {
 	var headerByte []byte
 	headerByte = make([]byte, 8)
@@ -266,7 +266,7 @@ func GetImgExt(file string) (ext string, err error) {
 	return ext, nil
 }
 
-//保存图片
+// 保存图片
 func SaveImage(path string, img image.Image) (err error) {
 	//需要保持的文件
 	imgfile, err := os.Create(path)
@@ -276,7 +276,7 @@ func SaveImage(path string, img image.Image) (err error) {
 	return err
 }
 
-//下载图片
+// 下载图片
 func DownloadImage(imgUrl string) (filePath string, err error) {
 	imgPath := "./static/imgs/"
 	fileName := path.Base(imgUrl)
@@ -302,7 +302,7 @@ func DownloadImage(imgUrl string) (filePath string, err error) {
 	return
 }
 
-//保存base64数据为文件
+// 保存base64数据为文件
 func SaveBase64ToFile(content, path string) error {
 	data, err := base64.StdEncoding.DecodeString(content)
 	if err != nil {
@@ -432,7 +432,7 @@ func GetWilsonScore(p, n float64) float64 {
 	return toFixed(((p+1.9208)/(p+n)-1.96*math.Sqrt(p*n/(p+n)+0.9604)/(p+n))/(1+3.8416/(p+n)), 2)
 }
 
-//将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上
+// 将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上
 func ChangeWordsToNum(str string) (numStr string) {
 	words := ([]rune)(str)
 	num := 0
@@ -603,7 +603,7 @@ func GetMonthStartAndEnd(myYear string, myMonth string) (startDate, endDate stri
 	return t1, t2
 }
 
-//移除字符串中的空格
+// 移除字符串中的空格
 func TrimStr(str string) (str2 string) {
 	if str == "" {
 		return str
@@ -611,7 +611,7 @@ func TrimStr(str string) (str2 string) {
 	return strings.Replace(str, " ", "", -1)
 }
 
-//字符串转换为time
+// 字符串转换为time
 func StrTimeToTime(strTime string) time.Time {
 	timeLayout := "2006-01-02 15:04:05"  //转化所需模板
 	loc, _ := time.LoadLocation("Local") //重要:获取时区
@@ -619,7 +619,7 @@ func StrTimeToTime(strTime string) time.Time {
 	return resultTime
 }
 
-//字符串类型时间转周几
+// 字符串类型时间转周几
 func StrDateTimeToWeek(strTime string) string {
 	var WeekDayMap = map[string]string{
 		"Monday":    "周一",
@@ -636,7 +636,7 @@ func StrDateTimeToWeek(strTime string) string {
 	return WeekDayMap[staweek_int]
 }
 
-//时间格式转年月日字符串
+// 时间格式转年月日字符串
 func TimeToStrYmd(time2 time.Time) string {
 	var Ymd string
 	year := time2.Year()
@@ -646,7 +646,7 @@ func TimeToStrYmd(time2 time.Time) string {
 	return Ymd
 }
 
-//时间格式去掉时分秒
+// 时间格式去掉时分秒
 func TimeRemoveHms(strTime string) string {
 	var Ymd string
 	var resultTime = StrTimeToTime(strTime)
@@ -657,7 +657,7 @@ func TimeRemoveHms(strTime string) string {
 	return Ymd
 }
 
-//时间格式去掉时分秒
+// 时间格式去掉时分秒
 func TimeRemoveHms2(strTime string) string {
 	var Ymd string
 	var resultTime = StrTimeToTime(strTime)
@@ -668,7 +668,7 @@ func TimeRemoveHms2(strTime string) string {
 	return Ymd
 }
 
-//文章上一次编辑时间
+// 文章上一次编辑时间
 func ArticleLastTime(strTime string) string {
 	var newTime string
 	stamp, _ := time.ParseInLocation("2006-01-02 15:04:05", strTime, time.Local)
@@ -689,7 +689,7 @@ func ArticleLastTime(strTime string) string {
 	return newTime
 }
 
-//人民币小写转大写
+// 人民币小写转大写
 func ConvertNumToCny(num float64) (str string, err error) {
 	strNum := strconv.FormatFloat(num*100, 'f', 0, 64)
 	sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"}
@@ -1001,7 +1001,7 @@ func HideString(src string, hideLen int) string {
 	return string(str[:frontLen]) + hideStr + string(str[frontLen+int64(hideLen):])
 }
 
-//用户参会时间转换
+// 用户参会时间转换
 func GetAttendanceDetailSeconds(secondNum int) string {
 	var timeStr string
 	if secondNum <= 60 {
@@ -1118,3 +1118,64 @@ func GetTimeSubDay(t1, t2 time.Time) int {
 
 	return day
 }
+
+// GetFrequencyEndDay 根据当前时间和频度,获取该频度下最后一天的日期
+func GetFrequencyEndDay(currDate time.Time, frequency string) (endDate time.Time) {
+	switch frequency {
+	case "周度":
+		// 如果当前就是最后一天,那么就直接返回本日期就好了
+		if currDate.Weekday() == 0 {
+			endDate = currDate
+		} else {
+			endDate = currDate.AddDate(0, 0, 7-int(currDate.Weekday()))
+		}
+	case "旬度":
+		nextDay := currDate.AddDate(0, 0, 1)
+		if nextDay.Day() == 1 || currDate.Day() == 10 || currDate.Day() == 20 {
+			//如果是每月10、20、最后一天,那么就直接返回本日期就好了
+			endDate = currDate
+		} else {
+			if currDate.Day() < 10 { // 每月10号
+				endDate = time.Date(currDate.Year(), currDate.Month(), 10, 0, 0, 0, 0, time.Local)
+			} else if currDate.Day() < 20 { // 每月10号
+				endDate = time.Date(currDate.Year(), currDate.Month(), 20, 0, 0, 0, 0, time.Local)
+			} else {
+				// 下旬,多种可能,最大天数可能存在8天,9天,10天,11天,
+				tmpNextMonth := currDate.AddDate(0, 0, 13)
+				endDate = time.Date(tmpNextMonth.Year(), tmpNextMonth.Month(), 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
+			}
+		}
+	case "月度":
+		nextDay := currDate.AddDate(0, 0, 1)
+		if nextDay.Day() == 1 {
+			//如果是每月的最后一天,那么就直接返回本日期就好了
+			endDate = currDate
+		} else {
+			endDate = time.Date(nextDay.Year(), nextDay.Month()+1, 1, 0, 0, 0, 0, time.Local).AddDate(0, 0, -1)
+		}
+	case "季度":
+		nextDay := currDate.AddDate(0, 0, 1)
+		if (nextDay.Month() == 1 || nextDay.Month() == 4 || nextDay.Month() == 7 || nextDay.Month() == 10) && nextDay.Day() == 1 {
+			//如果是每季的最后一天,那么就直接返回本日期就好了
+			endDate = currDate
+		} else {
+			if currDate.Month() < 4 { // 1季度
+				endDate = time.Date(currDate.Year(), 3, 31, 0, 0, 0, 0, time.Local)
+			} else if currDate.Month() < 7 { // 2季度
+				endDate = time.Date(currDate.Year(), 6, 30, 0, 0, 0, 0, time.Local)
+			} else if currDate.Month() < 10 { // 3季度
+				endDate = time.Date(currDate.Year(), 9, 30, 0, 0, 0, 0, time.Local)
+			} else {
+				// 4季度
+				endDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, time.Local)
+			}
+		}
+	case "年度":
+		endDate = time.Date(currDate.Year(), 12, 31, 0, 0, 0, 0, time.Local)
+	default:
+		endDate = currDate
+		return
+	}
+
+	return
+}

+ 55 - 54
utils/constants.go

@@ -6,7 +6,7 @@ const (
 	Md5Key = "GuRaB6dY1bXOJcwG"
 )
 
-//常量定义
+// 常量定义
 const (
 	FormatTime                 = "15:04:05"            //时间格式
 	FormatDate                 = "2006-01-02"          //日期格式
@@ -27,61 +27,62 @@ const (
 	EmailSendToUsers = "glji@hzinsights.com;pyan@hzinsights.com;cxzhang@hzinsights.com"
 )
 
-//数据来源渠道
+// 数据来源渠道
 const (
-	DATA_SOURCE_THS                         = iota + 1 //同花顺
-	DATA_SOURCE_WIND                                   //wind
-	DATA_SOURCE_PB                                     //彭博
-	DATA_SOURCE_CALCULATE                              //指标运算
-	DATA_SOURCE_CALCULATE_LJZZY                        //累计值转月
-	DATA_SOURCE_CALCULATE_TBZ                          //同比值
-	DATA_SOURCE_CALCULATE_TCZ                          //同差值
-	DATA_SOURCE_CALCULATE_NSZYDPJJS                    //N数值移动平均计算
-	DATA_SOURCE_MANUAL                                 //手工指标
-	DATA_SOURCE_LZ                                     //隆众
-	DATA_SOURCE_YS                                     //有色
-	DATA_SOURCE_CALCULATE_HBZ                          //环比值->12
-	DATA_SOURCE_CALCULATE_HCZ                          //环差值->13
-	DATA_SOURCE_CALCULATE_BP                           //变频->14
-	DATA_SOURCE_GL                                     //钢联->15
-	DATA_SOURCE_ZZ                                     //郑商所->16
-	DATA_SOURCE_DL                                     //大商所->17
-	DATA_SOURCE_SH                                     //上期所->18
-	DATA_SOURCE_CFFEX                                  //中金所->19
-	DATA_SOURCE_SHFE                                   //上期能源->20
-	DATA_SOURCE_GIE                                    //欧洲天然气->21
-	DATA_SOURCE_CALCULATE_TIME_SHIFT                   //时间移位->22
-	DATA_SOURCE_CALCULATE_ZJPJ                         //直接拼接->23
-	DATA_SOURCE_CALCULATE_LJZTBPJ                      //累计值同比拼接->24
-	DATA_SOURCE_LT                                     //路透->25
-	DATA_SOURCE_COAL                                   //煤炭网->26
-	DATA_SOURCE_PYTHON                                 //python代码->27
-	DATA_SOURCE_PB_FINANCE                             //彭博财务数据->28
-	DATA_SOURCE_GOOGLE_TRAVEL                          //谷歌出行数据->29
-	DATA_SOURCE_PREDICT                                //普通预测指标->30
-	DATA_SOURCE_PREDICT_CALCULATE                      //预测指标运算->31
-	DATA_SOURCE_PREDICT_CALCULATE_TBZ                  //预测指标 - 同比值->32
-	DATA_SOURCE_PREDICT_CALCULATE_TCZ                  //预测指标 - 同差值->33
-	DATA_SOURCE_MYSTEEL_CHEMICAL                       //钢联化工->34
-	DATA_SOURCE_CALCULATE_CJJX                         //超季节性->35
-	DATA_SOURCE_EIA_STEO                               //eia steo报告->36
-	DATA_SOURCE_CALCULATE_NHCC                         //计算指标(拟合残差)->37
-	DATA_SOURCE_COM_TRADE                              //联合国商品贸易数据->38
-	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
+	DATA_SOURCE_THS                          = iota + 1 //同花顺
+	DATA_SOURCE_WIND                                    //wind
+	DATA_SOURCE_PB                                      //彭博
+	DATA_SOURCE_CALCULATE                               //指标运算
+	DATA_SOURCE_CALCULATE_LJZZY                         //累计值转月
+	DATA_SOURCE_CALCULATE_TBZ                           //同比值
+	DATA_SOURCE_CALCULATE_TCZ                           //同差值
+	DATA_SOURCE_CALCULATE_NSZYDPJJS                     //N数值移动平均计算
+	DATA_SOURCE_MANUAL                                  //手工指标
+	DATA_SOURCE_LZ                                      //隆众
+	DATA_SOURCE_YS                                      //有色
+	DATA_SOURCE_CALCULATE_HBZ                           //环比值->12
+	DATA_SOURCE_CALCULATE_HCZ                           //环差值->13
+	DATA_SOURCE_CALCULATE_BP                            //变频->14
+	DATA_SOURCE_GL                                      //钢联->15
+	DATA_SOURCE_ZZ                                      //郑商所->16
+	DATA_SOURCE_DL                                      //大商所->17
+	DATA_SOURCE_SH                                      //上期所->18
+	DATA_SOURCE_CFFEX                                   //中金所->19
+	DATA_SOURCE_SHFE                                    //上期能源->20
+	DATA_SOURCE_GIE                                     //欧洲天然气->21
+	DATA_SOURCE_CALCULATE_TIME_SHIFT                    //时间移位->22
+	DATA_SOURCE_CALCULATE_ZJPJ                          //直接拼接->23
+	DATA_SOURCE_CALCULATE_LJZTBPJ                       //累计值同比拼接->24
+	DATA_SOURCE_LT                                      //路透->25
+	DATA_SOURCE_COAL                                    //煤炭网->26
+	DATA_SOURCE_PYTHON                                  //python代码->27
+	DATA_SOURCE_PB_FINANCE                              //彭博财务数据->28
+	DATA_SOURCE_GOOGLE_TRAVEL                           //谷歌出行数据->29
+	DATA_SOURCE_PREDICT                                 //普通预测指标->30
+	DATA_SOURCE_PREDICT_CALCULATE                       //预测指标运算->31
+	DATA_SOURCE_PREDICT_CALCULATE_TBZ                   //预测指标 - 同比值->32
+	DATA_SOURCE_PREDICT_CALCULATE_TCZ                   //预测指标 - 同差值->33
+	DATA_SOURCE_MYSTEEL_CHEMICAL                        //钢联化工->34
+	DATA_SOURCE_CALCULATE_CJJX                          //超季节性->35
+	DATA_SOURCE_EIA_STEO                                //eia steo报告->36
+	DATA_SOURCE_CALCULATE_NHCC                          //计算指标(拟合残差)->37
+	DATA_SOURCE_COM_TRADE                               //联合国商品贸易数据->38
+	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
+	DATA_SOURCE_CALCULATE_JP                            //变频->51
 )
 
-//基础数据初始化日期
+// 基础数据初始化日期
 var (
 	BASE_START_DATE         = time.Now().AddDate(-30, 0, 0).Format(FormatDate)        //基础数据开始日期
 	BASE_END_DATE           = time.Now().AddDate(4, 0, 0).Format(FormatDate)          //基础数据结束日期
@@ -112,7 +113,7 @@ const (
 	CHART_PREFIX = "hz_chart"
 )
 
-//数据刷新频率
+// 数据刷新频率
 const (
 	DATA_REFRESH        = 7 //7个单位,日/周/月/季度/年
 	DATA_END_DATE_LIMIT = 4 //数据结束日期为,当前日期,加上4年时间