Jelajahi Sumber

Merge branch 'feature/eta1.6.5_edb_calculate' into debug

# Conflicts:
#	utils/constants.go
xyxie 1 tahun lalu
induk
melakukan
fdd62d8ccc

+ 135 - 141
controllers/base_from_calculate.go

@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"strconv"
 	"strings"
+	"sync"
 	"time"
 )
 
@@ -68,13 +69,6 @@ func (this *CalculateController) Add() {
 		br.Msg = "请填写指标"
 		return
 	}
-	calculateFormula := req.CalculateFormula
-	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
-	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
-	calculateFormula = strings.Replace(calculateFormula, ",", ",", -1)
-	calculateFormula = strings.Replace(calculateFormula, "。", ".", -1)
-	calculateFormula = strings.Replace(calculateFormula, "%", "*0.01", -1)
-	req.CalculateFormula = calculateFormula
 
 	//加入缓存机制,避免创建同一个名称的指标 start
 	redisKey := fmt.Sprint("edb_lib:edb_info:calculate:add:", utils.DATA_SOURCE_CALCULATE, ":", req.EdbName)
@@ -90,140 +84,20 @@ func (this *CalculateController) Add() {
 		}()
 	}
 
-	//判断是否重复指标
-	edbInfoMap := make(map[int]string)
-	//移除研究员选择指标中的未使用的指标
-	{
-		//转大写的计算公式
-		upperCalculateFormulaStr := strings.ToUpper(req.CalculateFormula)
-		//用到的指标
-		newEdbInfoIdArr := make([]models.EdbInfoFromTag, 0)
-		for _, tmpEdbInfo := range req.EdbInfoIdArr {
-			_, ok := edbInfoMap[tmpEdbInfo.EdbInfoId]
-			if ok {
-				br.Msg = "选择指标失败,请勿选择重复指标!"
-				return
-			}
-			edbInfoMap[tmpEdbInfo.EdbInfoId] = tmpEdbInfo.FromTag
-
-			upperFromTag := strings.ToUpper(tmpEdbInfo.FromTag)
-			if strings.Contains(upperCalculateFormulaStr, upperFromTag) {
-				newEdbInfoIdArr = append(newEdbInfoIdArr, tmpEdbInfo)
-			}
-		}
-		req.EdbInfoIdArr = newEdbInfoIdArr
-	}
-
-	var condition string
-	var pars []interface{}
-	condition += " AND edb_name=? "
-	pars = append(pars, req.EdbName)
-
-	count, err := models.GetEdbInfoCountByCondition(condition, pars)
-	if err != nil {
-		br.Msg = "判断指标名称是否存在失败"
-		br.ErrMsg = "判断指标名称是否存在失败,Err:" + err.Error()
-		return
-	}
-
-	if count > 0 {
-		br.Msg = "指标名称已存在,请重新填写"
-		br.ErrMsg = "指标名称已存在,请重新填写"
-		br.IsSendEmail = false
-		return
-	}
-	//检验公式
-	var formulaStr string
-	var edbInfoIdBytes []string
-	for _, v := range req.EdbInfoIdArr {
-		formulaStr += v.FromTag + ","
-		edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
-	}
-	formulaSlice, err := utils.CheckFormulaJson(req.CalculateFormula)
+	// 新增
+	edbInfo, uniqueCode, err, errMsg := services.EdbCalculateAdd(req)
 	if err != nil {
-		br.Msg = "公式格式错误,请重新填写"
+		br.Msg = err.Error()
+		br.ErrMsg = errMsg
 		return
 	}
-	for _, formula := range formulaSlice {
-		formulaMap := utils.CheckFormula(formula)
-		for _, v := range formulaMap {
-			if !strings.Contains(formulaStr, v) {
-				br.Msg = "公式错误,请重新填写"
-				return
-			}
-		}
-	}
-
-	//关联的指标信息
-	edbInfoList := make([]*models.EdbInfo, 0)
-	//关联的指标数据表
-	calculateMappingList := make([]*models.EdbInfoCalculateMapping, 0)
-	for k, v := range req.EdbInfoIdArr {
-		fromEdbInfo, err := models.GetEdbInfoById(v.EdbInfoId)
-		if err != nil {
-			if err.Error() == utils.ErrNoRow() {
-				br.Msg = "生成计算指标失败"
-				br.Msg = "指标 " + strconv.Itoa(v.EdbInfoId) + " 不存在"
-				return
-			}
-			br.Msg = "生成计算指标失败"
-			br.Msg = "获取指标失败:Err:" + err.Error()
-			return
-		}
-
-		edbInfoList = append(edbInfoList, fromEdbInfo)
-		//关联关系表
-		{
-			calculateMappingItem := &models.EdbInfoCalculateMapping{
-				EdbInfoCalculateMappingId: 0,
-				EdbInfoId:                 0,
-				Source:                    utils.DATA_SOURCE_CALCULATE,
-				SourceName:                "指标运算",
-				EdbCode:                   "",
-				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
-				FromEdbCode:               fromEdbInfo.EdbCode,
-				FromEdbName:               fromEdbInfo.EdbName,
-				FromSource:                fromEdbInfo.Source,
-				FromSourceName:            fromEdbInfo.SourceName,
-				FromTag:                   v.FromTag,
-				Sort:                      k + 1,
-				CreateTime:                time.Now(),
-				ModifyTime:                time.Now(),
-			}
-			//calculateMappingItem.EdbCode = edbCode
-			//calculateMappingItem.EdbInfoId = int(edbInfoId)
-			calculateMappingList = append(calculateMappingList, calculateMappingItem)
-		}
-	}
-
-	for _, v := range formulaSlice {
-		formulaMap := utils.CheckFormula(v)
-		//预先计算,判断公式是否正常
-		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
-		if !ok {
-			br.Msg = "生成计算指标失败,请使用正确的计算公式"
-			return
-		}
-	}
-
-	randStr := utils.GetRandDigit(4)
-	edbCode := `C` + time.Now().Format("060102") + randStr
-	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
-	uniqueCode := utils.MD5(utils.DATA_PREFIX + "_" + timestamp)
 
-	// 新增计算指标
-	edbInfo, err := models.AddCalculateInfo(req, calculateMappingList, edbInfoList, edbCode, uniqueCode, edbInfoIdBytes)
-	if err != nil {
-		br.Msg = "生成计算指标失败"
-		br.Msg = "生成计算指标失败,AddEdbInfo Err:" + err.Error()
-		return
-	}
 	//处理同名指标
 	{
-		edbNameList, err := models.GetEdbInfoByName(req.EdbName)
-		if err != nil {
-			br.Msg = "保存失败"
-			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		edbNameList, e := models.GetEdbInfoByName(req.EdbName)
+		if e != nil {
+			err = fmt.Errorf("保存失败")
+			errMsg = "获取指标信息失败,Err:" + e.Error()
 			return
 		}
 		if len(edbNameList) >= 2 {
@@ -231,8 +105,8 @@ func (this *CalculateController) Add() {
 				edbName := v.EdbName + "(" + v.SourceName + ")"
 				err = models.ModifyEdbInfoNameSource(edbName, v.EdbInfoId)
 				if err != nil {
-					br.Msg = "保存失败"
-					br.ErrMsg = "修改指标名称失败,Err:" + err.Error()
+					errMsg = "修改指标名称失败,Err:" + err.Error()
+					err = fmt.Errorf("保存失败")
 					return
 				}
 			}
@@ -240,10 +114,8 @@ func (this *CalculateController) Add() {
 	}
 
 	// 更新指标最大最小值
-	err, errMsg := models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	err, errMsg = models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
 	if err != nil {
-		br.Msg = errMsg
-		br.ErrMsg = err.Error()
 		return
 	}
 	resp := models.AddEdbInfoResp{
@@ -424,7 +296,11 @@ func (this *CalculateController) Edit() {
 		return
 	}
 	for _, formula := range formulaSlice {
-		formulaMap := utils.CheckFormula(formula)
+		formulaMap, e := utils.CheckFormula(formula)
+		if e != nil {
+			br.Msg = "公式错误,请重新填写"
+			return
+		}
 		for _, v := range formulaMap {
 			if !strings.Contains(formulaStr, v) {
 				br.Msg = "公式错误,请重新填写"
@@ -2187,3 +2063,121 @@ func (this *CalculateController) Calculate() {
 	}
 	br.IsAddLog = true
 }
+
+// BatchSaveMulti
+// @Title 批量计算 累计值转月-同比值-同差等计算新增
+// @Description 批量计算 累计值转月-同比值-同差等计算新增接口
+// @Param request body models.EdbInfoCalculateBatchSaveReq true "type json string"
+// @Success Ret=200 返回指标id
+// @router /batch/save/multi [post]
+func (this *CalculateController) BatchSaveMulti() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.CalculateBatchSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	resp := models.BatchEdbInfoCalculateBatchSaveResp{
+		Fail:    make([]models.BatchEdbInfoCalculateBatchSaveFailResp, 0),
+		Success: make([]models.BatchEdbInfoCalculateBatchSaveSuccessResp, 0),
+	}
+
+	redisKeyList := make([]string, 0) //需要清理的缓存key列表
+	defer func() {
+		for _, redisKey := range redisKeyList {
+			utils.Rc.Delete(redisKey)
+		}
+	}()
+	var wg sync.WaitGroup
+	// 校验参数
+	for _, item := range req.EdbList {
+		calculateId := item.CalculateId
+		//加入缓存机制,避免创建同一个名称的指标 start
+		redisKey := fmt.Sprint("edb_info:calculate:batch:save:", req.AdminId, ":", req.Source, ":", calculateId)
+		isExist := utils.Rc.IsExist(redisKey)
+		if isExist {
+			resp.Fail = append(resp.Fail, models.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: calculateId,
+				Msg:         "指标正在处理,请勿重复提交",
+			})
+			continue
+		} else {
+			//设置3分钟缓存
+			utils.Rc.SetNX(redisKey, 1, time.Second*300)
+			redisKeyList = append(redisKeyList, redisKey)
+		}
+		wg.Add(1)
+		reqItem := models.EdbInfoCalculateBatchSaveReq{
+			AdminId:          req.AdminId,
+			AdminName:        req.AdminName,
+			EdbInfoId:        item.EdbInfoId,
+			EdbName:          item.EdbName,
+			Frequency:        item.Frequency,
+			Unit:             item.Unit,
+			ClassifyId:       item.ClassifyId,
+			Formula:          req.Formula, //N数值移动平均计算、环比值、环差值
+			FromEdbInfoId:    item.FromEdbInfoId,
+			CalculateFormula: req.CalculateFormula,
+			Source:           req.Source,
+			MoveType:         req.MoveType,
+			MoveFrequency:    req.MoveFrequency,
+			EdbInfoIdArr:     req.EdbInfoIdArr,
+			Calendar:         req.Calendar,
+			EmptyType:        req.EmptyType,
+			MaxEmptyType:     req.MaxEmptyType,
+			Extra:            req.Extra,
+		}
+		var errMsg string
+
+		uniqueCode := ""
+		go func() {
+			defer func() {
+				// todo 批量报错处理
+				if err != nil {
+					// 整理报错的指标
+					utils.FileLog.Info(fmt.Sprintf("批量指标计算,保存失败 Err:%v, ErrMsg:%s", err, errMsg))
+					resp.Fail = append(resp.Fail, models.BatchEdbInfoCalculateBatchSaveFailResp{
+						CalculateId: calculateId,
+						Msg:         err.Error(),
+						ErrMsg:      errMsg,
+					})
+				} else {
+					// 整理成功的指标
+					//todo 整理执行成功指标信息
+					resp.Success = append(resp.Success, models.BatchEdbInfoCalculateBatchSaveSuccessResp{
+						ClassifyId:  reqItem.ClassifyId,
+						CalculateId: calculateId,
+						EdbInfoId:   reqItem.EdbInfoId,
+						UniqueCode:  uniqueCode,
+					})
+				}
+				wg.Done()
+			}()
+
+			uniqueCode, err, errMsg = services.EdbCalculateBatchSave(reqItem)
+			return
+		}()
+	}
+	wg.Wait()
+	if err != nil {
+		br.Msg = "批量指标计算,保存失败"
+		br.ErrMsg = "批量指标计算,保存失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}

+ 20 - 4
controllers/base_from_predict_calculate.go

@@ -112,7 +112,11 @@ func addPredictCalculate(br *models.BaseResponse, req models.EdbInfoCalculateSav
 		return
 	}
 	for _, formula := range formulaSlice {
-		formulaMap := utils.CheckFormula(formula)
+		formulaMap, e := utils.CheckFormula(formula)
+		if e != nil {
+			br.Msg = "公式错误,请重新填写"
+			return
+		}
 		for _, v := range formulaMap {
 			if !strings.Contains(formulaStr, v) {
 				br.Msg = "公式错误,请重新填写"
@@ -181,7 +185,11 @@ func addPredictCalculate(br *models.BaseResponse, req models.EdbInfoCalculateSav
 	}
 
 	for _, v := range formulaSlice {
-		formulaMap := utils.CheckFormula(v)
+		formulaMap, e := utils.CheckFormula(v)
+		if e != nil {
+			br.Msg = "公式错误,请重新填写"
+			return
+		}
 		//预先计算,判断公式是否正常
 		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
 		if !ok {
@@ -352,7 +360,11 @@ func editPredictCalculate(br *models.BaseResponse, req models.EdbInfoCalculateSa
 		return
 	}
 	for _, formula := range formulaSlice {
-		formulaMap := utils.CheckFormula(formula)
+		formulaMap, e := utils.CheckFormula(formula)
+		if e != nil {
+			br.Msg = "公式错误,请重新填写"
+			return
+		}
 		for _, v := range formulaMap {
 			if !strings.Contains(formulaStr, v) {
 				br.Msg = "公式错误,请重新填写"
@@ -427,7 +439,11 @@ func editPredictCalculate(br *models.BaseResponse, req models.EdbInfoCalculateSa
 		}
 	}
 	for _, v := range formulaSlice {
-		formulaMap := utils.CheckFormula(v)
+		formulaMap, e := utils.CheckFormula(v)
+		if e != nil {
+			br.Msg = "公式错误,请重新填写"
+			return
+		}
 		//预先计算,判断公式是否正常
 		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
 		if !ok {

+ 26 - 5
logic/predict_edb.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"eta/eta_index_lib/models"
 	"eta/eta_index_lib/utils"
+	"fmt"
 	"strconv"
 	"strings"
 	"time"
@@ -206,7 +207,11 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName, dataDateType st
 				return
 			}
 			for _, fm := range formulaSlice {
-				formulaMap := utils.CheckFormula(fm)
+				formulaMap, e := utils.CheckFormula(fm)
+				if e != nil {
+					err = fmt.Errorf("公式错误,请重新填写")
+					return
+				}
 				for _, f := range formulaMap {
 					if !strings.Contains(formulaStr, f) {
 						errMsg = "公式错误,请重新填写"
@@ -278,7 +283,11 @@ func AddPredictEdbInfo(sourceEdbInfoId, classifyId int, edbName, dataDateType st
 				trendsMappingList = append(trendsMappingList, tmpPredictEdbConfCalculateMapping)
 			}
 			for _, f := range formulaSlice {
-				formulaMap := utils.CheckFormula(f)
+				formulaMap, e := utils.CheckFormula(f)
+				if e != nil {
+					err = fmt.Errorf("公式错误,请重新填写")
+					return
+				}
 				//预先计算,判断公式是否正常
 				ok, _ := models.CheckFormula2(edbInfoList, formulaMap, f, edbInfoIdBytes)
 				if !ok {
@@ -590,7 +599,11 @@ func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string,
 				return
 			}
 			for _, fm := range formulaSlice {
-				formulaMap := utils.CheckFormula(fm)
+				formulaMap, e := utils.CheckFormula(fm)
+				if e != nil {
+					err = fmt.Errorf("公式错误,请重新填写")
+					return
+				}
 				for _, f := range formulaMap {
 					if !strings.Contains(formulaStr, f) {
 						errMsg = "公式错误,请重新填写"
@@ -663,7 +676,11 @@ func EditPredictEdbInfo(edbInfoId, classifyId int, edbName, dataDateType string,
 			}
 
 			for _, f := range formulaSlice {
-				formulaMap := utils.CheckFormula(f)
+				formulaMap, e := utils.CheckFormula(f)
+				if e != nil {
+					err = fmt.Errorf("公式错误,请重新填写")
+					return
+				}
 				//预先计算,判断公式是否正常
 				ok, _ := models.CheckFormula2(edbInfoList, formulaMap, f, edbInfoIdBytes)
 				if !ok {
@@ -907,7 +924,11 @@ func RefreshPredictEdbInfo(edbInfoId int) (edbInfo *models.EdbInfo, err error, e
 				return
 			}
 			for _, fm := range formulaSlice {
-				formulaMap := utils.CheckFormula(fm)
+				formulaMap, e := utils.CheckFormula(fm)
+				if e != nil {
+					err = fmt.Errorf("公式错误,请重新填写")
+					return
+				}
 				for _, f := range formulaMap {
 					if !strings.Contains(formulaStr, f) {
 						errMsg = "公式错误,请重新填写"

+ 62 - 3
models/base_from_calculate.go

@@ -202,7 +202,11 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaSli
 		}
 
 		for _, v := range formulaSlice {
-			formulaMap := utils.CheckFormula(v)
+			formulaMap, e := utils.CheckFormula(v)
+			if e != nil {
+				err = fmt.Errorf("公式错误,请重新填写")
+				return
+			}
 			//预先计算,判断公式是否正常
 			ok, _ := CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
 			if !ok {
@@ -432,7 +436,11 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoTag map
 			if sk < fv {
 				if f, ok := formulaDateMap[fv]; ok {
 					formulaStr = f
-					formulaMap = utils.CheckFormula(formulaStr)
+					formulaMap, err = utils.CheckFormula(formulaStr)
+					if err != nil {
+						err = fmt.Errorf("公式错误,请重新填写")
+						return
+					}
 				}
 				break
 			}
@@ -613,6 +621,34 @@ func GetFormulaMap() map[string]string {
 	return funMap
 }
 
+// CalculateBatchSaveReq 添加计算指标的请求参数
+type CalculateBatchSaveReq struct {
+	EdbList          []*CalculateEdbInfoItem        //需要批量计算的指标列表
+	AdminId          int                            `description:"添加人id"`
+	AdminName        string                         `description:"添加人名称"`
+	Formula          string                         `description:"N值/移动天数"`
+	Source           int                            `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:升频"`
+	CalculateFormula string                         `description:"计算公式"`
+	EdbInfoIdArr     []EdbInfoCalculateEdbInfoIdReq `description:"关联指标列表"`
+	MoveType         int                            `description:"移动方式:1:领先(默认),2:滞后"`
+	MoveFrequency    string                         `description:"移动频度:天/周/月/季/年"`
+	Calendar         string                         `description:"公历/农历"`
+	Data             interface{}                    `description:"数据"`
+	EmptyType        int                            `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                            `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string                         `description:"指标额外配置"`
+}
+
+type CalculateEdbInfoItem struct {
+	EdbInfoId     int    `description:"指标id"`
+	EdbName       string `description:"指标名称"`
+	Frequency     string `description:"频度"`
+	Unit          string `description:"单位"`
+	ClassifyId    int    `description:"分类id"`
+	CalculateId   string `description:"当前请求时,单个计算的唯一标识"`
+	FromEdbInfoId int    `description:"计算来源指标id"`
+}
+
 // EdbInfoCalculateBatchSaveReq 添加计算指标的请求参数
 type EdbInfoCalculateBatchSaveReq struct {
 	AdminId          int                            `description:"添加人id"`
@@ -631,7 +667,9 @@ type EdbInfoCalculateBatchSaveReq struct {
 	MoveFrequency    string                         `description:"移动频度:天/周/月/季/年"`
 	Calendar         string                         `description:"公历/农历"`
 	Data             interface{}                    `description:"数据"`
-	Extra            string                         `description:"指标的额外配置"`
+	EmptyType        int                            `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                            `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string                         `description:"指标额外配置"`
 }
 
 // EdbInfoCalculateEdbInfoIdReq 新增/编辑请求 关联的指标列表
@@ -916,3 +954,24 @@ type PredictRuleCalculateByNineResp struct {
 	LatestDate string
 	DataList   interface{}
 }
+
+// BatchEdbInfoCalculateBatchSaveResp 批量添加 计算指标 返回数据
+type BatchEdbInfoCalculateBatchSaveResp struct {
+	Fail    []BatchEdbInfoCalculateBatchSaveFailResp    `description:"添加失败的指标"`
+	Success []BatchEdbInfoCalculateBatchSaveSuccessResp `description:"添加成功的指标"`
+}
+
+// BatchEdbInfoCalculateBatchSaveFailResp 添加失败的指标信息
+type BatchEdbInfoCalculateBatchSaveFailResp struct {
+	CalculateId string `description:"当前请求时,单个计算的唯一标识"`
+	Msg         string `description:"用户提示信息"`
+	ErrMsg      string `description:"错误信息,内部查看"`
+}
+
+// BatchEdbInfoCalculateBatchSaveSuccessResp 添加成功的指标信息
+type BatchEdbInfoCalculateBatchSaveSuccessResp struct {
+	ClassifyId  int    `description:"分类id"`
+	CalculateId string `description:"当前请求时,单个计算的唯一标识"`
+	EdbInfoId   int    `description:"指标ID"`
+	UniqueCode  string `description:"指标唯一编码"`
+}

+ 5 - 1
models/base_predict_from_calculate.go

@@ -394,7 +394,11 @@ func refreshAllPredictCalculate(to orm.TxOrmer, edbInfoIdList []*EdbInfo, edbInf
 			if sk < fv {
 				if f, ok := formulaDateMap[fv]; ok {
 					formulaStr = f
-					formulaMap = utils.CheckFormula(formulaStr)
+					formulaMap, err = utils.CheckFormula(formulaStr)
+					if err != nil {
+						err = fmt.Errorf("公式错误,请重新填写")
+						return
+					}
 				}
 				break
 			}

+ 418 - 0
models/edb_data_calculate_sum.go

@@ -0,0 +1,418 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type CalculateSum struct {
+}
+
+// Add 新增
+func (obj CalculateSum) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error, errMsg string) {
+	req := params.Req
+	edbCode := params.EdbCode
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("CalculateSum.Add,Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	if req.EdbInfoId > 0 {
+		err = errors.New("无法新增")
+		return
+	}
+
+	edbInfo = new(EdbInfo)
+	edbInfo.Source = obj.GetSource()
+	edbInfo.SourceName = obj.GetSourceName()
+	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 = params.SysUserId
+	edbInfo.SysUserRealName = params.SysUserRealName
+	edbInfo.CreateTime = time.Now()
+	edbInfo.ModifyTime = time.Now()
+	edbInfo.UniqueCode = params.UniqueCode
+	edbInfo.EdbType = obj.GetEdbType()
+	newEdbInfoId, tmpErr := to.Insert(edbInfo)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	edbInfo.EdbInfoId = int(newEdbInfoId)
+
+	//关联关系
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, e := GetEdbInfoById(v.EdbInfoId)
+		if e != nil {
+			err = e
+			return
+		}
+		relationEdbInfoList = append(relationEdbInfoList, 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
+		calculateMappingItem.FromSubSource = edbInfo.SubSource
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+
+		tagMap[v.FromTag] = v.EdbInfoId
+	}
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, relationEdbInfoList, edbInfo.EdbCode, edbInfo.Extra, tagMap, edbInfo.EmptyType)
+
+	return
+}
+
+func (obj CalculateSum) Edit(edbInfo *EdbInfo, req *EdbInfoCalculateBatchEditReq) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("EditCalculateKszs,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, edbInfo.SubSource)
+	sql = ` DELETE FROM ` + tableName + ` WHERE edb_info_id = ? `
+	_, err = to.Raw(sql, edbInfo.EdbInfoId).Exec()
+	if err != nil {
+		return
+	}
+
+	//关联关系
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	calculateMappingItemList := make([]*EdbInfoCalculateMapping, 0)
+	for _, v := range req.EdbInfoIdArr {
+		tmpEdbInfo, tmpErr := GetEdbInfoById(v.EdbInfoId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		relationEdbInfoList = append(relationEdbInfoList, 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
+		calculateMappingItem.FromSubSource = edbInfo.SubSource
+		calculateMappingItemList = append(calculateMappingItemList, calculateMappingItem)
+
+		tagMap[v.FromTag] = v.EdbInfoId
+	}
+	_, err = to.InsertMulti(len(calculateMappingItemList), calculateMappingItemList)
+	if err != nil {
+		return
+	}
+
+	//计算数据
+	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, relationEdbInfoList, edbInfo.EdbCode, edbInfo.Extra, tagMap, edbInfo.EmptyType)
+
+	return
+}
+
+func (obj CalculateSum) Refresh(edbInfo *EdbInfo) (err error) {
+	edbInfoCalculateDetailList, err := GetEdbInfoCalculateDetailList(edbInfo.EdbInfoId)
+	if err != nil {
+		return
+	}
+	tagMap := make(map[string]int)
+	relationEdbInfoList := make([]*EdbInfo, 0)
+	for _, v := range edbInfoCalculateDetailList {
+		tagMap[v.FromTag] = v.FromEdbInfoId
+		fromEdbInfo, _ := GetEdbInfoById(v.FromEdbInfoId)
+		relationEdbInfoList = append(relationEdbInfoList, fromEdbInfo)
+	}
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println(reflect.TypeOf(obj).Name() + ",Err:" + err.Error())
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 计算数据
+	err = obj.refresh(to, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, relationEdbInfoList, edbInfo.EdbCode, edbInfo.Extra, tagMap, edbInfo.EmptyType)
+
+	return
+}
+
+func (obj CalculateSum) refresh(to orm.TxOrmer, edbInfoId, source, subSource int, edbInfoIdArr []*EdbInfo, edbCode, extra string, edbInfoTag map[string]int, emptyType int) (err error) {
+	realSaveDataMap := make(map[string]map[int]float64)
+	saveDataMap := make(map[string]map[int]float64)
+
+	// 最小的结束日期 , 最晚的数据开始日期
+	var minLatestDate, maxStartDate time.Time
+	dateList := make([]string, 0)        // 最终的日期数据
+	dateMap := make(map[string]struct{}) // 最终的日期数据
+
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+	tableName := GetEdbDataTableName(source, subSource)
+
+	// 获取多指标求和关联的指标id
+	dateTagConfig := ""
+	if extra != "" {
+		var dateConfig CalculateEdbExtra
+		err = json.Unmarshal([]byte(extra), &dateConfig)
+		if err != nil {
+			err = fmt.Errorf("refreshAllCalculate,extra解析失败,Err:%s", err.Error())
+			return
+		}
+		dateTagConfig = dateConfig.DateTag
+	}
+
+	for edbInfoIndex, v := range edbInfoIdArr {
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id=? "
+		pars = append(pars, v.EdbInfoId)
+		dataList, err := GetEdbDataListAllByTo(to, condition, pars, v.Source, v.SubSource, 1)
+		if err != nil {
+			return err
+		}
+
+		for _, dv := range dataList {
+			if val, ok := realSaveDataMap[dv.DataTime]; ok {
+				if _, ok := val[v.EdbInfoId]; !ok {
+					val[v.EdbInfoId] = dv.Value
+				}
+			} else {
+				temp := make(map[int]float64)
+				temp[v.EdbInfoId] = dv.Value
+				realSaveDataMap[dv.DataTime] = temp
+			}
+
+			// saveDataMap
+			if val, ok := saveDataMap[dv.DataTime]; ok {
+				if _, ok := val[v.EdbInfoId]; !ok {
+					val[v.EdbInfoId] = dv.Value
+				}
+			} else {
+				temp2 := make(map[int]float64)
+				temp2[v.EdbInfoId] = dv.Value
+				saveDataMap[dv.DataTime] = temp2
+			}
+
+			if dateTagConfig == "all" {
+				if _, ok := dateMap[dv.DataTime]; !ok {
+					dateList = append(dateList, dv.DataTime)
+					dateMap[dv.DataTime] = struct{}{}
+				}
+			} else if dateTagConfig == "" { // 默认取第一个指标的时间序列
+				if edbInfoIndex == 0 {
+					if _, ok := dateMap[dv.DataTime]; !ok {
+						dateList = append(dateList, dv.DataTime)
+						dateMap[dv.DataTime] = struct{}{}
+					}
+				}
+			} else {
+				if eId, ok := edbInfoTag[dateTagConfig]; ok {
+					if v.EdbInfoId == eId {
+						if _, ok1 := dateMap[dv.DataTime]; !ok1 {
+							dateList = append(dateList, dv.DataTime)
+							dateMap[dv.DataTime] = struct{}{}
+						}
+					}
+				}
+			}
+		}
+	}
+	// 处理最大日期和最小日期
+	for _, v := range dateList {
+		tmpDate, _ := time.ParseInLocation(utils.FormatDate, v, time.Local)
+		if minLatestDate.IsZero() || tmpDate.After(minLatestDate) {
+			minLatestDate = tmpDate
+		}
+		if maxStartDate.IsZero() || tmpDate.Before(maxStartDate) {
+			maxStartDate = tmpDate
+		}
+	}
+
+	//数据处理,将日期内不全的数据做补全
+	HandleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
+
+	addSql := ` INSERT INTO ` + tableName + ` (edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+	var isAdd bool
+
+	//获取指标所有数据
+	dataList := make([]*EdbData, 0)
+	dataTableName := GetEdbDataTableName(source, subSource)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)
+	if err != nil {
+		return err
+	}
+	dataMap := make(map[string]string)
+
+	removeDateMap := make(map[string]int) //需要移除的日期
+	for _, v := range dataList {
+		dataMap[v.DataTime] = v.Value
+		removeDateMap[v.DataTime] = 1
+	}
+	existDataMap := make(map[string]string)
+
+	for sk, sv := range saveDataMap {
+		// 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值
+		if emptyType == 1 {
+			if len(sv) != len(edbInfoIdArr) {
+				continue
+			}
+		}
+
+		var calVal float64
+		for _, value := range sv {
+			calVal += value
+		}
+
+		// 有计算出来值,那么就从待删除指标中移除
+		delete(removeDateMap, sk)
+		saveValue := decimal.NewFromFloat(calVal).RoundCeil(4).String()
+		if existVal, ok := dataMap[sk]; !ok {
+			dataTime, _ := time.ParseInLocation(utils.FormatDate, sk, time.Local)
+			timestamp := dataTime.UnixNano() / 1e6
+			timeStr := fmt.Sprintf("%d", timestamp)
+
+			if _, existOk := existDataMap[sk]; !existOk {
+				addSql += GetAddSql(edbInfoIdStr, edbCode, sk, timeStr, saveValue)
+				isAdd = true
+			}
+			existDataMap[sk] = sk
+		} else {
+			existValDecimal, err := decimal.NewFromString(existVal)
+			existStr := existValDecimal.String()
+			if existStr != 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, sk).Exec()
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			fmt.Println("RefreshAllCalculate add Err", err.Error())
+			return
+		}
+	}
+
+	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
+}
+
+// GetSource 获取来源编码id
+func (obj CalculateSum) GetSource() int {
+	return utils.DATA_SOURCE_CALCULATE_SUM
+}
+
+// GetSourceName 获取来源名称
+func (obj CalculateSum) GetSourceName() string {
+	return utils.DATA_SOURCE_NAME_CALCULATE_SUM
+}
+
+// GetEdbType 获取指标类型
+func (obj CalculateSum) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}

+ 5 - 1
models/predict_edb.go

@@ -160,7 +160,11 @@ func CalculateByRuleBy9(to orm.TxOrmer, rule CalculateRule) (resultDataList []*E
 			if sk < fv {
 				if f, ok := formulaDateMap[fv]; ok {
 					formulaStr = f
-					formulaMap = utils.CheckFormula(formulaStr)
+					formulaMap, err = utils.CheckFormula(formulaStr)
+					if err != nil {
+						err = fmt.Errorf("公式错误,请重新填写")
+						return
+					}
 				}
 				break
 			}

+ 9 - 0
routers/commentsRouter.go

@@ -124,6 +124,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_index_lib/controllers:CalculateController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:CalculateController"],
+        beego.ControllerComments{
+            Method: "BatchSaveMulti",
+            Router: `/batch/save/multi`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_index_lib/controllers:CalculateController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers:CalculateController"],
         beego.ControllerComments{
             Method: "CalculateComputeCorrelation",

+ 610 - 0
services/base_from_calculate.go

@@ -0,0 +1,610 @@
+package services
+
+import (
+	"eta/eta_index_lib/logic"
+	"eta/eta_index_lib/models"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// EdbCalculateBatchSave 批量指标运算
+func EdbCalculateBatchSave(req models.EdbInfoCalculateBatchSaveReq) (uniqueCode string, err error, errMsg string) {
+	// 校验参数
+	req.EdbName = strings.Trim(req.EdbName, " ")
+	if req.EdbName == "" {
+		err = fmt.Errorf("指标名称不能为空")
+		return
+	}
+
+	if req.Frequency == "" {
+		err = fmt.Errorf("频率不能为空")
+		return
+	}
+
+	if req.Unit == "" {
+		err = fmt.Errorf("单位不能为空")
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		err = fmt.Errorf("请选择分类")
+		return
+	}
+
+	// 基础指标id
+	fromEdbInfoId := req.FromEdbInfoId
+
+	var formulaInt int
+	var nhccDate models.NhccDate // 拟合残差的日期
+	switch req.Source {
+	case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_CALCULATE_HBZ, utils.DATA_SOURCE_CALCULATE_HCZ, utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_CALCULATE_CJJX:
+		if req.Formula == "" {
+			err = fmt.Errorf("请填写N值")
+			return
+		}
+		formulaInt, _ = strconv.Atoi(req.Formula)
+		if formulaInt <= 0 {
+			err = fmt.Errorf(" N值输入错误,请重新输入")
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZJPJ:
+		//直接拼接指标
+		//校验时间格式
+		_, err = time.ParseInLocation(utils.FormatDate, req.Formula, time.Local)
+		if err != nil {
+			err = fmt.Errorf("拼接日期有误,请重新输入")
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_NHCC: //拟合残差指标
+		//指标校验
+		if len(req.EdbInfoIdArr) != 2 {
+			err = fmt.Errorf("选择的指标异常,请重新选择")
+			return
+		}
+		fromEdbInfoId = req.EdbInfoIdArr[0].EdbInfoId
+
+		//校验时间格式
+		//数据格式:2022-11-01,2022-11-10
+		timeList := strings.Split(req.Formula, ",")
+		if len(timeList) != 2 {
+			err = fmt.Errorf("选择时间有误,请重新输入")
+			return
+		}
+		startDate, e := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+		if e != nil {
+			err = fmt.Errorf("开始日期有误,请重新输入")
+			return
+		}
+		endDate, e := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+		if e != nil {
+			err = fmt.Errorf("结束日期有误,请重新输入")
+			return
+		}
+		if utils.GetTimeSubDay(startDate, endDate) < 2 {
+			err = fmt.Errorf("日期间隔不得少于两天")
+			return
+		}
+		nhccDate.StartDate = startDate
+		nhccDate.EndDate = endDate
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if req.Formula != "期末值" && req.Formula != "平均值" {
+			err = fmt.Errorf("数据取值类型错误:" + req.Formula)
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZSXY: // 指数修匀
+		if req.Formula == "" {
+			err = fmt.Errorf("请填写alpha值")
+			return
+		}
+		a, e := strconv.ParseFloat(req.Formula, 64)
+		if e != nil {
+			err = fmt.Errorf("alpha值输入错误, 请重新输入")
+			return
+		}
+		if a <= 0 || a >= 1 {
+			err = fmt.Errorf("alpha值输入错误, 请重新输入")
+			return
+		}
+	}
+
+	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS, utils.DATA_SOURCE_CALCULATE_CORRELATION, utils.DATA_SOURCE_CALCULATE_ZDYFX} // 不需要传入来源指标id的 指标类型
+	if fromEdbInfoId <= 0 && !utils.InArrayByInt(notNeedFromEdbSourceList, req.Source) {
+		err = fmt.Errorf("请选择指标")
+		return
+	}
+	//加入缓存机制,避免创建同一个名称的指标 start
+	redisKey := fmt.Sprint("edb_lib:edb_info:calculate:batch:save:", req.Source, ":", req.EdbName)
+	isExist := utils.Rc.IsExist(redisKey)
+	if isExist {
+		err = fmt.Errorf("指标正在处理,请勿重复提交")
+		return
+	} else {
+		//设置3分钟缓存
+		utils.Rc.SetNX(redisKey, 1, time.Second*300)
+		defer func() {
+			_ = utils.Rc.Delete(redisKey)
+		}()
+	}
+	//加入缓存机制,避免创建同一个名称的指标 end
+
+	var condition string
+	var pars []interface{}
+	condition += " AND edb_name=? "
+	pars = append(pars, req.EdbName)
+
+	count, err := models.GetEdbInfoCountByCondition(condition, pars)
+	if err != nil {
+		err = fmt.Errorf("判断指标名称是否存在失败")
+		errMsg = "判断指标名称是否存在失败,Err:" + err.Error()
+		return
+	}
+
+	if count > 0 {
+		err = fmt.Errorf("指标名称已存在,请重新填写")
+		errMsg = "指标名称已存在,请重新填写"
+		return
+	}
+
+	// 来源指标
+	var fromEdbInfo *models.EdbInfo
+	if fromEdbInfoId > 0 {
+		fromEdbInfo, err = models.GetEdbInfoById(fromEdbInfoId)
+		if err != nil {
+			errMsg = "获取指标信息失败:Err:" + err.Error()
+			err = fmt.Errorf("获取指标信息失败")
+			return
+		}
+	}
+
+	//生成指标编码
+	randStr := utils.GetRandDigit(4)
+	edbCode := `C` + time.Now().Format("060102") + randStr
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	uniqueCode = utils.MD5(utils.DATA_PREFIX + "_" + timestamp)
+
+	sysUserId := req.AdminId
+	sysUserName := req.AdminName
+
+	var sourName string
+	var edbInfoId int
+	var edbInfo *models.EdbInfo
+
+	var baseEdbInfoModel models.BaseEdbInfoInterface
+	addParam := models.AddCalculateBatchParams{
+		Req:             &req,
+		FromEdbInfo:     fromEdbInfo,
+		EdbCode:         edbCode,
+		UniqueCode:      uniqueCode,
+		SysUserId:       sysUserId,
+		SysUserRealName: sysUserName,
+	}
+
+	switch req.Source {
+	case utils.DATA_SOURCE_CALCULATE:
+		sourName = "计算指标"
+		req2 := models.EdbInfoCalculateSaveReq{
+			AdminId:          sysUserId,
+			AdminName:        sysUserName,
+			EdbName:          req.EdbName,
+			Frequency:        req.Frequency,
+			Unit:             req.Unit,
+			ClassifyId:       req.ClassifyId,
+			CalculateFormula: req.CalculateFormula,
+			//EdbInfoIdArr:     req.EdbInfoIdArr,
+			EmptyType:    req.EmptyType,
+			MaxEmptyType: req.MaxEmptyType,
+			Extra:        req.Extra,
+		}
+
+		// 放入A指标
+		t := models.EdbInfoFromTag{
+			EdbInfoId: req.FromEdbInfoId,
+			FromTag:   "A",
+		}
+		req2.EdbInfoIdArr = append(req2.EdbInfoIdArr, t)
+		// 放入B指标
+		if len(req.EdbInfoIdArr) > 0 {
+			t = models.EdbInfoFromTag{
+				EdbInfoId: req.EdbInfoIdArr[0].EdbInfoId,
+				FromTag:   "B",
+			}
+			req2.EdbInfoIdArr = append(req2.EdbInfoIdArr, t)
+		}
+
+		edbInfo, _, err, errMsg = EdbCalculateAdd(req2)
+	case utils.DATA_SOURCE_CALCULATE_LJZZY:
+		sourName = "累计值转月值"
+		if fromEdbInfo.Frequency != "月度" {
+			err = fmt.Errorf("请选择月度指标")
+			return
+		}
+		edbInfo, err = models.AddCalculateLjzzy(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_TBZ:
+		if req.Frequency != fromEdbInfo.Frequency {
+			err = fmt.Errorf("当前频度和原指标频度不一致")
+			return
+		}
+		if req.Unit != "无" {
+			err = fmt.Errorf("单位只允许为无,禁止选择其他单位")
+			return
+		}
+		sourName = "同比值"
+		edbInfo, err = models.AddCalculateTbz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_TCZ:
+		if req.Frequency != fromEdbInfo.Frequency {
+			err = fmt.Errorf("当前频度和原指标频度不一致")
+			return
+		}
+		if req.Unit != fromEdbInfo.Unit {
+			err = fmt.Errorf("当前单位和原指标单位不一致")
+			return
+		}
+		sourName = "同差值"
+		edbInfo, err = models.AddCalculateTcz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS:
+		sourName = "N数值移动平均计算"
+		edbInfo, err = models.AddCalculateNszydpjjs(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName, formulaInt)
+	case utils.DATA_SOURCE_CALCULATE_HBZ:
+		var condition string
+		var pars []interface{}
+		condition += " AND edb_info_id =? "
+		pars = append(pars, fromEdbInfoId)
+		condition += " AND value <=0 "
+		checkCount, tmpErr := models.GetEdbDataCount(condition, pars, fromEdbInfo.Source, fromEdbInfo.SubSource)
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			err = fmt.Errorf("判断环比值是否可计算失败")
+			errMsg = "判断环比值是否可计算失败,Err:" + tmpErr.Error()
+			return
+		}
+		if checkCount > 0 {
+			err = fmt.Errorf("原始数据中存在0或负数,该指标不能进行环比运算")
+			errMsg = "原始数据中出现0和负值时,提示该指标不能进行环比运算"
+			return
+		}
+		sourName = "环比值"
+		edbInfo, err = models.AddCalculateHbz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName, formulaInt)
+	case utils.DATA_SOURCE_CALCULATE_HCZ:
+		sourName = "环差值"
+		edbInfo, err = models.AddCalculateHcz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName, formulaInt)
+	case utils.DATA_SOURCE_CALCULATE_BP:
+		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 = "时间移位"
+		edbInfo, err = models.AddCalculateTimeShift(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_ZJPJ:
+		sourName = "直接拼接"
+
+		if len(req.EdbInfoIdArr) != 1 {
+			err = fmt.Errorf("请传入拼接日期之后的指标")
+			errMsg = "请传入拼接日期之后的指标"
+			return
+		}
+
+		secondEdbInfoReq := req.EdbInfoIdArr[0]
+		secondEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+		if tmpErr != nil {
+			err = fmt.Errorf("获取拼接日期之后的指标信息失败")
+			errMsg = "获取拼接日期之后的指标信息失败:Err:" + tmpErr.Error()
+			return
+		}
+
+		if fromEdbInfo.EdbInfoId == secondEdbInfo.EdbInfoId {
+			err = fmt.Errorf("两个指标不允许为同一个")
+			errMsg = "两个指标不允许为同一个"
+			return
+		}
+		edbInfo, err = models.AddCalculateZjpj(&req, fromEdbInfo, secondEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_LJZTBPJ:
+		sourName = "累计值同比拼接"
+
+		if fromEdbInfo.Frequency != "月度" {
+			err = fmt.Errorf("待拼接指标只能筛选月度指标")
+			errMsg = "待拼接指标只能筛选月度指标"
+			return
+		}
+		if len(req.EdbInfoIdArr) != 1 {
+			err = fmt.Errorf("请传入同比值指标")
+			errMsg = "请传入同比值指标"
+			return
+		}
+
+		secondEdbInfoReq := req.EdbInfoIdArr[0]
+		tbzEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+		if tmpErr != nil {
+			err = fmt.Errorf("获取同比值指标信息失败")
+			errMsg = "获取同比值指标信息失败:Err:" + tmpErr.Error()
+			return
+		}
+		if tbzEdbInfo.Source != utils.DATA_SOURCE_CALCULATE_TBZ {
+			err = fmt.Errorf("指标必须是传入同比值指标类型")
+			errMsg = "指标必须是传入同比值指标类型"
+			return
+		}
+		if tbzEdbInfo.Frequency != "月度" {
+			err = fmt.Errorf("同比值指标只能筛选月度指标")
+			errMsg = "同比值指标只能筛选月度指标"
+			return
+		}
+
+		if fromEdbInfo.EdbInfoId == tbzEdbInfo.EdbInfoId {
+			err = fmt.Errorf("两个指标不允许为同一个")
+			errMsg = "两个指标不允许为同一个"
+			return
+		}
+		edbInfo, err = models.AddCalculateLjztbpj(&req, fromEdbInfo, tbzEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_CJJX:
+		sourName = "超季节性"
+		edbInfo, err = models.AddCalculateCjjx(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName, formulaInt)
+	case utils.DATA_SOURCE_CALCULATE_NHCC:
+		sourName = "拟合残差"
+
+		secondEdbInfoReq := req.EdbInfoIdArr[1]
+		secondEdbInfo, tmpErr := models.GetEdbInfoById(secondEdbInfoReq.EdbInfoId)
+		if tmpErr != nil {
+			err = fmt.Errorf("获取因变量的指标信息失败")
+			errMsg = "获取因变量的指标信息失败:Err:" + tmpErr.Error()
+			return
+		}
+
+		if fromEdbInfo.EdbInfoId == secondEdbInfo.EdbInfoId {
+			err = fmt.Errorf("两个指标不允许为同一个")
+			errMsg = "两个指标不允许为同一个"
+			return
+		}
+		edbInfo, err, errMsg = models.AddCalculateNhcc(&req, fromEdbInfo, secondEdbInfo, edbCode, uniqueCode, nhccDate, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_JP:
+		if !models.CheckFrequency(fromEdbInfo.Frequency, req.Frequency) {
+			err = fmt.Errorf("频度异常,不允许低频降频到高频")
+			return
+		}
+		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)
+	case utils.DATA_SOURCE_CALCULATE_KSZS:
+		//关联的指标信息
+		if len(req.EdbInfoIdArr) < 2 {
+			err = fmt.Errorf("指标数量不能小于2个,请重新选择")
+			errMsg = "指标数量不能小于2个,请重新选择"
+			//br.IsSendEmail = false
+			return
+		}
+		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 {
+			err = fmt.Errorf("指标数量不能小于2个,请重新选择")
+			errMsg = "指标数量不能小于2个,请重新选择"
+			//br.IsSendEmail = false
+			return
+		}
+		sourName = utils.DATA_SOURCE_NAME_CALCULATE_CORRELATION
+		edbInfo, err, errMsg = models.AddCalculateCorrelation(&req, edbCode, uniqueCode, sysUserId, sysUserName)
+	case utils.DATA_SOURCE_CALCULATE_RJZ:
+		if req.Frequency == "日度" {
+			err = fmt.Errorf("日度指标无需进行日均值计算")
+			return
+		}
+		if req.Frequency != fromEdbInfo.Frequency {
+			err = fmt.Errorf("当前频度和原指标频度不一致")
+			return
+		}
+		if req.Unit != fromEdbInfo.Unit {
+			err = fmt.Errorf("单位只允许为和原指标频度保持一致,禁止选择其他单位")
+			return
+		}
+		sourName = "日均值"
+		edbInfo, err = models.AddCalculateRjz(&req, fromEdbInfo, edbCode, uniqueCode, sysUserId, sysUserName)
+	default:
+		// 获取通用的数据源处理服务
+		baseEdbInfoModel = models.GetBaseEdbInfoModel(req.Source)
+		// 没有找到的话,那么就直接返回报错吧
+		if baseEdbInfoModel == nil {
+			err = fmt.Errorf("无效计算方式")
+			errMsg = "无效计算方式,source:" + strconv.Itoa(req.Source)
+			return
+		}
+		sourName = baseEdbInfoModel.GetSourceName()
+		edbInfo, err, errMsg = baseEdbInfoModel.Add(addParam)
+	}
+
+	if err != nil {
+		errMsg = "生成" + sourName + "失败 Err:" + err.Error() + errMsg
+		err = fmt.Errorf("生成" + sourName + "失败")
+		return
+	}
+
+	if edbInfo == nil {
+		err = fmt.Errorf("生成" + sourName + "失败")
+		errMsg = "生成" + sourName + "失败,指标ID错误:" + strconv.Itoa(edbInfoId)
+		return
+	}
+	edbInfoId = edbInfo.EdbInfoId
+
+	//处理同名指标
+	{
+		edbNameList, tErr := models.GetEdbInfoByName(req.EdbName)
+		if tErr != nil {
+			err = fmt.Errorf("保存失败")
+			errMsg = "获取指标信息失败,Err:" + tErr.Error()
+			return
+		}
+		if len(edbNameList) >= 2 {
+			for _, v := range edbNameList {
+				edbName := v.EdbName + "(" + v.SourceName + ")"
+				err = models.ModifyEdbInfoNameSource(edbName, v.EdbInfoId)
+				if err != nil {
+					errMsg = "修改指标名称失败,Err:" + err.Error()
+					err = fmt.Errorf("保存失败")
+					return
+				}
+			}
+		}
+	}
+
+	// 更新指标最大最小值
+	err, errMsg = models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	if err != nil {
+		return
+	}
+
+	// 更新ES
+	go logic.UpdateEs(edbInfo.EdbInfoId)
+	return
+}
+
+// EdbCalculateAdd 新增指标运算
+func EdbCalculateAdd(req models.EdbInfoCalculateSaveReq) (edbInfo *models.EdbInfo, uniqueCode string, err error, errMsg string) {
+	calculateFormula := req.CalculateFormula
+	calculateFormula = strings.Replace(calculateFormula, "(", "(", -1)
+	calculateFormula = strings.Replace(calculateFormula, ")", ")", -1)
+	calculateFormula = strings.Replace(calculateFormula, ",", ",", -1)
+	calculateFormula = strings.Replace(calculateFormula, "。", ".", -1)
+	calculateFormula = strings.Replace(calculateFormula, "%", "*0.01", -1)
+	req.CalculateFormula = calculateFormula
+
+	//判断是否重复指标
+	edbInfoMap := make(map[int]string)
+	//移除研究员选择指标中的未使用的指标
+	{
+		//转大写的计算公式
+		upperCalculateFormulaStr := strings.ToUpper(req.CalculateFormula)
+		//用到的指标
+		newEdbInfoIdArr := make([]models.EdbInfoFromTag, 0)
+		for _, tmpEdbInfo := range req.EdbInfoIdArr {
+			_, ok := edbInfoMap[tmpEdbInfo.EdbInfoId]
+			if ok {
+				err = fmt.Errorf("选择指标失败,请勿选择重复指标!")
+				return
+			}
+			edbInfoMap[tmpEdbInfo.EdbInfoId] = tmpEdbInfo.FromTag
+
+			upperFromTag := strings.ToUpper(tmpEdbInfo.FromTag)
+			if strings.Contains(upperCalculateFormulaStr, upperFromTag) {
+				newEdbInfoIdArr = append(newEdbInfoIdArr, tmpEdbInfo)
+			}
+		}
+		req.EdbInfoIdArr = newEdbInfoIdArr
+	}
+
+	var condition string
+	var pars []interface{}
+	condition += " AND edb_name=? "
+	pars = append(pars, req.EdbName)
+
+	count, err := models.GetEdbInfoCountByCondition(condition, pars)
+	if err != nil {
+		errMsg = "判断指标名称是否存在失败,Err:" + err.Error()
+		err = fmt.Errorf("判断指标名称是否存在失败")
+		return
+	}
+
+	if count > 0 {
+		err = fmt.Errorf("指标名称已存在,请重新填写")
+		errMsg = "指标名称已存在,请重新填写"
+		//br.IsSendEmail = false
+		return
+	}
+	//检验公式
+	var formulaStr string
+	var edbInfoIdBytes []string
+	for _, v := range req.EdbInfoIdArr {
+		formulaStr += v.FromTag + ","
+		edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
+	}
+	formulaSlice, err := utils.CheckFormulaJson(req.CalculateFormula)
+	if err != nil {
+		err = fmt.Errorf("公式格式错误,请重新填写")
+		return
+	}
+	for _, formula := range formulaSlice {
+		formulaMap, e := utils.CheckFormula(formula)
+		if e != nil {
+			err = fmt.Errorf("公式错误,请重新填写")
+			return
+		}
+		for _, v := range formulaMap {
+			if !strings.Contains(formulaStr, v) {
+				err = fmt.Errorf("公式错误,请重新填写")
+				return
+			}
+		}
+	}
+
+	//关联的指标信息
+	edbInfoList := make([]*models.EdbInfo, 0)
+	//关联的指标数据表
+	calculateMappingList := make([]*models.EdbInfoCalculateMapping, 0)
+	for k, v := range req.EdbInfoIdArr {
+		fromEdbInfo, e := models.GetEdbInfoById(v.EdbInfoId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				err = fmt.Errorf("生成计算指标失败")
+				errMsg = "指标 " + strconv.Itoa(v.EdbInfoId) + " 不存在"
+				return
+			}
+			err = fmt.Errorf("生成计算指标失败")
+			errMsg = "获取指标失败:Err:" + e.Error()
+			return
+		}
+
+		edbInfoList = append(edbInfoList, fromEdbInfo)
+		//关联关系表
+		{
+			calculateMappingItem := &models.EdbInfoCalculateMapping{
+				EdbInfoCalculateMappingId: 0,
+				EdbInfoId:                 0,
+				Source:                    utils.DATA_SOURCE_CALCULATE,
+				SourceName:                "指标运算",
+				EdbCode:                   "",
+				FromEdbInfoId:             fromEdbInfo.EdbInfoId,
+				FromEdbCode:               fromEdbInfo.EdbCode,
+				FromEdbName:               fromEdbInfo.EdbName,
+				FromSource:                fromEdbInfo.Source,
+				FromSourceName:            fromEdbInfo.SourceName,
+				FromTag:                   v.FromTag,
+				Sort:                      k + 1,
+				CreateTime:                time.Now(),
+				ModifyTime:                time.Now(),
+			}
+			//calculateMappingItem.EdbCode = edbCode
+			//calculateMappingItem.EdbInfoId = int(edbInfoId)
+			calculateMappingList = append(calculateMappingList, calculateMappingItem)
+		}
+	}
+
+	for _, v := range formulaSlice {
+		formulaMap, e := utils.CheckFormula(v)
+		if e != nil {
+			err = fmt.Errorf("公式错误,请重新填写")
+			return
+		}
+		//预先计算,判断公式是否正常
+		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
+		if !ok {
+			err = fmt.Errorf("生成计算指标失败,请使用正确的计算公式")
+			return
+		}
+	}
+
+	randStr := utils.GetRandDigit(4)
+	edbCode := `C` + time.Now().Format("060102") + randStr
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	uniqueCode = utils.MD5(utils.DATA_PREFIX + "_" + timestamp)
+
+	// 新增计算指标
+	edbInfo, err = models.AddCalculateInfo(req, calculateMappingList, edbInfoList, edbCode, uniqueCode, edbInfoIdBytes)
+	if err != nil {
+		errMsg = "生成计算指标失败,AddEdbInfo Err:" + err.Error()
+		err = fmt.Errorf("生成计算指标失败")
+		return
+	}
+
+	return
+}

+ 18 - 3
services/base_from_predict.go

@@ -35,7 +35,12 @@ func GetCalculateByRuleByNineParams(req models.RuleConfig) (formula string, edbI
 		return
 	}
 	for _, f := range formulaSlice {
-		formulaMap := utils.CheckFormula(f)
+		formulaMap, e := utils.CheckFormula(f)
+		if e != nil {
+			err = fmt.Errorf("公式错误,请重新填写")
+			return
+		}
+
 		for _, v := range formulaMap {
 			if !strings.Contains(checkFormulaStr, v) {
 				errMsg = "公式错误,请重新填写"
@@ -63,7 +68,12 @@ func GetCalculateByRuleByNineParams(req models.RuleConfig) (formula string, edbI
 	}
 
 	for _, v := range formulaSlice {
-		formulaMap := utils.CheckFormula(v)
+		formulaMap, e := utils.CheckFormula(v)
+		if e != nil {
+			err = fmt.Errorf("公式错误,请重新填写")
+			return
+		}
+
 		//预先计算,判断公式是否正常
 		ok, _ := models.CheckFormula2(edbInfoList, formulaMap, v, edbInfoIdBytes)
 		if !ok {
@@ -178,7 +188,12 @@ func CalculateByRuleByNine(formulaStr string, edbInfoList []*models.EdbInfo, edb
 			if date < fv {
 				if f, ok := formulaDateMap[fv]; ok {
 					formulaStr = f
-					formulaMap = utils.CheckFormula(formulaStr)
+					formulaMap, err = utils.CheckFormula(formulaStr)
+					if err != nil {
+						err = fmt.Errorf("公式错误,请重新填写")
+						return
+					}
+
 				}
 				break
 			}

+ 10 - 3
utils/base_from_calculate.go

@@ -9,7 +9,7 @@ import (
 )
 
 // CheckFormula 检测计算公式是否异常
-func CheckFormula(formula string) map[string]string {
+func CheckFormula(formula string) (byteMap map[string]string, err error) {
 	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN", "EXP"}
 
 	str := strings.ToUpper(formula)
@@ -19,10 +19,17 @@ func CheckFormula(formula string) map[string]string {
 	str = strings.Replace(str, "(", "", -1)
 	str = strings.Replace(str, ")", "", -1)
 
-	byteMap := make(map[string]string)
+	byteMap = make(map[string]string)
 	for i := 0; i < len(str); i++ {
 		byteInt := str[i]
 		if byteInt >= 65 && byteInt <= 90 {
+			// 判断前一位是否是数字,如果是数字就报错
+			if i > 0 {
+				if str[i-1] >= '0' && str[i-1] <= '9' {
+					err = fmt.Errorf("计算公式异常,请检查公式:%s", formula)
+					return
+				}
+			}
 			byteStr := string(byteInt) //获取计算公式中的占位符A,B, AA,AB
 			if i+1 < len(str) {
 				next := str[i+1]
@@ -36,7 +43,7 @@ func CheckFormula(formula string) map[string]string {
 			}
 		}
 	}
-	return byteMap
+	return
 }
 
 type FormulaListItem struct {

+ 6 - 1
utils/constants.go

@@ -105,6 +105,8 @@ const (
 	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->78
 	DATA_SOURCE_ICPI                                 = 79       // ICPI消费价格指数->79
 	DATA_SOURCE_MTJH                                 = 80       // 煤炭江湖->80
+	DATA_SOURCE_CALCULATE_SUM                        = 81
+	DATA_SOURCE_CALCULATE_AVG                        = 82
 )
 
 // 指标来源的中文展示
@@ -186,7 +188,10 @@ const (
 	DATA_SOURCE_NAME_YONYI                                = `涌益咨询`              // 涌益咨询
 	DATA_SOURCE_NAME_ICPI                                 = "ICPI消费价格指数"
 	DATA_SOURCE_NAME_FENWEI                               = `汾渭数据` // 汾渭煤炭
-	DATA_SOURCE_NAME_MTJH                                 = `煤炭江湖`              // 煤炭江湖->80
+	DATA_SOURCE_NAME_MTJH                                 = `煤炭江湖` // 煤炭江湖->80
+
+	DATA_SOURCE_NAME_CALCULATE_SUM = `多指标求和`
+	DATA_SOURCE_NAME_CALCULATE_AVG = `多指标求平均`
 )
 
 // 基础数据初始化日期