瀏覽代碼

feat:AI预测模型

Roc 1 周之前
父節點
當前提交
2506993045

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

@@ -1133,7 +1133,7 @@ func (this *AiPredictModelIndexController) SearchByEs() {
 }
 
 // ScriptPathSave
-// @Title 保存保存标的关联脚本路径标的
+// @Title 保存标的关联脚本路径
 // @Description 保存标的关联脚本路径
 // @Param	request	body request.AiPredictModelIndexSaveScriptPathReq true "type json string"
 // @Success 200 Ret=200 保存成功

+ 225 - 3
controllers/data_manage/ai_predict_model/index_config.go

@@ -7,6 +7,7 @@ import (
 	data_manage "eta/eta_api/models/ai_predict_model"
 	"eta/eta_api/models/ai_predict_model/request"
 	"eta/eta_api/models/ai_predict_model/response"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
@@ -87,7 +88,7 @@ func (c *AiPredictModelIndexConfigController) List() {
 // @Description 获取当前版本参数信息
 // @Param   IndexId   query   int   true   "标的ID"
 // @Success 200 {object} []*data_manage.AiPredictModelIndexConfigView
-// @router /index_config/detail [get]
+// @router /index_config/version/curr [get]
 func (c *AiPredictModelIndexConfigController) CurrVersion() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
@@ -142,9 +143,67 @@ func (c *AiPredictModelIndexConfigController) CurrVersion() {
 	br.Msg = "获取成功"
 }
 
+// SetCurr
+// @Title 设置为当前版本
+// @Description 设置为当前版本
+// @Param	request	body request.DelConfigReq true "type json string"
+// @Success 200 Ret=200 设置成功
+// @router /index_config/set_curr [post]
+func (c *AiPredictModelIndexConfigController) SetCurr() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+
+	var req request.DelConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	configItem, err := obj.GetById(req.AiPredictModelIndexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemById(configItem.AiPredictModelIndexId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取失败,根据配置ID获取标的信息失败, %v", e)
+		return
+	}
+
+	indexItem.AiPredictModelIndexConfigId = configItem.AiPredictModelIndexConfigId
+	indexItem.ModifyTime = time.Now()
+	err = indexItem.Update([]string{indexOb.Cols().ModifyTime, indexOb.Cols().AiPredictModelIndexConfigId})
+	if err != nil {
+		br.Msg = "配置失败"
+		br.ErrMsg = fmt.Sprintf("配置失败,Err:%v", e)
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
 // Del
-// @Title 删除问题
-// @Description 删除问题
+// @Title 删除模型配置
+// @Description 删除模型配置
 // @Param	request	body request.DelConfigReq true "type json string"
 // @Success 200 Ret=200 删除成功
 // @router /index_config/del [post]
@@ -211,3 +270,166 @@ func (c *AiPredictModelIndexConfigController) Del() {
 	br.Success = true
 	br.Msg = `删除成功`
 }
+
+// ChartDetail
+// @Title 获取当前版本的图表信息
+// @Description 获取当前版本的图表信息
+// @Param   AiPredictModelIndexConfigId   query   int   true   "标的配置ID"
+// @Success 200 {object} []*data_manage.AiPredictModelIndexConfigView
+// @router /index_config/chart/detail [get]
+func (c *AiPredictModelIndexConfigController) ChartDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		return
+	}
+	indexConfigId, _ := c.GetInt("AiPredictModelIndexConfigId")
+	if indexConfigId <= 0 {
+		br.Msg = "标的配置id不能为空"
+		br.ErrMsg = "标的配置id不能为空"
+		return
+	}
+
+	resp := response.AiPredictModelDetailResp{}
+
+	// TODO 后面加上数据缓存
+
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	configItem, err := obj.GetById(indexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查找是否被标的引用为默认模型
+	// 查询标的情况
+	indexOb := new(data_manage.AiPredictModelIndex)
+	indexItem, e := indexOb.GetItemByConfigId(configItem.AiPredictModelIndexConfigId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = fmt.Sprintf("获取失败,根据配置ID获取标的信息失败, %v", e)
+		return
+	}
+
+	// 获取标的数据
+	dailyData := make([]*data_manage.AiPredictModelIndexConfigTrainData, 0)
+	{
+		dataOb := new(data_manage.AiPredictModelIndexConfigTrainData)
+		dataCond := fmt.Sprintf(` AND %s = ?`, data_manage.AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigId)
+		dataPars := make([]interface{}, 0)
+		dataPars = append(dataPars, configItem.AiPredictModelIndexConfigId)
+		list, e := dataOb.GetAllListByCondition(dataCond, dataPars, []string{}, fmt.Sprintf("%s DESC", data_manage.AiPredictModelIndexConfigTrainDataColumns.DataTime))
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取标的数据失败, %v", e)
+			return
+		}
+
+		for _, v := range list {
+			// 日度数据
+			if v.Source == data_manage.ModelDataSourceDaily {
+				dailyData = append(dailyData, v)
+				continue
+			}
+		}
+	}
+
+	// 日度图表
+	if len(dailyData) > 0 {
+		dailyChartDetail, e := services.GetAiPredictConfigChartDetailByData(indexItem.IndexName, configItem, dailyData, data_manage.ModelDataSourceDaily)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprintf("获取日度图表失败, %v", e)
+			return
+		}
+		resp.DailyChartView = dailyChartDetail
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Train
+// @Title 训练模型
+// @Description 训练模型
+// @Param	request	body request.DelConfigReq true "type json string"
+// @Success 200 Ret=200 训练中
+// @router /index_config/train [post]
+func (c *AiPredictModelIndexConfigController) Train() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelConfigReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.AiPredictModelIndexConfigId <= 0 {
+		br.Msg = "配置id不能为空"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 查找配置
+	obj := new(data_manage.AiPredictModelIndexConfig)
+	item, err := obj.GetById(req.AiPredictModelIndexConfigId)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "修改失败,查找配置失败,Err:" + err.Error()
+		if utils.IsErrNoRow(err) {
+			br.Msg = "配置不存在"
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	// 查找是否被标的引用为默认模型
+	{
+		// 查询标的情况
+		indexOb := new(data_manage.AiPredictModelIndex)
+		count, e := indexOb.GetCountByCondition(fmt.Sprintf(` AND %s = ? `, indexOb.Cols().AiPredictModelIndexConfigId), []interface{}{item.AiPredictModelIndexConfigId})
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = fmt.Sprintf("删除失败,根据配置ID获取标的信息失败, %v", e)
+			return
+		}
+
+		if count > 0 {
+			br.Msg = "删除失败,该版本配置正在被使用"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	item.IsDeleted = 1
+	item.ModifyTime = time.Now()
+	err = item.Update([]string{"IsDeleted", "ModifyTime"})
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = `删除成功`
+}

+ 29 - 11
models/ai_predict_model/ai_predict_model_index.go

@@ -140,6 +140,21 @@ func (m *AiPredictModelIndex) GetItemById(id int) (item *AiPredictModelIndex, er
 	return
 }
 
+// GetItemByConfigId
+// @Description: 根据配置id获取标的信息
+// @author: Roc
+// @receiver m
+// @datetime 2025-05-06 13:31:24
+// @param configId int
+// @return item *AiPredictModelIndex
+// @return err error
+func (m *AiPredictModelIndex) GetItemByConfigId(configId int) (item *AiPredictModelIndex, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.Cols().AiPredictModelIndexConfigId)
+	err = o.Raw(sql, configId).First(&item).Error
+	return
+}
+
 func (m *AiPredictModelIndex) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *AiPredictModelIndex, err error) {
 	o := global.DbMap[utils.DbNameIndex]
 	order := ``
@@ -442,17 +457,20 @@ type AiPredictModelIndexSaveChart struct {
 }
 
 type AiPredictModelIndexExtraConfig struct {
-	MonthlyChart struct {
-		LeftMin string `description:"图表左侧最小值"`
-		LeftMax string `description:"图表左侧最大值"`
-		Unit    string `description:"单位"`
-	}
-	DailyChart struct {
-		LeftMin           string `description:"图表左侧最小值"`
-		LeftMax           string `description:"图表左侧最大值"`
-		Unit              string `description:"单位"`
-		PredictLegendName string `description:"预测图例的名称(通常为Predicted)"`
-	}
+	MonthlyChart MonthlyChartConfig
+	DailyChart   DailyChartConfig
+}
+type MonthlyChartConfig struct {
+	LeftMin string `description:"图表左侧最小值"`
+	LeftMax string `description:"图表左侧最大值"`
+	Unit    string `description:"单位"`
+}
+
+type DailyChartConfig struct {
+	LeftMin           string `description:"图表左侧最小值"`
+	LeftMax           string `description:"图表左侧最大值"`
+	Unit              string `description:"单位"`
+	PredictLegendName string `description:"预测图例的名称(通常为Predicted)"`
 }
 
 func (m *AiPredictModelIndex) GetSortMax() (sort int, err error) {

+ 15 - 5
models/ai_predict_model/ai_predict_model_index_config.go

@@ -20,6 +20,8 @@ type AiPredictModelIndexConfig struct {
 	TestR2                      string    `gorm:"column:test_r2" description:"测试集r2"`
 	Remark                      string    `gorm:"column:remark" description:"训练结果说明"`
 	IsDeleted                   int8      `gorm:"column:is_deleted" description:"是否删除,0:未删除,1:已删除"`
+	LeftMin                     string    `gorm:"column:left_min" description:"图表左侧下限"`
+	LeftMax                     string    `gorm:"column:left_max" description:"图表左侧下限"`
 	ModifyTime                  time.Time `gorm:"column:modify_time" description:"修改时间"`
 	CreateTime                  time.Time `gorm:"column:create_time" description:"创建时间"`
 }
@@ -43,6 +45,8 @@ var AiPredictModelIndexConfigColumns = struct {
 	IsDeleted                   string
 	ModifyTime                  string
 	CreateTime                  string
+	LeftMin                     string
+	LeftMax                     string
 }{
 	AiPredictModelIndexConfigId: "ai_predict_model_index_config_id",
 	AiPredictModelIndexId:       "ai_predict_model_index_id",
@@ -53,6 +57,8 @@ var AiPredictModelIndexConfigColumns = struct {
 	TestMse:                     "test_mse",
 	TestR2:                      "test_r2",
 	Remark:                      "remark",
+	LeftMin:                     "left_min",
+	LeftMax:                     "left_max",
 	IsDeleted:                   "is_deleted",
 	ModifyTime:                  "modify_time",
 	CreateTime:                  "create_time",
@@ -69,6 +75,8 @@ type AiPredictModelIndexConfigView struct {
 	TestMse                     string `gorm:"column:test_mse" description:"测试集mse"`
 	TestR2                      string `gorm:"column:test_r2" description:"测试集r2"`
 	Remark                      string `gorm:"column:remark" description:"训练结果说明"`
+	LeftMin                     string `gorm:"column:left_min" description:"图表左侧下限"`
+	LeftMax                     string `gorm:"column:left_max" description:"图表左侧下限"`
 	IsCurr                      int8   `gorm:"column:is_curr" description:"是否当前版本,0:否,1:是"`
 	ModifyTime                  string `gorm:"column:modify_time" description:"修改时间"`
 	CreateTime                  string `gorm:"column:create_time" description:"创建时间"`
@@ -93,6 +101,8 @@ func (m *AiPredictModelIndexConfig) ToView() AiPredictModelIndexConfigView {
 		TestMse:                     m.TestMse,
 		TestR2:                      m.TestR2,
 		Remark:                      m.Remark,
+		LeftMin:                     m.LeftMin,
+		LeftMax:                     m.LeftMax,
 		ModifyTime:                  modifyTime,
 		CreateTime:                  createTime,
 	}
@@ -108,19 +118,19 @@ func (m *AiPredictModelIndexConfig) ListToViewList(list []*AiPredictModelIndexCo
 }
 
 func (m *AiPredictModelIndexConfig) Create() (err error) {
-	err = global.DbMap[utils.DbNameAI].Create(&m).Error
+	err = global.DbMap[utils.DbNameIndex].Create(&m).Error
 
 	return
 }
 
 func (m *AiPredictModelIndexConfig) Update(updateCols []string) (err error) {
-	err = global.DbMap[utils.DbNameAI].Select(updateCols).Updates(&m).Error
+	err = global.DbMap[utils.DbNameIndex].Select(updateCols).Updates(&m).Error
 
 	return
 }
 
 func (m *AiPredictModelIndexConfig) GetById(id int) (item *AiPredictModelIndexConfig, err error) {
-	err = global.DbMap[utils.DbNameAI].Where(fmt.Sprintf("%s = ?", AiPredictModelIndexConfigColumns.AiPredictModelIndexConfigId), id).First(&item).Error
+	err = global.DbMap[utils.DbNameIndex].Where(fmt.Sprintf("%s = ?", AiPredictModelIndexConfigColumns.AiPredictModelIndexConfigId), id).First(&item).Error
 
 	return
 }
@@ -131,7 +141,7 @@ func (m *AiPredictModelIndexConfig) GetListByCondition(field, condition string,
 	}
 	sqlStr := fmt.Sprintf(`SELECT %s FROM %s WHERE is_deleted=0 %s order by ai_predict_model_index_config_id desc LIMIT ?,?`, field, m.TableName(), condition)
 	pars = append(pars, startSize, pageSize)
-	err = global.DbMap[utils.DbNameAI].Raw(sqlStr, pars...).Find(&items).Error
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Find(&items).Error
 
 	return
 }
@@ -139,7 +149,7 @@ func (m *AiPredictModelIndexConfig) GetListByCondition(field, condition string,
 func (m *AiPredictModelIndexConfig) GetCountByCondition(condition string, pars []interface{}) (total int, err error) {
 	var intNull sql.NullInt64
 	sqlStr := fmt.Sprintf(`SELECT COUNT(1) total FROM %s WHERE is_deleted=0 %s`, m.TableName(), condition)
-	err = global.DbMap[utils.DbNameAI].Raw(sqlStr, pars...).Scan(&intNull).Error
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Scan(&intNull).Error
 	if err == nil && intNull.Valid {
 		total = int(intNull.Int64)
 	}

+ 132 - 0
models/ai_predict_model/ai_predict_model_index_config_train_data.go

@@ -0,0 +1,132 @@
+package data_manage
+
+import (
+	"database/sql"
+	"eta/eta_api/global"
+	"eta/eta_api/utils"
+	"fmt"
+	"strings"
+	"time"
+)
+
+// AiPredictModelIndexConfigTrainData AI预测模型标的训练数据
+type AiPredictModelIndexConfigTrainData struct {
+	AiPredictModelIndexConfigTrainDataId int             `gorm:"primaryKey;column:ai_predict_model_index_config_train_data_id" description:"-"`
+	AiPredictModelIndexConfigId          int             `gorm:"column:ai_predict_model_index_config_id" description:"标的配置Id"`
+	AiPredictModelIndexId                int             `gorm:"column:ai_predict_model_index_id" description:"标的Id"`
+	IndexCode                            string          `gorm:"column:index_code" description:"指标编码"`
+	DataTime                             time.Time       `gorm:"column:data_time" description:"数据日期"`
+	Value                                sql.NullFloat64 `gorm:"column:value" description:"实际值"`
+	PredictValue                         sql.NullFloat64 `gorm:"column:predict_value" description:"预测值"`
+	Direction                            string          `gorm:"column:direction" description:"方向"`
+	DeviationRate                        string          `gorm:"column:deviation_rate" description:"偏差率"`
+	CreateTime                           time.Time       `gorm:"column:create_time" description:"创建时间"`
+	ModifyTime                           time.Time       `gorm:"column:modify_time" description:"修改时间"`
+	DataTimestamp                        int64           `gorm:"column:data_timestamp" description:"数据日期时间戳"`
+	Source                               uint8           `gorm:"column:source" description:"来源:1-月度预测;2-日度预测"`
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *AiPredictModelIndexConfigTrainData) TableName() string {
+	return "ai_predict_model_index_config_train_data"
+}
+
+// AiPredictModelIndexConfigTrainDataColumns get sql column name.获取数据库列名
+var AiPredictModelIndexConfigTrainDataColumns = struct {
+	AiPredictModelIndexConfigTrainDataId string
+	AiPredictModelIndexConfigId          string
+	AiPredictModelIndexId                string
+	IndexCode                            string
+	DataTime                             string
+	Value                                string
+	PredictValue                         string
+	Direction                            string
+	DeviationRate                        string
+	CreateTime                           string
+	ModifyTime                           string
+	DataTimestamp                        string
+	Source                               string
+}{
+	AiPredictModelIndexConfigTrainDataId: "ai_predict_model_index_config_train_data_id",
+	AiPredictModelIndexConfigId:          "ai_predict_model_index_config_id",
+	AiPredictModelIndexId:                "ai_predict_model_index_id",
+	IndexCode:                            "index_code",
+	DataTime:                             "data_time",
+	Value:                                "value",
+	PredictValue:                         "predict_value",
+	Direction:                            "direction",
+	DeviationRate:                        "deviation_rate",
+	CreateTime:                           "create_time",
+	ModifyTime:                           "modify_time",
+	DataTimestamp:                        "data_timestamp",
+	Source:                               "source",
+}
+
+func (m *AiPredictModelIndexConfigTrainData) Create() (err error) {
+	err = global.DbMap[utils.DbNameIndex].Create(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) Update(updateCols []string) (err error) {
+	err = global.DbMap[utils.DbNameIndex].Select(updateCols).Updates(&m).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetById(id int) (item *AiPredictModelIndexConfigTrainData, err error) {
+	err = global.DbMap[utils.DbNameIndex].Where(fmt.Sprintf("%s = ?", AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigTrainDataId), id).First(&item).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetAllListByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*AiPredictModelIndexConfigTrainData, err error) {
+	o := global.DbMap[utils.DbNameIndex]
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, AiPredictModelIndexConfigTrainDataColumns.AiPredictModelIndexConfigTrainDataId)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sqlRun := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	err = o.Raw(sqlRun, pars...).Find(&items).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetListByCondition(field, condition string, pars []interface{}, startSize, pageSize int) (items []*AiPredictModelIndexConfigTrainData, err error) {
+	if field == "" {
+		field = "*"
+	}
+	sqlStr := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s order by ai_predict_model_index_config_train_data_id desc LIMIT ?,?`, field, m.TableName(), condition)
+	pars = append(pars, startSize, pageSize)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Find(&items).Error
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetCountByCondition(condition string, pars []interface{}) (total int, err error) {
+	var intNull sql.NullInt64
+	sqlStr := fmt.Sprintf(`SELECT COUNT(1) total FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = global.DbMap[utils.DbNameIndex].Raw(sqlStr, pars...).Scan(&intNull).Error
+	if err == nil && intNull.Valid {
+		total = int(intNull.Int64)
+	}
+
+	return
+}
+
+func (m *AiPredictModelIndexConfigTrainData) GetPageListByCondition(condition string, pars []interface{}, startSize, pageSize int) (total int, items []*AiPredictModelIndexConfigTrainData, err error) {
+
+	total, err = m.GetCountByCondition(condition, pars)
+	if err != nil {
+		return
+	}
+	if total > 0 {
+		items, err = m.GetListByCondition(``, condition, pars, startSize, pageSize)
+	}
+
+	return
+}

+ 7 - 2
models/ai_predict_model/response/index_config.go

@@ -1,11 +1,16 @@
 package response
 
 import (
-	data_manage "eta/eta_api/models/ai_predict_model"
+	aiPredictModel "eta/eta_api/models/ai_predict_model"
+	"eta/eta_api/models/data_manage"
 	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 type AiPredictModelIndexConfigListResp struct {
-	List   []data_manage.AiPredictModelIndexConfigView
+	List   []aiPredictModel.AiPredictModelIndexConfigView
 	Paging *paging.PagingItem `description:"分页数据"`
 }
+
+type AiPredictModelDetailResp struct {
+	DailyChartView *data_manage.ChartInfoDetailResp `description:"日度预测数据图表"`
+}

+ 31 - 4
routers/commentsRouter.go

@@ -358,6 +358,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "ChartDetail",
+            Router: `/index_config/chart/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
         beego.ControllerComments{
             Method: "Del",
@@ -369,8 +378,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
         beego.ControllerComments{
-            Method: "CurrVersion",
-            Router: `/index_config/detail`,
+            Method: "List",
+            Router: `/index_config/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -378,8 +387,26 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
         beego.ControllerComments{
-            Method: "List",
-            Router: `/index_config/list`,
+            Method: "SetCurr",
+            Router: `/index_config/set_curr`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "Train",
+            Router: `/index_config/train`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/ai_predict_model:AiPredictModelIndexConfigController"],
+        beego.ControllerComments{
+            Method: "CurrVersion",
+            Router: `/index_config/version/curr`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,

+ 193 - 1
services/ai_predict_model_index.go

@@ -59,7 +59,7 @@ func ImportAiPredictModelIndexAndData(imports []*aiPredictModel.AiPredictModelIm
 				b, _ := json.Marshal(oldConfig)
 				v.Index.ExtraConfig = string(b)
 			}
-			
+
 			v.Index.AiPredictModelIndexId = exist.AiPredictModelIndexId
 			v.Index.IndexCode = exist.IndexCode
 			updateIndexes = append(updateIndexes, v)
@@ -439,3 +439,195 @@ func FixAiPredictCharts() {
 	}
 	return
 }
+func GetAiPredictConfigChartDetailByData(indexName string, indexConfigItem *aiPredictModel.AiPredictModelIndexConfig, indexData []*aiPredictModel.AiPredictModelIndexConfigTrainData, source int) (resp *data_manage.ChartInfoDetailResp, err error) {
+	resp = new(data_manage.ChartInfoDetailResp)
+	// 标的配置
+	extraConfig := aiPredictModel.AiPredictModelIndexExtraConfig{
+		MonthlyChart: aiPredictModel.MonthlyChartConfig{
+			LeftMin: "",
+			LeftMax: "",
+			Unit:    "",
+		},
+		DailyChart: aiPredictModel.DailyChartConfig{
+			LeftMin:           "",
+			LeftMax:           "",
+			Unit:              "",
+			PredictLegendName: "预测值",
+		},
+	}
+
+	// 图表信息
+	var predictLegendName, confLeftMin, confLeftMax, unit string
+	if source == aiPredictModel.ModelDataSourceDaily {
+		predictLegendName = extraConfig.DailyChart.PredictLegendName
+		if predictLegendName == "" {
+			predictLegendName = "Predicted"
+		}
+		unit = extraConfig.DailyChart.Unit
+		confLeftMin = extraConfig.DailyChart.LeftMin
+		confLeftMax = extraConfig.DailyChart.LeftMax
+	}
+	if source == aiPredictModel.ModelDataSourceMonthly {
+		predictLegendName = "预测值"
+		unit = extraConfig.MonthlyChart.Unit
+		confLeftMin = extraConfig.MonthlyChart.LeftMin
+		confLeftMax = extraConfig.MonthlyChart.LeftMax
+	}
+	// 这里简单兼容下吧,暂时就不修数据了
+	if confLeftMin == "" {
+		confLeftMin = indexConfigItem.LeftMin
+	}
+	if confLeftMax == "" {
+		confLeftMax = indexConfigItem.LeftMax
+	}
+
+	// 获取曲线图主题样式
+	chartView := new(data_manage.ChartInfoView)
+	chartView.ChartName = indexName
+	chartView.ChartNameEn = indexName
+	chartView.ChartType = utils.CHART_SOURCE_DEFAULT
+	chartTheme, e := data.GetChartThemeConfig(0, chartView.ChartType, utils.CHART_TYPE_CURVE)
+	if e != nil {
+		err = fmt.Errorf("获取图表主题样式失败, %v", e)
+		return
+	}
+	chartView.ChartThemeStyle = chartTheme.Config
+	chartView.ChartThemeId = chartTheme.ChartThemeId
+
+	chartView.DateType = 3
+	chartView.Calendar = "公历"
+	chartView.ChartSource = "AI预测模型"
+	chartView.ChartSourceEn = "AI预测模型"
+	chartView.Unit = unit
+	chartView.UnitEn = unit
+
+	// EdbList-固定一条为标的实际值、一条为预测值
+	edbList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	edbActual, edbPredict := new(data_manage.ChartEdbInfoMapping), new(data_manage.ChartEdbInfoMapping)
+	edbActual.EdbName = indexName
+	edbActual.EdbNameEn = indexName
+	edbActual.IsAxis = 1
+	edbActual.Unit = unit
+	edbActual.UnitEn = unit
+
+	edbPredict.EdbName = predictLegendName
+	edbPredict.EdbNameEn = predictLegendName
+	edbPredict.IsAxis = 1
+	edbPredict.Unit = unit
+	edbPredict.UnitEn = unit
+	actualData, predictData := make([]*data_manage.EdbDataList, 0), make([]*data_manage.EdbDataList, 0)
+
+	var startDate, endDate time.Time
+	var actualValues, predictValues []float64
+	var actualNewest, predictNewest bool
+	var actualLatestTimestamp int64 // 实际值最后一天的时间戳,作为日度图表的分割线
+	for k, v := range indexData {
+		// 如果实际值和预测值都是null那么该日期无效直接忽略
+		if !v.Value.Valid && !v.PredictValue.Valid {
+			continue
+		}
+
+		// 将有效值加入[]float64,最后取极值
+		if v.Value.Valid {
+			actualValues = append(actualValues, v.Value.Float64)
+		}
+		if v.PredictValue.Valid {
+			predictValues = append(predictValues, v.PredictValue.Float64)
+		}
+
+		// 开始结束时间
+		if k == 0 {
+			startDate = v.DataTime
+			endDate = v.CreateTime
+		}
+		if v.DataTime.Before(startDate) {
+			startDate = v.DataTime
+		}
+		if v.DataTime.After(endDate) {
+			endDate = v.DataTime
+		}
+
+		// 指标数据
+		if v.Value.Valid {
+			if !actualNewest {
+				edbActual.LatestDate = v.DataTime.Format(utils.FormatDate)
+				edbActual.LatestValue = v.Value.Float64
+				actualLatestTimestamp = v.DataTime.UnixNano() / 1e6
+				actualNewest = true
+			}
+			actualData = append(actualData, &data_manage.EdbDataList{
+				DataTime:      v.DataTime.Format(utils.FormatDate),
+				Value:         v.Value.Float64,
+				DataTimestamp: v.DataTimestamp,
+			})
+		}
+		if v.PredictValue.Valid {
+			if !predictNewest {
+				edbPredict.LatestDate = v.DataTime.Format(utils.FormatDate)
+				edbPredict.LatestValue = v.Value.Float64
+				predictNewest = true
+			}
+			predictData = append(predictData, &data_manage.EdbDataList{
+				DataTime:      v.DataTime.Format(utils.FormatDate),
+				Value:         v.PredictValue.Float64,
+				DataTimestamp: v.DataTimestamp,
+			})
+		}
+	}
+
+	// 图表数据这里均做一个升序排序
+	sort.Slice(actualData, func(i, j int) bool {
+		return actualData[i].DataTimestamp < actualData[j].DataTimestamp
+	})
+	sort.Slice(predictData, func(i, j int) bool {
+		return predictData[i].DataTimestamp < predictData[j].DataTimestamp
+	})
+
+	// 极值
+	actualMin, actualMax := utils.FindMinMax(actualValues)
+	predictMin, predictMax := utils.FindMinMax(predictValues)
+	edbActual.MinData = actualMin
+	edbActual.MaxData = actualMax
+	edbPredict.MinData = predictMin
+	edbPredict.MaxData = predictMax
+
+	edbActual.DataList = actualData
+	edbPredict.DataList = predictData
+	edbList = append(edbList, edbActual, edbPredict)
+
+	// 上下限
+	if confLeftMin != "" {
+		chartView.LeftMin = confLeftMin
+	} else {
+		leftMin := actualMin
+		if leftMin > predictMin {
+			leftMin = predictMin
+		}
+		chartView.LeftMin = fmt.Sprint(leftMin)
+	}
+	if confLeftMax != "" {
+		chartView.LeftMax = confLeftMax
+	} else {
+		leftMax := actualMax
+		if leftMax < predictMax {
+			leftMax = predictMax
+		}
+		chartView.LeftMax = fmt.Sprint(leftMax)
+	}
+
+	chartView.StartDate = startDate.Format(utils.FormatDate)
+	chartView.EndDate = endDate.Format(utils.FormatDate)
+
+	// 日度图表的分割线日期
+	if source == aiPredictModel.ModelDataSourceDaily {
+		var dataResp struct {
+			ActualLatestTimestamp int64
+		}
+		dataResp.ActualLatestTimestamp = actualLatestTimestamp
+		resp.DataResp = dataResp
+	}
+
+	resp.ChartInfo = chartView
+	resp.EdbInfoList = edbList
+	return
+}