Răsfoiți Sursa

Merge branch 'master' into feature/eta1.2.2_edb_source

# Conflicts:
#	controllers/base_from_smm.go
#	models/db.go
#	services/base_from_smm.go
#	services/base_from_ths.go
xyxie 1 an în urmă
părinte
comite
24a3d5af42

+ 88 - 1
controllers/base_from_calculate.go

@@ -560,7 +560,7 @@ func (this *CalculateController) BatchSave() {
 		}
 	}
 
-	notNeedFromEdbSourceList := []int{utils.DATA_SOURCE_CALCULATE_KSZS, utils.DATA_SOURCE_CALCULATE_CORRELATION} // 不需要传入来源指标id的 指标类型
+	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) {
 		br.Msg = "请选择指标"
 		return
@@ -1973,3 +1973,90 @@ func (this *CalculateController) CalculateComputeCorrelation() {
 	br.Data = valStr
 	br.IsAddLog = true
 }
+
+// ResetCustomAnalysisData
+// @Title 自定义表格数据重置
+// @Description 自定义表格数据重置
+// @Param request body models.ResetCustomAnalysisData true "type json string"
+// @Success Ret=200 返回指标id
+// @router /custom_analysis/reset [post]
+func (this *CalculateController) ResetCustomAnalysisData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.ResetCustomAnalysisData
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		br.ErrMsg = br.Msg
+		br.IsSendEmail = false
+		return
+	}
+	if len(req.DateList) <= 0 {
+		br.Msg = "请传入日期序列"
+		br.ErrMsg = br.Msg
+		br.IsSendEmail = false
+		return
+	}
+	if len(req.DataList) <= 0 {
+		br.Msg = "请传入数据序列"
+		br.ErrMsg = br.Msg
+		br.IsSendEmail = false
+		return
+	}
+
+	edbInfo, err := models.GetEdbInfoById(req.EdbInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "指标已被删除,请刷新页面"
+			br.ErrMsg = "指标已被删除,请刷新页面:Err:" + err.Error()
+			return
+		}
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败:Err:" + err.Error()
+		return
+	}
+	baseEdbInfoModel := models.CustomAnalysis{}
+	err, errMsg := baseEdbInfoModel.ResetData(edbInfo, req.DateList, req.DataList)
+	if err != nil {
+		br.Msg = "更新数据失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "更新数据失败 Err:" + err.Error()
+		return
+	}
+	if edbInfo == nil {
+		br.Msg = "更新数据失败"
+		br.ErrMsg = "更新数据失败,指标ID错误:"
+		return
+	}
+
+	// 更新指标最大最小值
+	err, errMsg = models.UnifiedModifyEdbInfoMaxAndMinInfo(edbInfo)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	resp := models.AddEdbInfoResp{
+		EdbInfoId:  edbInfo.EdbInfoId,
+		UniqueCode: edbInfo.UniqueCode,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "处理成功"
+	br.Data = resp
+	br.IsAddLog = true
+}

+ 7 - 1
controllers/base_from_smm.go

@@ -6,6 +6,7 @@ import (
 	"eta/eta_index_lib/models"
 	"eta/eta_index_lib/services"
 	"eta/eta_index_lib/utils"
+	"fmt"
 	"strconv"
 	"time"
 )
@@ -153,7 +154,12 @@ func (this *SmmController) HandleExcelData() {
 	}
 
 	// 处理excel表数据
-	services.SmmIndexHandle(req.BaseFilePath, req.RenameFilePath, req.IndexName, req.IndexCode, req.Unit, req.Frequency, req.Source, req.ExcelDataMap, req.TerminalCode)
+	e, errMsg := services.SmmIndexHandle(req.BaseFilePath, req.RenameFilePath, req.IndexName, req.IndexCode, req.Unit, req.Frequency, req.Source, req.ExcelDataMap, req.TerminalCode)
+	if e != nil {
+		br.Msg = "处理失败"
+		br.ErrMsg = fmt.Sprintf("处理有色excel表数据失败, Err: %s, ErrMsg: %s", e.Error(), errMsg)
+		return
+	}
 
 	br.Ret = 200
 	br.Success = true

+ 43 - 0
controllers/fix/custom_analysis.go

@@ -0,0 +1,43 @@
+package fix
+
+import (
+	"eta/eta_index_lib/controllers"
+	"eta/eta_index_lib/models"
+	"eta/eta_index_lib/services/fix"
+)
+
+// CustomAnalysisController 自定义分析
+type CustomAnalysisController struct {
+	controllers.BaseAuthController
+}
+
+var fixTable = false
+
+// FixTableV1
+// @Title 指标详情接口
+// @Description  指标详情接口
+// @Success 200 {object} models.EdbInfoDetailReq
+// @router /v1 [post]
+func (this *CustomAnalysisController) FixTableV1() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	if fixTable {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "请不要重复修复"
+		return
+	}
+	fixTable = true
+	//ETA1.0.2 自定义分析(生成指标数据修复)
+	fix.FixTableData()
+	//ETA1.0.2 自定义分析(修复excel与指标的关系)
+	fix.FixTableDataMapping()
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "修复成功"
+}

+ 3 - 1
models/base_from_calculate.go

@@ -619,6 +619,7 @@ type EdbInfoCalculateBatchSaveReq struct {
 	MoveType         int                            `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency    string                         `description:"移动频度:天/周/月/季/年"`
 	Calendar         string                         `description:"公历/农历"`
+	Data             interface{}                    `description:"数据"`
 }
 
 // EdbInfoCalculateEdbInfoIdReq 新增/编辑请求 关联的指标列表
@@ -645,7 +646,8 @@ type EdbInfoCalculateBatchEditReq struct {
 		FromTag   string `description:"指标对应标签"`
 		MoveValue int    `description:"移动的值"`
 	}
-	Calendar string `description:"公历/农历" orm:"default(公历)"`
+	Calendar string      `description:"公历/农历" orm:"default(公历)"`
+	Data     interface{} `description:"数据"`
 }
 
 // CheckFormula2 校验公式是否正常(比如说除法的分母不能为0之类的,实际上就是用预设的字段数据做一次计算)

+ 4 - 0
models/common.go

@@ -7,7 +7,9 @@ type BaseEdbInfoInterface interface {
 	Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error, errMsg string)
 	Edit(params EditCalculateBatchParams) (err error, errMsg string)
 	Refresh(params RefreshParams) (err error, errMsg string)
+	GetSource() int
 	GetSourceName() string
+	GetEdbType() int
 }
 
 // AddCalculateBatchParams 添加的请求参
@@ -50,6 +52,8 @@ func GetBaseEdbInfoModel(source int) (baseEdbInfoModel BaseEdbInfoInterface) {
 		baseEdbInfoModel = Percentile{}
 	case utils.DATA_SOURCE_CALCULATE_ZSXY:
 		baseEdbInfoModel = ExponentialSmoothing{}
+	case utils.DATA_SOURCE_CALCULATE_ZDYFX:
+		baseEdbInfoModel = CustomAnalysis{}
 	default:
 
 	}

+ 12 - 0
models/db.go

@@ -2,6 +2,7 @@ package models
 
 import (
 	"eta/eta_index_lib/models/data_stat"
+	"eta/eta_index_lib/models/excel"
 	"eta/eta_index_lib/models/future_good"
 	"eta/eta_index_lib/models/supply_analysis"
 	"eta/eta_index_lib/utils"
@@ -68,6 +69,8 @@ func init() {
 
 	// initDataStat 数据源统计管理相关表
 	initDataStat()
+	// Eta表格相关
+	initExcel()
 }
 
 // initFutureGood 注册期货数据 数据表
@@ -116,3 +119,12 @@ func initDataStat() {
 		new(data_stat.EdbSourceStat),     // 数据源统计表
 	)
 }
+
+// initExcel Excel
+func initExcel() {
+	orm.RegisterModel(
+		new(excel.ExcelInfo),
+		new(excel.ExcelClassify),
+		new(excel.ExcelEdbMapping), //excel与指标的关系表
+	)
+}

+ 6 - 1
models/edb_data_calculate_ljz.go

@@ -67,7 +67,7 @@ func (obj Ljz) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error,
 		MinValue:         0,
 		MaxValue:         0,
 		CalculateFormula: req.Formula,
-		EdbType:          2,
+		EdbType:          obj.GetEdbType(),
 		Sort:             0,
 		MoveType:         0,
 		MoveFrequency:    "",
@@ -274,6 +274,11 @@ func (obj Ljz) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_LJZ
 }
 
+// GetEdbType 获取指标类型
+func (obj Ljz) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 func (obj Ljz) refresh(to orm.TxOrmer, edbInfoId, source int, edbInfo, fromEdbInfo *EdbInfo, edbCode, startDate string) (err error) {
 	dataTableName := GetEdbDataTableName(source)
 	edbInfoIdStr := strconv.Itoa(edbInfoId)

+ 6 - 1
models/edb_data_calculate_ljznczj.go

@@ -67,7 +67,7 @@ func (obj LjzNczj) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err er
 		MinValue:         0,
 		MaxValue:         0,
 		CalculateFormula: req.Formula,
-		EdbType:          2,
+		EdbType:          obj.GetEdbType(),
 		Sort:             0,
 		MoveType:         0,
 		MoveFrequency:    "",
@@ -274,6 +274,11 @@ func (obj LjzNczj) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_LJZNCZJ
 }
 
+// GetEdbType 获取指标类型
+func (obj LjzNczj) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 func (obj LjzNczj) refresh(to orm.TxOrmer, edbInfoId, source int, edbInfo, fromEdbInfo *EdbInfo, edbCode, startDate string) (err error) {
 	dataTableName := GetEdbDataTableName(source)
 	edbInfoIdStr := strconv.Itoa(edbInfoId)

+ 6 - 1
models/edb_data_calculate_ljzzj.go

@@ -55,7 +55,7 @@ func (obj Ljzzj) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err erro
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.UniqueCode = params.UniqueCode
 	edbInfo.CalculateFormula = req.Formula
-	edbInfo.EdbType = 2
+	edbInfo.EdbType = obj.GetEdbType()
 	newEdbInfoId, tmpErr := to.Insert(edbInfo)
 	if tmpErr != nil {
 		err = tmpErr
@@ -231,6 +231,11 @@ func (obj Ljzzj) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_LJZZJ
 }
 
+// GetEdbType 获取指标类型
+func (obj Ljzzj) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 func (obj Ljzzj) refresh(to orm.TxOrmer, edbInfoId, source int, fromEdbInfo *EdbInfo, edbCode string) (err error) {
 	dataTableName := GetEdbDataTableName(source)
 	edbInfoIdStr := strconv.Itoa(edbInfoId)

+ 6 - 1
models/edb_data_calculate_percentile.go

@@ -51,7 +51,7 @@ func (obj Percentile) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.UniqueCode = params.UniqueCode
 	edbInfo.CalculateFormula = req.Formula
-	edbInfo.EdbType = 2
+	edbInfo.EdbType = obj.GetEdbType()
 	newEdbInfoId, tmpErr := to.Insert(edbInfo)
 	if tmpErr != nil {
 		err = tmpErr
@@ -229,6 +229,11 @@ func (obj Percentile) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_PERCENTILE
 }
 
+// GetEdbType 获取指标类型
+func (obj Percentile) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 // PercentileConfig 百分位的配置
 type PercentileConfig struct {
 	CalculateValue int    `description:"时间长度期数"`

+ 6 - 1
models/edb_data_calculate_standard_deviation.go

@@ -50,7 +50,7 @@ func (obj StandardDeviation) Add(params AddCalculateBatchParams) (edbInfo *EdbIn
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.UniqueCode = params.UniqueCode
 	edbInfo.CalculateFormula = req.Formula
-	edbInfo.EdbType = 2
+	edbInfo.EdbType = obj.GetEdbType()
 	newEdbInfoId, tmpErr := to.Insert(edbInfo)
 	if tmpErr != nil {
 		err = tmpErr
@@ -228,6 +228,11 @@ func (obj StandardDeviation) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_STANDARD_DEVIATION
 }
 
+// GetEdbType 获取指标类型
+func (obj StandardDeviation) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 func (obj StandardDeviation) refresh(to orm.TxOrmer, edbInfo, fromEdbInfo *EdbInfo, edbCode string) (err error) {
 	edbInfoId := edbInfo.EdbInfoId
 	dataTableName := GetEdbDataTableName(edbInfo.Source)

+ 348 - 0
models/edb_data_calculate_zdyfx.go

@@ -0,0 +1,348 @@
+package models
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_index_lib/models/excel"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/shopspring/decimal"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// CustomAnalysis 自定义分析
+type CustomAnalysis struct{}
+
+// CustomAnalysisData 自定义分析的数据
+type CustomAnalysisData struct {
+	ExcelInfoId int `description:"excel的id"`
+	DateList    []string
+	DataList    []float64
+}
+
+// Add 添加
+func (obj CustomAnalysis) Add(params AddCalculateBatchParams) (edbInfo *EdbInfo, err error, errMsg string) {
+	req := params.Req
+	edbCode := params.EdbCode
+
+	// 自定义分析的数据集
+	jsonByte, err := json.Marshal(req.Data)
+	if err != nil {
+		return
+	}
+	var customAnalysisData CustomAnalysisData
+	err = json.Unmarshal(jsonByte, &customAnalysisData)
+	if err != nil {
+		return
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+			fmt.Println(reflect.TypeOf(obj).Name(), ";Add,Err:"+err.Error())
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	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.CalculateFormula = req.Formula
+	edbInfo.EdbType = 2
+	newEdbInfoId, tmpErr := to.Insert(edbInfo)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	edbInfo.EdbInfoId = int(newEdbInfoId)
+
+	//关联关系
+	{
+		excelEdbMappingItem := new(excel.ExcelEdbMapping)
+		excelEdbMappingItem.CreateTime = time.Now()
+		excelEdbMappingItem.ModifyTime = time.Now()
+		excelEdbMappingItem.ExcelInfoId = customAnalysisData.ExcelInfoId
+		excelEdbMappingItem.Source = 4
+		excelEdbMappingItem.EdbInfoId = edbInfo.EdbInfoId
+		_, err = to.Insert(excelEdbMappingItem)
+		if err != nil {
+			return
+		}
+	}
+
+	//计算数据
+	err = obj.refresh(to, edbInfo, customAnalysisData.DateList, customAnalysisData.DataList)
+
+	return
+}
+
+// Edit 编辑
+func (obj CustomAnalysis) Edit(params EditCalculateBatchParams) (err error, errMsg string) {
+	req := params.Req
+	edbInfo := params.EdbInfo
+
+	// 自定义分析的数据集
+	jsonByte, err := json.Marshal(req.Data)
+	if err != nil {
+		return
+	}
+	var customAnalysisData CustomAnalysisData
+	err = json.Unmarshal(jsonByte, &customAnalysisData)
+	if err != nil {
+		return
+	}
+
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+			fmt.Println(reflect.TypeOf(obj).Name(), ";Edit,Err:"+err.Error())
+		} 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
+	}
+
+	// 只有excel的id有传递,同时有数据的情况下,才去做处理
+	if customAnalysisData.ExcelInfoId > 0 && len(customAnalysisData.DateList) > 0 && len(customAnalysisData.DataList) > 0 {
+		//判断计算指标是否被更换
+		excelEdbMapping, tmpErr := excel.GetExcelEdbMappingByEdbInfoId(edbInfo.EdbInfoId)
+		if tmpErr != nil {
+			err = errors.New("获取excel与指标的关系失败,Err:" + tmpErr.Error())
+			return
+		}
+		if excelEdbMapping.ExcelInfoId != customAnalysisData.ExcelInfoId {
+			errMsg = `excel与指标关系异常`
+			err = errors.New(errMsg)
+			return
+		}
+
+		//计算数据
+		err = obj.refresh(to, edbInfo, customAnalysisData.DateList, customAnalysisData.DataList)
+	}
+
+	return
+}
+
+// Refresh 刷新
+func (obj CustomAnalysis) Refresh(params RefreshParams) (err error, errMsg string) {
+
+	return
+}
+
+// GetSource 获取来源编码id
+func (obj CustomAnalysis) GetSource() int {
+	return utils.DATA_SOURCE_CALCULATE_ZDYFX
+}
+
+// GetSourceName 获取来源名称
+func (obj CustomAnalysis) GetSourceName() string {
+	return utils.DATA_SOURCE_NAME_CALCULATE_ZDYFX
+}
+
+// GetEdbType 获取指标类型
+func (obj CustomAnalysis) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
+// UpdateEdbDataStr 数据更新结构体
+type UpdateEdbDataStr struct {
+	Value    string `description:"数据对应的最新值"`
+	DataTime string `description:"数据对应的日期"`
+}
+
+func (obj CustomAnalysis) refresh(to orm.TxOrmer, edbInfo *EdbInfo, dateList []string, dataList []float64) (err error) {
+	edbInfoId := edbInfo.EdbInfoId
+	dataTableName := GetEdbDataTableName(edbInfo.Source)
+	edbInfoIdStr := strconv.Itoa(edbInfoId)
+
+	if len(dateList) != len(dataList) {
+		err = errors.New("数据集与日期集不匹配")
+		return
+	}
+
+	//获取指标所有数据
+	existDataList := make([]*EdbData, 0)
+	sql := `SELECT * FROM %s WHERE edb_info_id=? `
+	sql = fmt.Sprintf(sql, dataTableName)
+	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
+	if err != nil {
+		return err
+	}
+	existDataMap := make(map[string]string)
+	removeDataTimeMap := make(map[string]int) //需要移除的日期数据
+	for _, v := range existDataList {
+		existDataMap[v.DataTime] = v.Value
+		removeDataTimeMap[v.DataTime] = 1
+	}
+	needAddDateMap := make(map[time.Time]int)
+
+	var isAdd, isUpdate bool
+	addSql := ` INSERT INTO ` + dataTableName + `(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
+
+	updateEdbDataStrList := make([]UpdateEdbDataStr, 0)
+	updateSql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
+	updateSql = fmt.Sprintf(updateSql, dataTableName)
+	p, err := to.Raw(updateSql).Prepare()
+	if err != nil {
+		return
+	}
+	defer func() {
+		_ = p.Close()
+	}()
+
+	for i, currDateStr := range dateList {
+		currVal := dataList[i] // 当前日期对应的值
+
+		currTime, tmpErr := time.ParseInLocation(utils.FormatDate, currDateStr, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		// 当前的实际值
+		saveValue := decimal.NewFromFloat(currVal).Round(4).String()
+
+		existVal, ok := existDataMap[currDateStr]
+		// 如果库中已经存在该数据的话,那么就进行值的变更操作
+		if ok {
+			//校验待删除日期数据里面是否存在该元素,如果存在的话,那么移除该日期
+			delete(removeDataTimeMap, currDateStr)
+			existValDec, _ := decimal.NewFromString(existVal)
+			existVal = existValDec.Round(4).String()
+
+			if existVal != saveValue {
+				isUpdate = true
+				updateEdbDataStrList = append(updateEdbDataStrList, UpdateEdbDataStr{
+					Value:    saveValue,
+					DataTime: currDateStr,
+				})
+				//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, currDateStr).Exec()
+				//if err != nil {
+				//	return
+				//}
+			}
+
+			continue
+		}
+
+		// 库中不存在该日期的数据
+		timestamp := currTime.UnixNano() / 1e6
+		timeStr := fmt.Sprintf("%d", timestamp)
+		if _, existOk := needAddDateMap[currTime]; !existOk {
+			addSql += GetAddSql(edbInfoIdStr, edbInfo.EdbCode, currDateStr, timeStr, saveValue)
+			isAdd = true
+		}
+		needAddDateMap[currTime] = 1
+	}
+
+	//删除已经不存在的指标数据(由于该指标当日的数据删除了)
+	{
+		removeDateList := make([]string, 0)
+		for dateTime := range removeDataTimeMap {
+			removeDateList = append(removeDateList, dateTime)
+		}
+		removeNum := len(removeDateList)
+		if removeNum > 0 {
+			sql := fmt.Sprintf(` DELETE FROM %s WHERE edb_info_id = ? and data_time in (`+utils.GetOrmInReplace(removeNum)+`) `, dataTableName)
+			_, err = to.Raw(sql, edbInfo.EdbInfoId, removeDateList).Exec()
+			if err != nil {
+				fmt.Println(reflect.TypeOf(obj).Name(), " add data ;delete Err", err.Error())
+				err = fmt.Errorf("删除不存在的指标数据失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
+
+	// 添加指标数据
+	if isAdd {
+		addSql = strings.TrimRight(addSql, ",")
+		_, err = to.Raw(addSql).Exec()
+		if err != nil {
+			fmt.Println(reflect.TypeOf(obj).Name(), " add data Err", err.Error())
+			return
+		}
+	}
+
+	// 更新指标数据
+	if isUpdate {
+		for _, v := range updateEdbDataStrList {
+			if v.Value == "" || v.DataTime == "" {
+				continue
+			}
+			_, err = p.Exec(v.Value, edbInfoId, v.DataTime)
+			if err != nil {
+				fmt.Println(reflect.TypeOf(obj).Name(), " update data Err", err.Error())
+				return
+			}
+		}
+	}
+
+	return
+}
+
+// ResetData 数据重置
+func (obj CustomAnalysis) ResetData(edbInfo *EdbInfo, dateList []string, dataList []float64) (err error, errMsg string) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+			fmt.Println(reflect.TypeOf(obj).Name(), ";ResetData,Err:"+err.Error())
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	err = obj.refresh(to, edbInfo, dateList, dataList)
+
+	return
+}
+
+// ResetCustomAnalysisData 数据重置的结构体
+type ResetCustomAnalysisData struct {
+	EdbInfoId int
+	DateList  []string
+	DataList  []float64
+}

+ 6 - 1
models/edb_data_calculate_zsxy.go

@@ -49,7 +49,7 @@ func (obj ExponentialSmoothing) Add(params AddCalculateBatchParams) (edbInfo *Ed
 	edbInfo.ModifyTime = time.Now()
 	edbInfo.UniqueCode = params.UniqueCode
 	edbInfo.CalculateFormula = req.Formula
-	edbInfo.EdbType = 2
+	edbInfo.EdbType = obj.GetEdbType()
 	newEdbInfoId, tmpErr := to.Insert(edbInfo)
 	if tmpErr != nil {
 		err = tmpErr
@@ -226,6 +226,11 @@ func (obj ExponentialSmoothing) GetSourceName() string {
 	return utils.DATA_SOURCE_NAME_CALCULATE_ZSXY
 }
 
+// GetEdbType 获取指标类型
+func (obj ExponentialSmoothing) GetEdbType() int {
+	return utils.CALCULATE_EDB_TYPE
+}
+
 func (obj ExponentialSmoothing) refresh(to orm.TxOrmer, edbInfo, fromEdbInfo *EdbInfo, edbCode string) (err error) {
 	edbInfoId := edbInfo.EdbInfoId
 	dataTableName := GetEdbDataTableName(edbInfo.Source)

+ 63 - 0
models/excel/excel_classify.go

@@ -0,0 +1,63 @@
+package excel
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ExcelClassify excel表格分类
+type ExcelClassify struct {
+	ExcelClassifyId   int       `orm:"column(excel_classify_id);pk"`
+	Source            int       `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
+	ExcelClassifyName string    `description:"分类名称"`
+	ParentId          int       `description:"父级id"`
+	SysUserId         int       `description:"创建人id"`
+	SysUserRealName   string    `description:"创建人姓名"`
+	Level             int       `description:"层级"`
+	UniqueCode        string    `description:"唯一编码"`
+	Sort              int       `description:"排序字段,越小越靠前,默认值:10"`
+	IsDelete          int       `description:"排序字段,越小越靠前,默认值:10"`
+	CreateTime        time.Time `description:"创建时间"`
+	ModifyTime        time.Time `description:"修改时间"`
+}
+
+// AddExcelClassify 添加excel分类
+func AddExcelClassify(item *ExcelClassify) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	if err != nil {
+		return
+	}
+	item.ExcelClassifyId = int(lastId)
+
+	return
+}
+
+type ExcelClassifyItems struct {
+	ExcelClassifyId   int `description:"分类id"`
+	ExcelInfoId       int `description:"表格id"`
+	ExcelClassifyName string
+	ParentId          int
+	Level             int    `description:"层级"`
+	Sort              int    `description:"排序字段,越小越靠前,默认值:10"`
+	UniqueCode        string `description:"唯一编码"`
+	SysUserId         int    `description:"创建人id"`
+	SysUserRealName   string `description:"创建人姓名"`
+	StartDate         string `description:"自定义开始日期"`
+	Children          []*ExcelClassifyItems
+}
+
+// GetExcelClassifyByParentId
+// @Description: 根据父级分类id获取指标下面的分类列表
+// @author: Roc
+// @datetime2023-10-30 13:46:35
+// @param parentId int
+// @param source int
+// @return items []*ExcelClassifyItems
+// @return err error
+func GetExcelClassifyByParentId(parentId, source int) (items []*ExcelClassifyItems, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM excel_classify WHERE parent_id=? AND source = ? AND is_delete=0 order by sort asc,excel_classify_id asc`
+	_, err = o.Raw(sql, parentId, source).QueryRows(&items)
+	return
+}

+ 57 - 0
models/excel/excel_edb_mapping.go

@@ -0,0 +1,57 @@
+package excel
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ExcelEdbMapping excel与指标的关系表
+type ExcelEdbMapping struct {
+	ExcelEdbMappingId int       `orm:"column(excel_edb_mapping_id);pk"`
+	ExcelInfoId       int       `description:"excel的id"`
+	Source            int       `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
+	EdbInfoId         int       `description:"计算指标id"`
+	CreateTime        time.Time `description:"创建时间"`
+	ModifyTime        time.Time `description:"修改时间"`
+}
+
+// AddExcelEdbMappingMulti 批量添加excel与指标的关系
+func AddExcelEdbMappingMulti(items []*ExcelEdbMapping) (err error) {
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+// Add 添加excel与指标的关系
+func (e *ExcelEdbMapping) Add() (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(e)
+	return
+}
+
+type ExcelEdbMappingItem struct {
+	EdbInfoId        int    `description:"指标id"`
+	UniqueCode       string `description:"唯一编码"`
+	EdbName          string `description:"指标名称"`
+	ClassifyId       int    `description:"分类id"`
+	Frequency        string `description:"频度"`
+	Unit             string `description:"单位"`
+	CalculateFormula string `json:"-"`
+	DateSequenceStr  string `description:"日期序列公式"`
+	DataSequenceStr  string `description:"数据序列公式"`
+}
+
+// CalculateFormula 计算公式
+type CalculateFormula struct {
+	DateSequenceStr string `json:"DateSequenceStr"`
+	DataSequenceStr string `json:"DataSequenceStr"`
+}
+
+// GetExcelEdbMappingByEdbInfoId 根据指标id获取配置关系
+func GetExcelEdbMappingByEdbInfoId(edbInfoId int) (item *ExcelEdbMapping, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT *  FROM excel_edb_mapping WHERE 1=1 AND edb_info_id = ? `
+
+	err = o.Raw(sql, edbInfoId).QueryRow(&item)
+	return
+}

+ 112 - 0
models/excel/excel_info.go

@@ -0,0 +1,112 @@
+package excel
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ExcelInfo excel表格详情表
+type ExcelInfo struct {
+	ExcelInfoId     int       `orm:"column(excel_info_id);pk"`
+	Source          int       `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
+	ExcelType       int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName       string    `description:"表格名称"`
+	UniqueCode      string    `description:"表格唯一编码"`
+	ExcelClassifyId int       `description:"表格分类id"`
+	SysUserId       int       `description:"操作人id"`
+	SysUserRealName string    `description:"操作人真实姓名"`
+	Content         string    `description:"表格内容"`
+	ExcelImage      string    `description:"表格图片"`
+	FileUrl         string    `description:"表格下载地址"`
+	Sort            int       `description:"排序字段,数字越小越排前面"`
+	IsDelete        int       `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime      time.Time `description:"最近修改日期"`
+	CreateTime      time.Time `description:"创建日期"`
+}
+
+// GetNoContentExcelInfoAll 获取不含content的表格列表 用于分类展示
+func GetNoContentExcelInfoAll(source, userId int) (items []*ExcelClassifyItems, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT excel_info_id,excel_classify_id,excel_name AS excel_classify_name,
+             unique_code,sys_user_id,sys_user_real_name
+            FROM excel_info where is_delete=0 AND source = ?  `
+
+	pars := []interface{}{source}
+
+	if userId > 0 {
+		sql += ` AND sys_user_id = ? `
+		pars = append(pars, userId)
+	}
+	sql += `  ORDER BY sort asc,create_time desc `
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+	return
+}
+
+// UpdateExcelInfoClassifyId 更改表格分类
+func UpdateExcelInfoClassifyId(classifyId, excelInfoId int) (err error) {
+	o := orm.NewOrm()
+	sql := ` update excel_info set excel_classify_id = ? WHERE excel_info_id=? `
+	_, err = o.Raw(sql, classifyId, excelInfoId).Exec()
+
+	return
+}
+
+// GetAllExcelInfoBySource 根据来源获取包含content的表格列表
+func GetAllExcelInfoBySource(source int) (items []*ExcelInfo, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM excel_info where is_delete=0  AND source = ?  ORDER BY sort asc,create_time desc `
+	_, err = o.Raw(sql, source).QueryRows(&items)
+	return
+}
+
+// TableDataReq 自定义表格请求参数
+type TableDataReq struct {
+	EdbInfoIdList []int             `description:"指标id列表,从左至右,从上到下的顺序"`
+	Sort          int               `description:"日期排序,1:倒序,2:正序"`
+	Data          []EdbInfoData     `description:"数据列表"`
+	TextRowData   [][]ManualDataReq `description:"文本列表"`
+}
+
+// EdbInfoData 自定义表格的数据
+type EdbInfoData struct {
+	EdbInfoId    int             `description:"指标ID"`
+	Tag          string          `description:"标签"`
+	EdbName      string          `description:"指标名称"`
+	EdbAliasName string          `description:"指标别名"`
+	Frequency    string          `description:"频度"`
+	Unit         string          `description:"单位"`
+	Data         []ManualDataReq `description:"单元格数据列表"`
+}
+
+// ManualDataReq 自定义表格的单元格数据
+type ManualDataReq struct {
+	DataType            int               `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算,5:预测值"`
+	DataTime            string            `description:"所属日期"`
+	DataTimeType        int               `description:"日期类型,1:实际日期;2:未来日期"`
+	ShowValue           string            `description:"展示值"`
+	Value               string            `description:"实际值(计算公式)"`
+	RelationEdbInfoList []RelationEdbInfo `description:"关联指标(计算公式中关联的指标,用于计算的时候去匹配)"`
+}
+
+// RelationEdbInfo 自定义表格中单元格的关联指标
+type RelationEdbInfo struct {
+	Tag string `description:"指标标签"`
+	Row string `description:"第几行"`
+}
+
+// MixedTableReq 混合表格保存请求参数
+type MixedTableReq struct {
+	CellRelation string                    `description:"单元格关系"`
+	Data         [][]MixedTableCellDataReq `description:"混合表格单元格参数"`
+}
+
+// MixedTableCellDataReq 混合表格单元格参数
+type MixedTableCellDataReq struct {
+	Uid          string `description:"单元格唯一标识"`
+	DataType     int    `description:"数据类型,1:日期,2:指标,3:自定义文本,4:插值"`
+	DataTime     string `description:"所属日期"`
+	DataTimeType int    `description:"日期类型:0:手动输入日期;1:导入系统日期;;3:导入指标日期(指标库的最新日期);"`
+	EdbInfoId    int    `description:"指标id"`
+	ShowValue    string `description:"展示值"`
+	Value        string `description:"实际值"`
+}

+ 18 - 0
routers/commentsRouter.go

@@ -7,6 +7,15 @@ import (
 
 func init() {
 
+    beego.GlobalControllerRouter["eta/eta_index_lib/controllers/fix:CustomAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers/fix:CustomAnalysisController"],
+        beego.ControllerComments{
+            Method: "FixTableV1",
+            Router: `/v1`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_index_lib/controllers/future_good:FutureGoodEdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_index_lib/controllers/future_good:FutureGoodEdbInfoController"],
         beego.ControllerComments{
             Method: "Add",
@@ -115,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: "ResetCustomAnalysisData",
+            Router: `/custom_analysis/reset`,
+            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: "Edit",

+ 6 - 0
routers/router.go

@@ -9,6 +9,7 @@ package routers
 
 import (
 	"eta/eta_index_lib/controllers"
+	"eta/eta_index_lib/controllers/fix"
 	"eta/eta_index_lib/controllers/future_good"
 	"eta/eta_index_lib/controllers/open"
 	beego "github.com/beego/beego/v2/server/web"
@@ -191,6 +192,11 @@ func init() {
 				&controllers.ExchangeCrawler{},
 			),
 		),
+		beego.NSNamespace("/fix",
+			beego.NSInclude(
+				&fix.CustomAnalysisController{},
+			),
+		),
 	)
 	beego.AddNamespace(ns)
 }

+ 61 - 46
services/base_from_smm.go

@@ -1,7 +1,6 @@
 package services
 
 import (
-	"errors"
 	"eta/eta_index_lib/logic"
 	"eta/eta_index_lib/models"
 	"eta/eta_index_lib/services/alarm_msg"
@@ -11,14 +10,17 @@ import (
 	"time"
 )
 
-func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, frequency, source string, excelDataMap map[string]string, terminalCode string) {
-	var err error
-
-	errMsgList := make([]string, 0)
+func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, frequency, source string, excelDataMap map[string]string, terminalCode string) (err error, errMsg string) {
+	messages := make([]string, 0)
 	defer func() {
-		if len(errMsgList) > 0 {
-			fmt.Println(fmt.Sprint("SMM有色实际数据处理失败,err:", strings.Join(errMsgList, "\n")))
-			go alarm_msg.SendAlarmMsg(fmt.Sprint("SMM有色实际数据处理失败,err:", strings.Join(errMsgList, "\n")), 3)
+		if len(messages) > 0 {
+			errMsg = strings.Join(messages, "\n")
+			utils.FileLog.Info("SmmIndexHandle ErrMsg: %s", errMsg)
+		}
+		if err != nil {
+			tips := fmt.Sprintf("SMM有色excel数据处理失败, Err: %s, ErrMsg: %s", err.Error(), errMsg)
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
 		}
 	}()
 
@@ -35,26 +37,24 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 		utils.FileLog.Info("未刷新到指标数据:indexName:" + indexName)
 		return
 	}
-	//判断指标是否存在
+	// 判断指标是否存在
 	var isAdd int
-	item, err := indexObj.GetSmmIndexItem(indexCode)
-	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
+	item, e := indexObj.GetSmmIndexItem(indexCode)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
 			isAdd = 1
 		} else {
 			isAdd = -1
-			fmt.Println("GetSmmIndexItem Err:" + err.Error())
+			err = fmt.Errorf("GetSmmIndexItem Err: %s", e.Error())
 			return
 		}
 	}
 	if item != nil && item.BaseFromSmmIndexId > 0 {
-		fmt.Println("item:", item)
 		isAdd = 2
 	} else {
 		isAdd = 1
 	}
 
-	fmt.Println("isAdd:", isAdd)
 	if !strings.Contains(frequency, "度") {
 		frequency = frequency + "度"
 	}
@@ -70,18 +70,18 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 		indexObj.BaseFileName = baseFilePath
 		indexObj.RenameFileName = renameFilePath
 		indexObj.TerminalCode = terminalCode
-		lastId, err := indexObj.AddBaseFromSmmIndex()
-		if err != nil {
-			fmt.Println("add err:" + err.Error())
+		lastId, e := indexObj.AddBaseFromSmmIndex()
+		if e != nil {
+			err = fmt.Errorf("AddBaseFromSmmIndex err: %s", e.Error())
 			return
 		}
 		indexId = lastId
 		go models.ModifySmmIndexSort(indexId)
 	} else if isAdd == 2 {
 		//获取已存在的所有数据
-		exitDataList, err := models.GetBaseFromSmmDataBySmmCode(indexCode)
-		if err != nil {
-			fmt.Println("GetIndexDataList Err:" + err.Error())
+		exitDataList, e := models.GetBaseFromSmmDataBySmmCode(indexCode)
+		if e != nil {
+			err = fmt.Errorf("GetBaseFromSmmDataBySmmCode err: %s", e.Error())
 			return
 		}
 		fmt.Println("exitDataListLen:", len(exitDataList))
@@ -102,9 +102,9 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 		whereParam["index_code"] = indexCode
 
 		smmIndexObj := new(models.BaseFromSmmIndex)
-		err = smmIndexObj.Update(updateParams, whereParam)
-		if err != nil {
-			err = errors.New("smm index update err:" + err.Error())
+		e = smmIndexObj.Update(updateParams, whereParam)
+		if e != nil {
+			err = fmt.Errorf("smm index update err: %s", e.Error())
 			return
 		}
 	}
@@ -113,20 +113,27 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 	for date, value := range excelDataMap {
 		dateTime, e := time.ParseInLocation(utils.FormatDate, date, time.Local)
 		if e != nil {
-			fmt.Println("time.ParseInLocation Err:" + e.Error())
-			return
+			messages = append(messages, fmt.Sprintf("data time parse err: %s, date: %s", e.Error(), date))
+			continue
 		}
 		if _, ok := exitDataMap[date]; !ok {
 			if !strings.Contains(value, "#N/A") {
 				var saveDataTime time.Time
 				if strings.Contains(date, "00:00:00") {
-					saveDataTime, err = time.Parse(utils.FormatDateTime, date)
+					saveDataTime, e = time.Parse(utils.FormatDateTime, date)
+					if e != nil {
+						messages = append(messages, fmt.Sprintf("save data time parse err: %s, date: %s", e.Error(), date))
+						continue
+					}
 				} else {
-					saveDataTime, err = time.Parse(utils.FormatDate, date)
+					saveDataTime, e = time.Parse(utils.FormatDate, date)
+					if e != nil {
+						messages = append(messages, fmt.Sprintf("save data time parse err: %s, date: %s", e.Error(), date))
+						continue
+					}
 				}
-				if err != nil {
-					errMsg := "saveDataTime parse err:" + err.Error() + " dataTime:" + date
-					fmt.Println(errMsg)
+				if saveDataTime.IsZero() {
+					messages = append(messages, fmt.Sprintf("save data time empty"))
 					continue
 				}
 				timestamp := saveDataTime.UnixNano() / 1e6
@@ -143,7 +150,12 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 			}
 		} else {
 			// 更新对应日期数据
-			if strings.Contains(value, "#N/A") {
+			if value == "" || strings.Contains(value, "#N/A") {
+				continue
+			}
+			// 若数值相同则忽略更新
+			existData := exitDataMap[date]
+			if existData != nil && existData.Value == value {
 				continue
 			}
 
@@ -156,38 +168,40 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 		}
 	}
 
+	//fmt.Println("addDataList len: ", len(addDataList))
 	if len(addDataList) > 0 {
-		err = models.AddBaseFromSmmData(addDataList)
-		if err != nil {
-			fmt.Println("AddBaseFromSmmData Err:" + err.Error())
-			errMsgList = append(errMsgList, "AddBaseFromSmmData err: "+err.Error())
+		e = models.AddBaseFromSmmData(addDataList)
+		if e != nil {
+			err = fmt.Errorf("AddBaseFromSmmData err: %s", e.Error())
+			return
 		}
 	}
 
 	// 已存在的日期数据更新
+	//fmt.Println("updateDataList len: ", len(updateDataList))
 	if len(updateDataList) > 0 {
-		err = models.MultiUpdateBaseFromSmmDataValue(updateDataList)
-		if err != nil {
-			fmt.Println("MultiUpdateBaseFromSmmDataValue Err:" + err.Error())
-			errMsgList = append(errMsgList, "MultiUpdateBaseFromSmmDataValue err: "+err.Error())
+		e = models.MultiUpdateBaseFromSmmDataValue(updateDataList)
+		if e != nil {
+			err = fmt.Errorf("MultiUpdateBaseFromSmmDataValue err: %s", e.Error())
+			return
 		}
 	}
 
 	itemInfo, err := models.GetSmmIndexInfoMaxAndMinInfo(indexCode)
 	if err == nil && item != nil {
-		e := models.ModifySmmIndexMaxAndMinInfo(indexCode, itemInfo)
+		e = models.ModifySmmIndexMaxAndMinInfo(indexCode, itemInfo)
 		if e != nil {
-			fmt.Println("ModifySmmIndexMaxAndMinInfo Err:" + e.Error())
-			errMsgList = append(errMsgList, "ModifySmmIndexMaxAndMinInfo err: "+e.Error())
+			err = fmt.Errorf("ModifySmmIndexMaxAndMinInfo err: %s", e.Error())
+			return
 		}
 	}
 
 	// 同步刷新ETA图库有色的指标
 	{
 		// 获取指标详情
-		edbInfo, err := models.GetEdbInfoByEdbCode(utils.DATA_SOURCE_YS, indexCode)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			errMsgList = append(errMsgList, fmt.Sprint("刷新ETA指标异常,指标编码:", indexCode, err.Error()))
+		edbInfo, e := models.GetEdbInfoByEdbCode(utils.DATA_SOURCE_YS, indexCode)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			messages = append(messages, fmt.Sprintf("刷新ETA指标异常, indexCode: %s, err: %s", indexCode, e.Error()))
 		}
 
 		// 已经加入到指标库的话,那么就去更新ETA指标库吧
@@ -195,4 +209,5 @@ func SmmIndexHandle(baseFilePath, renameFilePath, indexName, indexCode, unit, fr
 			go logic.RefreshBaseEdbInfo(edbInfo, ``)
 		}
 	}
+	return
 }

+ 6 - 6
services/base_from_ths.go

@@ -193,12 +193,12 @@ func GetFutureGoodDataFromThs(edbCode, startDate, endDate, edbTerminalCode strin
 		terminalCodeCacheKey := utils.CACHE_EDB_TERMINAL_CODE_URL + edbCode
 		_ = utils.Rc.Put(terminalCodeCacheKey, terminal.TerminalCode, utils.GetTodayLastSecond())
 	}
-	if utils.RunMode == `release` { // 生产环境走官方http请求,测试环境走终端
-		var token string
-		token, err = GetAccessToken(false, terminal.Value)
-		if err != nil {
-			return
-		}
+	var token string
+	token, err = GetAccessToken(false, terminal.Value)
+	if err != nil {
+		return
+	}
+	if utils.ThsDataMethod == "" || utils.ThsDataMethod == "api" { // 生产环境走官方http请求,测试环境走终端
 		return getFutureGoodDataFromThsHttp(edbCode, startDate, endDate, terminal.Value, token)
 	} else {
 		return getFutureGoodDataFromThsApp(edbCode, startDate, endDate, 0, terminal.ServerUrl)

+ 270 - 0
services/fix/custom_analysis.go

@@ -0,0 +1,270 @@
+package fix
+
+import (
+	"encoding/json"
+	excelModel "eta/eta_index_lib/models/excel"
+	"eta/eta_index_lib/utils"
+	"fmt"
+	"time"
+)
+
+// FixTableData ETA1.0.2 自定义分析(生成指标数据修复)
+func FixTableData() {
+	// 获取一级分类
+	classifyList, err := excelModel.GetExcelClassifyByParentId(0, utils.EXCEL_DEFAULT)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		fmt.Println("数据修复失败,Err:" + err.Error())
+		return
+	}
+	timeTableMap := make(map[int]int)
+	mixTableMap := make(map[int]int)
+	for _, v := range classifyList {
+		// 时间序列表格
+		classify := &excelModel.ExcelClassify{
+			//ExcelClassifyId:   0,
+			ExcelClassifyName: v.ExcelClassifyName,
+			ParentId:          v.ParentId,
+			Source:            utils.TIME_TABLE,
+			SysUserId:         v.SysUserId,
+			SysUserRealName:   v.SysUserRealName,
+			Level:             v.Level,
+			UniqueCode:        utils.MD5(fmt.Sprint(v.UniqueCode, "_", utils.TIME_TABLE)),
+			Sort:              v.Sort,
+			CreateTime:        time.Now(),
+			ModifyTime:        time.Now(),
+		}
+		_, err = excelModel.AddExcelClassify(classify)
+		timeTableMap[v.ExcelClassifyId] = classify.ExcelClassifyId
+
+		// 混合表格
+		classify2 := &excelModel.ExcelClassify{
+			//ExcelClassifyId:   0,
+			ExcelClassifyName: v.ExcelClassifyName,
+			ParentId:          v.ParentId,
+			Source:            utils.MIXED_TABLE,
+			SysUserId:         v.SysUserId,
+			SysUserRealName:   v.SysUserRealName,
+			Level:             v.Level,
+			UniqueCode:        utils.MD5(fmt.Sprint(v.UniqueCode, "_", utils.MIXED_TABLE)),
+			Sort:              v.Sort,
+			CreateTime:        time.Now(),
+			ModifyTime:        time.Now(),
+		}
+		_, err = excelModel.AddExcelClassify(classify2)
+		mixTableMap[v.ExcelClassifyId] = classify2.ExcelClassifyId
+	}
+
+	// 修改时间序列表
+	{
+		// 获取时间序列表
+		timeTableExcelList, err := excelModel.GetNoContentExcelInfoAll(utils.TIME_TABLE, 0)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			fmt.Println("获取时间序列表列表失败,Err:" + err.Error())
+			return
+		}
+
+		for _, v := range timeTableExcelList {
+			classifyId, ok := timeTableMap[v.ExcelClassifyId]
+			if !ok {
+				continue
+			}
+			excelModel.UpdateExcelInfoClassifyId(classifyId, v.ExcelInfoId)
+		}
+	}
+
+	// 修改混合序列表
+	{
+		// 获取时间序列表
+		mixTableExcelList, err := excelModel.GetNoContentExcelInfoAll(utils.MIXED_TABLE, 0)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			fmt.Println("获取时间序列表列表失败,Err:" + err.Error())
+			return
+		}
+
+		for _, v := range mixTableExcelList {
+			classifyId, ok := mixTableMap[v.ExcelClassifyId]
+			if !ok {
+				continue
+			}
+			excelModel.UpdateExcelInfoClassifyId(classifyId, v.ExcelInfoId)
+		}
+	}
+
+	fmt.Println("完成生成指标数据修复")
+}
+
+// FixTableDataMapping ETA1.0.2 自定义分析(修复excel与指标的关系)
+func FixTableDataMapping() {
+
+	// 修改时间序列表
+	{
+		// 获取时间序列表
+		timeTableExcelList, err := excelModel.GetAllExcelInfoBySource(utils.TIME_TABLE)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			fmt.Println("获取时间序列表列表失败,Err:" + err.Error())
+			return
+		}
+
+		for _, v := range timeTableExcelList {
+
+			var tableData excelModel.TableDataReq
+			err = json.Unmarshal([]byte(v.Content), &tableData)
+			if err != nil {
+				fmt.Println(v.ExcelInfoId, "json转结构体失败,Err:"+err.Error())
+				continue
+			}
+			if len(tableData.EdbInfoIdList) > 0 {
+				excelEdbMappingList := make([]*excelModel.ExcelEdbMapping, 0)
+				for _, edbInfoId := range tableData.EdbInfoIdList {
+					excelEdbMappingList = append(excelEdbMappingList, &excelModel.ExcelEdbMapping{
+						//ExcelEdbMappingId: 0,
+						ExcelInfoId: v.ExcelInfoId,
+						Source:      v.Source,
+						EdbInfoId:   edbInfoId,
+						CreateTime:  time.Now(),
+						ModifyTime:  time.Now(),
+					})
+				}
+				err = excelModel.AddExcelEdbMappingMulti(excelEdbMappingList)
+				if err != nil {
+					fmt.Println(v.ExcelInfoId, "自定义表格关系保存失败,Err:"+err.Error())
+					continue
+				}
+			}
+
+		}
+	}
+
+	// 修改混合序列表
+	{
+		// 获取时间序列表
+		mixTableExcelList, err := excelModel.GetAllExcelInfoBySource(utils.MIXED_TABLE)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			fmt.Println("获取时间序列表列表失败,Err:" + err.Error())
+			return
+		}
+
+		for _, excelInfo := range mixTableExcelList {
+			var result excelModel.MixedTableReq
+			err = json.Unmarshal([]byte(excelInfo.Content), &result)
+			if err != nil {
+				fmt.Println(excelInfo.ExcelInfoId, "修改混合序列表,json转结构体失败,Err:"+err.Error())
+				continue
+			}
+			newResult, tmpErr, _ := GetMixedTableCellData(result.CellRelation, result.Data)
+			if tmpErr != nil {
+				fmt.Println(excelInfo.ExcelInfoId, "获取最新的数据失败,Err:"+err.Error())
+				continue
+			}
+			edbInfoIdList := make([]int, 0)
+			edbInfoIdMap := make(map[int]int)
+			for _, tmpV := range newResult {
+				for _, v := range tmpV {
+					if v.EdbInfoId > 0 {
+						if _, ok := edbInfoIdMap[v.EdbInfoId]; !ok {
+							edbInfoIdMap[v.EdbInfoId] = v.EdbInfoId
+							edbInfoIdList = append(edbInfoIdList, v.EdbInfoId)
+						}
+					}
+				}
+			}
+
+			if len(edbInfoIdList) > 0 {
+				excelEdbMappingList := make([]*excelModel.ExcelEdbMapping, 0)
+				for _, edbInfoId := range edbInfoIdList {
+					excelEdbMappingList = append(excelEdbMappingList, &excelModel.ExcelEdbMapping{
+						//ExcelEdbMappingId: 0,
+						ExcelInfoId: excelInfo.ExcelInfoId,
+						Source:      excelInfo.Source,
+						EdbInfoId:   edbInfoId,
+						CreateTime:  time.Now(),
+						ModifyTime:  time.Now(),
+					})
+				}
+				err = excelModel.AddExcelEdbMappingMulti(excelEdbMappingList)
+				if err != nil {
+					fmt.Println(excelInfo.ExcelInfoId, "混合表格关系保存失败,Err:"+err.Error())
+					continue
+				}
+			}
+
+		}
+
+	}
+
+	fmt.Println("完成excel与指标的关系修复")
+}
+
+// CellRelationConf
+// @Description: 单元格的关系配置结构体
+type CellRelationConf struct {
+	CellRelation
+	//Type         int          `json:"type" description:"数据类型,跟MixedTableCellDataReq的DataType保持一致"`
+	//Key          string       `json:"key" description:"单元格的唯一标识"`
+	RelationDate CellRelation `json:"relation_date"`
+	RelationEdb  CellRelation `json:"relation_edb"`
+}
+
+// CellRelation
+// @Description: 单元格的关系结构体
+type CellRelation struct {
+	Type int    `json:"type" description:"数据类型,跟MixedTableCellDataReq的DataType保持一致"`
+	Key  string `json:"key" description:"单元格的唯一标识"`
+}
+
+// GetMixedTableCellData 获取混合表格数据
+func GetMixedTableCellData(cellRelationConf string, config [][]excelModel.MixedTableCellDataReq) (newMixedTableCellDataList [][]excelModel.MixedTableCellDataReq, err error, errMsg string) {
+	// 单元格关系配置x信息
+	cellRelationConfMap := make(map[string]CellRelationConf)
+	cellRelationConfList := make([]CellRelationConf, 0)
+	if cellRelationConf != `` {
+		err = json.Unmarshal([]byte(cellRelationConf), &cellRelationConfList)
+		if err != nil {
+			return
+		}
+
+		for _, v := range cellRelationConfList {
+			cellRelationConfMap[v.Key] = v
+		}
+	}
+
+	// 找出所有的关联指标id
+	config, _, _, err, errMsg = handleConfig(config)
+	if err != nil {
+		return
+	}
+
+	newMixedTableCellDataList = config
+
+	return
+}
+
+// 单元格的数据类型
+const (
+	DateDT          = iota + 1 //日期
+	EdbDT                      // 指标类型
+	CustomTextDT               // 自定义文本
+	InsertDataDT               // 插值
+	PopInsertDataDT            // 弹框插值
+)
+
+func handleConfig(configList [][]excelModel.MixedTableCellDataReq) (newConfig [][]excelModel.MixedTableCellDataReq, edbInfoIdList []int, dataEdbInfoIdList []int, err error, errMsg string) {
+	edbInfoIdList = make([]int, 0)
+	dataEdbInfoIdList = make([]int, 0)
+
+	for ck, rowList := range configList {
+		for _, cell := range rowList {
+			switch cell.DataType {
+			case EdbDT: // 指标信息
+				edbInfoIdList = append(edbInfoIdList, cell.EdbInfoId)
+			case InsertDataDT, PopInsertDataDT: // 插值、弹框插值
+				dataEdbInfoIdList = append(dataEdbInfoIdList, cell.EdbInfoId)
+			}
+		}
+		configList[ck] = rowList
+	}
+
+	newConfig = configList
+
+	return
+}

+ 15 - 0
utils/constants.go

@@ -174,6 +174,7 @@ const (
 	DATA_SOURCE_NAME_FUBAO                                = `富宝数据`              //富宝数据->71
 	DATA_SOURCE_NAME_CALCULATE_ZSXY                       = `指数修匀`              //指数修匀->72
 	DATA_SOURCE_NAME_PREDICT_CALCULATE_ZSXY               = `预测指数修匀`            //预测指数修匀->73
+	DATA_SOURCE_NAME_CALCULATE_ZDYFX                      = `自定义分析`             //自定义分析->74
 )
 
 // 基础数据初始化日期
@@ -237,3 +238,17 @@ var FrequencyDaysMap = map[string]int{
 var (
 	HZ_TRIAL_BUSSINESS_CODE = "E2023080700" //商家试用平台
 )
+
+// 指标类型:1:基础指标,2:计算指标
+const (
+	DEFAULT_EDB_TYPE   = 1 //基础指标
+	CALCULATE_EDB_TYPE = 2 //计算指标
+)
+
+// ETA表格
+const (
+	EXCEL_DEFAULT         = 1 // 自定义excel
+	TIME_TABLE            = 2 // 时间序列表格
+	MIXED_TABLE           = 3 // 混合表格
+	CUSTOM_ANALYSIS_TABLE = 4 // 自定义分析表格
+)

+ 1 - 1
utils/elastic.go

@@ -13,7 +13,7 @@ func initEs() {
 		elastic.SetSniff(false))
 	EsClient = client
 	if err != nil {
-		panic("ElasticSearch连接失败")
+		panic("ElasticSearch连接失败,Err:" + err.Error())
 		//go alarm_msg.SendAlarmMsg("ElasticSearch连接失败", 2)
 	}
 	return