Răsfoiți Sursa

AI预测模型图表

hsun 2 săptămâni în urmă
părinte
comite
cdb563a6bd

+ 31 - 2
controllers/data_manage/ai_predict_model/classify.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/models/data_manage"
 	dataSourceModel "eta/eta_api/models/data_source"
 	"eta/eta_api/services"
+	"eta/eta_api/services/data"
 	"eta/eta_api/services/elastic"
 	"eta/eta_api/utils"
 	"fmt"
@@ -444,15 +445,36 @@ func (this *AiPredictModelClassifyController) Remove() {
 			br.ErrMsg = fmt.Sprintf("获取标的信息失败, %v", e)
 			return
 		}
+		if aiIndex != nil && aiIndex.AiPredictModelIndexId <= 0 {
+			br.Ret = 200
+			br.Msg = "删除成功"
+			br.Success = true
+			return
+		}
+
+		// 获取指标图表
+		var chartIds []int
+		chartTypes := []int{utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY, utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY}
+		for _, v := range chartTypes {
+			ct, e := data_manage.GetAiPredictChartInfoByIndexId(v, req.IndexId)
+			if e != nil && !utils.IsErrNoRow(e) {
+				br.Msg = "操作失败"
+				br.ErrMsg = fmt.Sprintf("获取标的图表信息失败, %v", e)
+				return
+			}
+			if ct != nil && ct.ChartInfoId > 0 {
+				chartIds = append(chartIds, ct.ChartInfoId)
+			}
+		}
 
 		// 删除标的及数据
-		if e = indexOb.RemoveIndexAndData(req.IndexId); e != nil {
+		if e = indexOb.RemoveIndexAndData(req.IndexId, chartIds); e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = fmt.Sprintf("删除标的及数据失败, %v", e)
 			return
 		}
 
-		// ES标记删除
+		// ES标记标的/图表删除
 		go func() {
 			indexItem := new(dataSourceModel.SearchDataSource)
 			indexItem.PrimaryId = aiIndex.AiPredictModelIndexId
@@ -470,6 +492,13 @@ func (this *AiPredictModelClassifyController) Remove() {
 				utils.FileLog.Info("AI预测模型-标记删除es失败, %v", e)
 				return
 			}
+
+			if len(chartIds) == 0 {
+				return
+			}
+			for _, v := range chartIds {
+				data.EsDeleteChartInfo(v)
+			}
 		}()
 	}
 

+ 147 - 1
controllers/data_manage/ai_predict_model/index.go

@@ -5,9 +5,11 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	aiPredictModel "eta/eta_api/models/ai_predict_model"
+	"eta/eta_api/models/data_manage"
 	dataSourceModel "eta/eta_api/models/data_source"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
+	"eta/eta_api/services/data"
 	"eta/eta_api/services/elastic"
 	"eta/eta_api/utils"
 	"fmt"
@@ -583,7 +585,7 @@ func (this *AiPredictModelIndexController) Import() {
 	}
 
 	// 导入指标
-	if e = services.ImportAiPredictModelIndexAndData(importIndexes); e != nil {
+	if e = services.ImportAiPredictModelIndexAndData(importIndexes, sysUser.AdminId, sysUser.RealName); e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = fmt.Sprintf("导入指标数据失败, %v", e)
 		return
@@ -984,3 +986,147 @@ func (this *AiPredictModelIndexController) DashboardDetail() {
 	br.Success = true
 	br.Msg = "获取成功"
 }
+
+// SearchByEs
+// @Title 图表模糊搜索(从es获取)
+// @Description  图表模糊搜索(从es获取)
+// @Param   Keyword   query   string  true       "图表名称"
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Param   Source   query   int  true       "来源,14:日度预测,15:月度预测,默认0:全部14+15"
+// @Success 200 {object} data_manage.ChartInfo
+// @router /chart/search_by_es [get]
+func (this *AiPredictModelIndexController) SearchByEs() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	keyword := this.GetString("Keyword")
+	keyword = strings.TrimSpace(keyword)
+	if keyword == "" {
+		keyword = this.GetString("KeyWord")
+		keyword = strings.TrimSpace(keyword)
+	}
+
+	//只看我的
+	isShowMe, _ := this.GetBool("IsShowMe")
+	showSysId := 0
+	if isShowMe {
+		showSysId = sysUser.AdminId
+	}
+
+	source, _ := this.GetInt("Source")
+	sourceList := make([]int, 0)
+	if source <= 0 {
+		sourceList = append(sourceList, utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY, utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY)
+	} else {
+		sourceList = append(sourceList, source)
+	}
+
+	var searchList []*data_manage.ChartInfoMore
+	var total int64
+	var err error
+
+	// 获取当前账号的不可见指标(AI预测的指标为标的均可见)
+	noPermissionChartIdList := make([]int, 0)
+	//{
+	//	obj := data_manage.EdbInfoNoPermissionAdmin{}
+	//	confList, err := obj.GetAllChartListByAdminId(this.SysUser.AdminId)
+	//	if err != nil && !utils.IsErrNoRow(err) {
+	//		br.Msg = "获取失败"
+	//		br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+	//		return
+	//	}
+	//	for _, v := range confList {
+	//		noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
+	//	}
+	//}
+
+	if keyword != "" {
+		searchList, total, err = data.EsSearchChartInfo(keyword, showSysId, sourceList, noPermissionChartIdList, startSize, pageSize)
+	} else {
+		total, searchList, err = data_manage.ChartInfoSearchByEmptyKeyWord(showSysId, sourceList, noPermissionChartIdList, startSize, pageSize)
+		if err != nil && !utils.IsErrNoRow(err) {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	finalList := make([]*data_manage.ChartInfoMore, 0)
+	if len(searchList) > 0 {
+		chartInfoIds := ""
+		chartEdbMap := make(map[int][]*data_manage.ChartEdbInfoMapping)
+		for _, v := range searchList {
+			chartInfoIds += strconv.Itoa(v.ChartInfoId) + ","
+		}
+		if chartInfoIds != "" {
+			chartInfoIds = strings.Trim(chartInfoIds, ",")
+			//判断是否需要展示英文标识
+			edbList, e := data_manage.GetChartEdbMappingListByChartInfoIds(chartInfoIds)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + e.Error()
+				return
+			}
+			for _, v := range edbList {
+				chartEdbMap[v.ChartInfoId] = append(chartEdbMap[v.ChartInfoId], v)
+			}
+		}
+
+		for _, v := range searchList {
+			tmp := new(data_manage.ChartInfoMore)
+			tmp.ChartInfo = v.ChartInfo
+			// 图表数据权限
+			tmp.HaveOperaAuth = true
+			//判断是否需要展示英文标识
+			if edbTmpList, ok := chartEdbMap[v.ChartInfoId]; ok {
+				tmp.IsEnChart = data.CheckIsEnChart(v.ChartNameEn, edbTmpList, v.Source, v.ChartType)
+			}
+			tmp.SearchText = v.SearchText
+			if tmp.SearchText == "" {
+				tmp.SearchText = v.ChartName
+			}
+			finalList = append(finalList, tmp)
+		}
+	}
+	//新增搜索词记录
+	{
+		searchKeyword := new(data_manage.SearchKeyword)
+		searchKeyword.KeyWord = keyword
+		searchKeyword.CreateTime = time.Now()
+		go data_manage.AddSearchKeyword(searchKeyword)
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, int(total))
+	resp := data_manage.ChartInfoListByEsResp{
+		Paging: page,
+		List:   finalList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 51 - 9
models/ai_predict_model/ai_predict_model_index.go

@@ -6,6 +6,7 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -229,7 +230,7 @@ type AiPredictModelIndexPageListResp struct {
 }
 
 // RemoveIndexAndData 删除标的及数据
-func (m *AiPredictModelIndex) RemoveIndexAndData(indexId int) (err error) {
+func (m *AiPredictModelIndex) RemoveIndexAndData(indexId int, chartIds []int) (err error) {
 	o := global.DbMap[utils.DbNameIndex]
 	tx := o.Begin()
 	defer func() {
@@ -252,6 +253,21 @@ func (m *AiPredictModelIndex) RemoveIndexAndData(indexId int) (err error) {
 		err = fmt.Errorf("remove index data err: %v", e)
 		return
 	}
+
+	// 删除图表
+	if len(chartIds) == 0 {
+		return
+	}
+	sql = ` DELETE FROM chart_info WHERE chart_info_id IN ?`
+	if e = tx.Exec(sql, chartIds).Error; e != nil {
+		err = fmt.Errorf("remove charts err: %v", e)
+		return
+	}
+	sql = ` DELETE FROM chart_edb_mapping WHERE chart_info_id IN ?`
+	if e = tx.Exec(sql, chartIds).Error; e != nil {
+		err = fmt.Errorf("remove chart mappings err: %v", e)
+		return
+	}
 	return
 }
 
@@ -277,12 +293,18 @@ func GetFirstAiPredictModelIndexByClassifyId(classifyId int) (item *AiPredictMod
 }
 
 type AiPredictModelImportData struct {
-	Index *AiPredictModelIndex
-	Data  []*AiPredictModelData
+	Index  *AiPredictModelIndex
+	Data   []*AiPredictModelData
+	Charts []*AiPredictModelImportCharts
+}
+
+type AiPredictModelImportCharts struct {
+	ChartInfo   *data_manage.ChartInfo
+	EdbMappings []*data_manage.ChartEdbMapping
 }
 
 // ImportIndexAndData 导入数据
-func (m *AiPredictModelIndex) ImportIndexAndData(createIndexes, updateIndexes []*AiPredictModelImportData, updateCols []string) (err error) {
+func (m *AiPredictModelIndex) ImportIndexAndData(createIndexes, updateIndexes []*AiPredictModelImportData, updateCols []string) (chartIds []int, err error) {
 	if len(createIndexes) == 0 && len(updateIndexes) == 0 {
 		return
 	}
@@ -327,23 +349,43 @@ func (m *AiPredictModelIndex) ImportIndexAndData(createIndexes, updateIndexes []
 
 	if len(createIndexes) > 0 {
 		for _, v := range createIndexes {
-			e := tx.Create(v.Index).Error
-			if e != nil {
+			if e := tx.Create(v.Index).Error; e != nil {
 				err = fmt.Errorf("insert index err: %v", e)
 				return
 			}
 
 			indexId := v.Index.AiPredictModelIndexId
 			for _, d := range v.Data {
-				d.AiPredictModelIndexId = int(indexId)
+				d.AiPredictModelIndexId = indexId
 				d.IndexCode = v.Index.IndexCode
 				d.DataTimestamp = d.DataTime.UnixNano() / 1e6
 			}
-			e = tx.CreateInBatches(v.Data, utils.MultiAddNum).Error
-			if e != nil {
+			if e := tx.CreateInBatches(v.Data, utils.MultiAddNum).Error; e != nil {
 				err = fmt.Errorf("insert index data err: %v", e)
 				return
 			}
+
+			// 图表
+			if len(v.Charts) == 0 {
+				continue
+			}
+			for _, ct := range v.Charts {
+				if e := tx.Create(ct.ChartInfo).Error; e != nil {
+					err = fmt.Errorf("insert chart err: %v", e)
+					return
+				}
+				for _, cm := range ct.EdbMappings {
+					cm.ChartInfoId = ct.ChartInfo.ChartInfoId
+					cm.EdbInfoId = indexId
+					time.Sleep(time.Microsecond)
+					cm.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", indexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10)))
+				}
+				if e := tx.CreateInBatches(ct.EdbMappings, utils.MultiAddNum).Error; e != nil {
+					err = fmt.Errorf("insert chart mapping err: %v", e)
+					return
+				}
+				chartIds = append(chartIds, ct.ChartInfo.ChartInfoId)
+			}
 		}
 	}
 	return

+ 39 - 0
models/data_manage/chart_info.go

@@ -2973,3 +2973,42 @@ func GetNextChartByClassifyIdAndSource(classifyId, source int) (item *ChartInfo,
 	err = global.DbMap[utils.DbNameIndex].Raw(sql, classifyId, source).First(&item).Error
 	return
 }
+
+// GetAiPredictChartInfoByIndexId 获取AI预测模型图表
+func GetAiPredictChartInfoByIndexId(source, indexId int) (item *ChartInfo, err error) {
+	sql := `SELECT * FROM chart_info WHERE chart_info_id = (
+		  SELECT chart_info_id FROM chart_edb_mapping WHERE source = ? AND edb_info_id = ?
+		) LIMIT 1`
+	err = global.DbMap[utils.DbNameIndex].Raw(sql, source, indexId).First(&item).Error
+	return
+}
+
+func (m *ChartInfo) AddChartInfoAndEdbMappings(item *ChartInfo, edbMappings []*ChartEdbMapping) (err error) {
+	if item == nil {
+		return
+	}
+	tx := global.DbMap[utils.DbNameIndex].Begin()
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	if e := tx.Create(item).Error; e != nil {
+		err = fmt.Errorf("insert chart err: %v", e)
+		return
+	}
+	if len(edbMappings) == 0 {
+		return
+	}
+	for _, v := range edbMappings {
+		v.ChartInfoId = item.ChartInfoId
+	}
+	if e := tx.CreateInBatches(edbMappings, utils.MultiAddNum).Error; e != nil {
+		err = fmt.Errorf("insert chart mapping err: %v", e)
+		return
+	}
+	return
+}

+ 9 - 0
routers/commentsRouter.go

@@ -358,6 +358,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"],
+        beego.ControllerComments{
+            Method: "SearchByEs",
+            Router: `/chart/search_by_es`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexController"],
         beego.ControllerComments{
             Method: "DashboardDetail",

+ 169 - 3
services/ai_predict_model_index.go

@@ -8,10 +8,11 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
+	"strconv"
 	"time"
 )
 
-func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelImportData) (err error) {
+func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelImportData, adminId int, adminRealName string) (err error) {
 	if len(imports) == 0 {
 		return
 	}
@@ -59,21 +60,33 @@ func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelIm
 			continue
 		}
 
-		// 新增
+		// 新增标的/图表
 		indexCode, e := utils.GenerateEdbCode(1, "IPM")
 		if e != nil {
 			err = fmt.Errorf("生成标的编码失败, %v", e)
 			return
 		}
 		v.Index.IndexCode = indexCode
+		v.Charts = GetAiPredictCharts(v.Index.IndexName, adminId, adminRealName)
 		createIndexes = append(createIndexes, v)
 	}
 
 	// 新增/更新指标
-	if e := indexOb.ImportIndexAndData(createIndexes, updateIndexes, updateCols); e != nil {
+	chartIds, e := indexOb.ImportIndexAndData(createIndexes, updateIndexes, updateCols)
+	if e != nil {
 		err = fmt.Errorf("导入指标失败, %v", e)
 		return
 	}
+
+	// 更新图表ES
+	if len(chartIds) == 0 {
+		return
+	}
+	go func() {
+		for _, v := range chartIds {
+			data.EsAddOrEditChartInfo(v)
+		}
+	}()
 	return
 }
 
@@ -114,8 +127,28 @@ func GetAiPredictChartDetailByData(indexItem *aiPredictModel.AiPredictModelIndex
 		confLeftMax = indexItem.LeftMax
 	}
 
+	// 获取指标对应的图表
+	chartSourceMapping := map[int]int{
+		aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
+		aiPredictModel.ModelDataSourceDaily:   utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
+	}
+	chartInfo, e := data_manage.GetAiPredictChartInfoByIndexId(chartSourceMapping[source], indexItem.AiPredictModelIndexId)
+	if e != nil && !utils.IsErrNoRow(e) {
+		err = fmt.Errorf("获取标的图表失败, %v", e)
+		return
+	}
+
 	// 获取曲线图主题样式
 	chartView := new(data_manage.ChartInfoView)
+	if chartInfo != nil && chartInfo.ChartInfoId > 0 {
+		chartView.ChartInfoId = chartInfo.ChartInfoId
+		chartView.ChartName = chartInfo.ChartName
+		chartView.ChartNameEn = chartInfo.ChartNameEn
+		chartView.Source = chartInfo.Source
+	} else {
+		chartView.ChartName = indexItem.IndexName
+		chartView.ChartNameEn = indexItem.IndexName
+	}
 	chartView.ChartType = utils.CHART_SOURCE_DEFAULT
 	chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE)
 	if e != nil {
@@ -264,3 +297,136 @@ func GetAiPredictChartDetailByData(indexItem *aiPredictModel.AiPredictModelIndex
 	resp.EdbInfoList = edbList
 	return
 }
+
+// GetAiPredictCharts 获取AI预测模型图表
+func GetAiPredictCharts(indexName string, adminId int, adminRealName string) (charts []*aiPredictModel.AiPredictModelImportCharts) {
+	charts = make([]*aiPredictModel.AiPredictModelImportCharts, 0)
+
+	// 日度/月度图表
+	frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily}
+	sourceMapping := map[int]int{
+		aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
+		aiPredictModel.ModelDataSourceDaily:   utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
+	}
+	suffixNameMapping := map[int]string{
+		aiPredictModel.ModelDataSourceMonthly: "预测模型/回测",
+		aiPredictModel.ModelDataSourceDaily:   "预测模型",
+	}
+
+	for _, v := range frequencyArr {
+		chartSource := sourceMapping[v]
+		newChart := new(aiPredictModel.AiPredictModelImportCharts)
+
+		// 新增图表
+		chartName := fmt.Sprintf("%s%s", indexName, suffixNameMapping[v])
+		chartInfo := new(data_manage.ChartInfo)
+		chartInfo.ChartName = chartName
+		chartInfo.ChartNameEn = chartName
+		chartInfo.ChartType = utils.CHART_TYPE_CURVE
+		chartInfo.Calendar = "公历"
+		chartInfo.SysUserId = adminId
+		chartInfo.SysUserRealName = adminRealName
+		chartInfo.CreateTime = time.Now()
+		chartInfo.ModifyTime = time.Now()
+		chartInfo.Source = chartSource
+		time.Sleep(time.Microsecond)
+		chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10))
+		newChart.ChartInfo = chartInfo
+
+		// chart_edb_mapping中edb_info_id为标的ID
+		edbMapping := new(data_manage.ChartEdbMapping)
+		//edbMapping.EdbInfoId = indexId
+		//edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", indexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10)))
+		edbMapping.Source = chartSource
+		edbMapping.CreateTime = time.Now().Local()
+		edbMapping.ModifyTime = time.Now().Local()
+		newChart.EdbMappings = append(newChart.EdbMappings, edbMapping)
+
+		charts = append(charts, newChart)
+	}
+	return
+}
+
+// FixAiPredictCharts 修复AI预测模型图表
+func FixAiPredictCharts() {
+	var err error
+	defer func() {
+		if err != nil {
+			fmt.Println(err)
+		}
+		fmt.Println("修复完成")
+	}()
+	fmt.Println("开始修复")
+
+	indexOb := new(aiPredictModel.AiPredictModelIndex)
+	indexes, e := indexOb.GetItemsByCondition("", make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		err = fmt.Errorf("获取所有标的失败, %v", e)
+		return
+	}
+	// 日度/月度图表
+	frequencyArr := []int{aiPredictModel.ModelDataSourceMonthly, aiPredictModel.ModelDataSourceDaily}
+	sourceMapping := map[int]int{
+		aiPredictModel.ModelDataSourceMonthly: utils.CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY,
+		aiPredictModel.ModelDataSourceDaily:   utils.CHART_SOURCE_AI_PREDICT_MODEL_DAILY,
+	}
+	suffixNameMapping := map[int]string{
+		aiPredictModel.ModelDataSourceMonthly: "预测模型/回测",
+		aiPredictModel.ModelDataSourceDaily:   "预测模型",
+	}
+	chartOb := new(data_manage.ChartInfo)
+	for _, v := range indexes {
+		for _, fre := range frequencyArr {
+			chartSource := sourceMapping[fre]
+			item, e := data_manage.GetAiPredictChartInfoByIndexId(chartSource, v.AiPredictModelIndexId)
+			if e != nil && !utils.IsErrNoRow(e) {
+				err = fmt.Errorf("获取AI预测模型图表失败, %v", e)
+				return
+			}
+			// 由于标的名称是固定的所以chart_info没有什么可更新的, 已加入过就忽略
+			if item != nil && item.ChartInfoId > 0 {
+				fmt.Printf("标的%d-%d图表已存在, continue\n", v.AiPredictModelIndexId, chartSource)
+				continue
+			}
+
+			// 新增图表
+			chartName := fmt.Sprintf("%s%s", v.IndexName, suffixNameMapping[fre])
+			chartInfo := new(data_manage.ChartInfo)
+			chartInfo.ChartName = chartName
+			chartInfo.ChartNameEn = chartName
+			chartInfo.ChartType = utils.CHART_TYPE_CURVE
+			chartInfo.Calendar = "公历"
+			chartInfo.SysUserId = v.SysUserId
+			chartInfo.SysUserRealName = v.SysUserRealName
+			chartInfo.CreateTime = time.Now()
+			chartInfo.ModifyTime = time.Now()
+			chartInfo.Source = chartSource
+			time.Sleep(time.Microsecond)
+			chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + strconv.FormatInt(time.Now().UnixNano(), 10))
+
+			// chart_edb_mapping中edb_info_id为标的ID
+			mappings := make([]*data_manage.ChartEdbMapping, 0)
+			edbMapping := new(data_manage.ChartEdbMapping)
+			edbMapping.EdbInfoId = v.AiPredictModelIndexId
+			edbMapping.UniqueCode = utils.MD5(fmt.Sprint(utils.CHART_PREFIX, "_", v.AiPredictModelIndexId, "_", strconv.FormatInt(time.Now().UnixNano(), 10)))
+			edbMapping.Source = chartSource
+			edbMapping.CreateTime = time.Now().Local()
+			edbMapping.ModifyTime = time.Now().Local()
+			mappings = append(mappings, edbMapping)
+
+			// 新增图表
+			if e = chartOb.AddChartInfoAndEdbMappings(chartInfo, mappings); e != nil {
+				err = fmt.Errorf("新增图表及mapping失败, %v", e)
+				return
+			}
+
+			// 写入ES
+			if chartInfo.ChartInfoId <= 0 {
+				err = fmt.Errorf("图表ID有误")
+				return
+			}
+			go data.EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+		}
+	}
+	return
+}

+ 2 - 0
utils/constants.go

@@ -310,6 +310,8 @@ const (
 	CHART_SOURCE_BALANCE_EXCEL                   = 11 // 平衡表图表
 	CHART_SOURCE_RANGE_ANALYSIS                  = 12 // 	区间分析图表
 	CHART_SOURCE_TRADE_ANALYSIS_PROCESS          = 13 // 持仓分析-建仓过程图表
+	CHART_SOURCE_AI_PREDICT_MODEL_DAILY          = 14 // AI预测模型图表-日度预测
+	CHART_SOURCE_AI_PREDICT_MODEL_MONTHLY        = 15 // AI预测模型图表-月度预测
 )
 
 // 批量配置图表的位置来源