浏览代码

Merge remote-tracking branch 'origin/master'

Roc 1 年之前
父节点
当前提交
422fddaa1b

+ 80 - 6
controllers/data_manage/chart_framework.go

@@ -5,6 +5,8 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"strings"
@@ -75,7 +77,7 @@ func (this *ChartFrameworkController) List() {
 	}
 	resp := make([]*data_manage.ChartFrameworkItem, 0)
 	for _, v := range list {
-		t := data_manage.FormatChartFramework2Item(v)
+		t := data_manage.FormatChartFramework2Item(v, make([]*data_manage.ChartFrameworkNodeItem, 0))
 		resp = append(resp, t)
 	}
 
@@ -119,10 +121,25 @@ func (this *ChartFrameworkController) PublicMenu() {
 		return
 	}
 
+	// 用户被删除不展示框架
+	admins, e := system.GetSysAdminList(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取系统用户列表失败, Err: " + e.Error()
+		return
+	}
+	adminExist := make(map[int]bool)
+	for _, v := range admins {
+		adminExist[v.AdminId] = true
+	}
+
 	userExist := make(map[int]bool)
 	userFrameworks := make(map[int][]*data_manage.ChartFrameworkItem)
 	resp := make([]*data_manage.ChartFrameworkPublicMenuItem, 0)
 	for _, v := range list {
+		if !adminExist[v.AdminId] {
+			continue
+		}
 		if !userExist[v.AdminId] {
 			u := new(data_manage.ChartFrameworkPublicMenuItem)
 			u.AdminId = v.AdminId
@@ -130,7 +147,7 @@ func (this *ChartFrameworkController) PublicMenu() {
 			resp = append(resp, u)
 			userExist[v.AdminId] = true
 		}
-		t := data_manage.FormatChartFramework2Item(v)
+		t := data_manage.FormatChartFramework2Item(v, make([]*data_manage.ChartFrameworkNodeItem, 0))
 		if userFrameworks[v.AdminId] == nil {
 			userFrameworks[v.AdminId] = make([]*data_manage.ChartFrameworkItem, 0)
 		}
@@ -199,6 +216,14 @@ func (this *ChartFrameworkController) Add() {
 		}
 	}
 
+	// 获取图表分类下各自的图表数
+	chartsNumMap, e := data.GetMyChartClassifyIdNumMap(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败, GetMyChartClassifyIdNumMap Err: " + e.Error()
+		return
+	}
+
 	now := time.Now().Local()
 	frameworkCode := utils.MD5(fmt.Sprint(now.UnixMilli()))
 	item := new(data_manage.ChartFramework)
@@ -211,6 +236,7 @@ func (this *ChartFrameworkController) Add() {
 	item.CreateTime = now
 	item.ModifyTime = now
 	nodes := make([]*data_manage.ChartFrameworkNode, 0)
+	itemNodes := make([]*data_manage.ChartFrameworkNodeItem, 0)
 	if len(req.Nodes) > 0 {
 		for _, v := range req.Nodes {
 			if v.MyChartClassifyId <= 0 {
@@ -218,10 +244,15 @@ func (this *ChartFrameworkController) Add() {
 			}
 			t := new(data_manage.ChartFrameworkNode)
 			t.FrameworkName = req.FrameworkName
+			t.NodeId = v.NodeId
 			t.NodeName = v.NodeName
 			t.MyChartClassifyId = v.MyChartClassifyId
 			t.CreateTime = now
 			nodes = append(nodes, t)
+
+			// 响应节点数据
+			td := data_manage.FormatChartFrameworkNode2Item(t, chartsNumMap[t.MyChartClassifyId])
+			itemNodes = append(itemNodes, td)
 		}
 	}
 	if e := item.CreateFrameworkAndNodes(item, nodes); e != nil {
@@ -229,7 +260,7 @@ func (this *ChartFrameworkController) Add() {
 		br.ErrMsg = "新增框架及节点失败, Err: " + e.Error()
 		return
 	}
-	detail := data_manage.FormatChartFramework2Item(item)
+	detail := data_manage.FormatChartFramework2Item(item, itemNodes)
 
 	br.Data = detail
 	br.Ret = 200
@@ -308,6 +339,14 @@ func (this *ChartFrameworkController) Edit() {
 		}
 	}
 
+	// 获取图表分类下各自的图表数
+	chartsNumMap, e := data.GetMyChartClassifyIdNumMap(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败, GetMyChartClassifyIdNumMap Err: " + e.Error()
+		return
+	}
+
 	now := time.Now().Local()
 	item.FrameworkName = req.FrameworkName
 	item.FrameworkImg = req.FrameworkImg
@@ -315,6 +354,7 @@ func (this *ChartFrameworkController) Edit() {
 	item.ModifyTime = now
 	updateCols := []string{"FrameworkName", "FrameworkImg", "FrameworkContent", "ModifyTime"}
 	nodes := make([]*data_manage.ChartFrameworkNode, 0)
+	itemNodes := make([]*data_manage.ChartFrameworkNodeItem, 0)
 	if len(req.Nodes) > 0 {
 		for _, v := range req.Nodes {
 			if v.MyChartClassifyId <= 0 {
@@ -323,10 +363,15 @@ func (this *ChartFrameworkController) Edit() {
 			t := new(data_manage.ChartFrameworkNode)
 			t.ChartFrameworkId = req.ChartFrameworkId
 			t.FrameworkName = req.FrameworkName
+			t.NodeId = v.NodeId
 			t.NodeName = v.NodeName
 			t.MyChartClassifyId = v.MyChartClassifyId
 			t.CreateTime = now
 			nodes = append(nodes, t)
+
+			// 响应节点数据
+			td := data_manage.FormatChartFrameworkNode2Item(t, chartsNumMap[t.MyChartClassifyId])
+			itemNodes = append(itemNodes, td)
 		}
 	}
 	if e := item.EditFrameworkAndNodes(item, updateCols, nodes); e != nil {
@@ -334,7 +379,7 @@ func (this *ChartFrameworkController) Edit() {
 		br.ErrMsg = "编辑框架及节点失败, Err: " + e.Error()
 		return
 	}
-	detail := data_manage.FormatChartFramework2Item(item)
+	detail := data_manage.FormatChartFramework2Item(item, itemNodes)
 
 	br.Data = detail
 	br.Ret = 200
@@ -715,11 +760,40 @@ func (this *ChartFrameworkController) Detail() {
 			br.Msg = "框架不存在, 请刷新页面"
 			return
 		}
-		br.Msg = "操作失败"
+		br.Msg = "获取失败"
 		br.ErrMsg = "获取框架失败, Err: " + e.Error()
 		return
 	}
-	detail := data_manage.FormatChartFramework2Item(item)
+
+	// 获取节点
+	nodeOb := new(data_manage.ChartFrameworkNode)
+	nodeCond := ` AND chart_framework_id = ?`
+	nodePars := make([]interface{}, 0)
+	nodePars = append(nodePars, frameworkId)
+	nodes, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取框架节点失败, Err: " + e.Error()
+		return
+	}
+
+	// 获取图表分类下各自的图表数
+	chartsNumMap, e := data.GetMyChartClassifyIdNumMap(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败, GetMyChartClassifyIdNumMap Err: " + e.Error()
+		return
+	}
+
+	// 格式化响应数据
+	itemNodes := make([]*data_manage.ChartFrameworkNodeItem, 0)
+	for _, v := range nodes {
+		if v.NodeId == "" {
+			continue
+		}
+		itemNodes = append(itemNodes, data_manage.FormatChartFrameworkNode2Item(v, chartsNumMap[v.MyChartClassifyId]))
+	}
+	detail := data_manage.FormatChartFramework2Item(item, itemNodes)
 
 	br.Data = detail
 	br.Ret = 200

+ 7 - 1
controllers/data_manage/edb_info.go

@@ -1673,7 +1673,13 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				}
 				isAdd = true
 			}
-
+			// 查询基本信息
+			baseIndexInfo, tErr := data_manage.GetBaseIndexInfoByEdbCode(edbCode, source)
+			if tErr == nil {
+				searchItem.EdbName = baseIndexInfo.IndexName
+				searchItem.Frequency = baseIndexInfo.Frequency
+				searchItem.Unit = baseIndexInfo.Unit
+			}
 			// 指标来源于桥接服务: 桥接服务获取指标取频度信息等
 			if sourceItem.BridgeFlag != "" {
 				bridgeOb := data.InitBridgeOB(sourceItem.BridgeFlag)

+ 17 - 5
controllers/data_manage/edb_info_calculate.go

@@ -134,11 +134,19 @@ func (this *ChartInfoController) CalculateSave() {
 		formulaStr += v.FromTag + ","
 		edbInfoIdBytes = append(edbInfoIdBytes, v.FromTag)
 	}
-	formulaMap := data.CheckFormula(req.CalculateFormula)
-	for _, v := range formulaMap {
-		if !strings.Contains(formulaStr, v) {
-			br.Msg = "公式错误,请重新填写"
-			return
+
+	formulaSlice, err := data.CheckFormulaJson(req.CalculateFormula)
+	if err != nil {
+		br.Msg = "公式格式错误,请重新填写"
+		return
+	}
+	for _, formula := range formulaSlice {
+		formulaMap := data.CheckFormula(formula)
+		for _, v := range formulaMap {
+			if !strings.Contains(formulaStr, v) {
+				br.Msg = "公式错误,请重新填写"
+				return
+			}
 		}
 	}
 
@@ -153,6 +161,8 @@ func (this *ChartInfoController) CalculateSave() {
 		ClassifyId:       req.ClassifyId,
 		CalculateFormula: req.CalculateFormula,
 		EdbInfoIdArr:     req.EdbInfoIdArr,
+		EmptyType:        req.EmptyType,
+		MaxEmptyType:     req.MaxEmptyType,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {
@@ -422,6 +432,8 @@ func (this *ChartInfoController) CalculateEdit() {
 		ClassifyId:       req.ClassifyId,
 		CalculateFormula: req.CalculateFormula,
 		EdbInfoIdArr:     req.EdbInfoIdArr,
+		EmptyType:        req.EmptyType,
+		MaxEmptyType:     req.MaxEmptyType,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {

+ 54 - 14
controllers/data_manage/my_chart.go

@@ -189,6 +189,7 @@ func (this *MyChartController) ChartList() {
 	br.Data = resp
 }
 
+// ClassifyList
 // @Title 我的图表-分类列表接口
 // @Description 我的图表-分类列表接口
 // @Success 200 {object} data_manage.MyChartClassifyResp
@@ -218,14 +219,28 @@ func (this *MyChartController) ClassifyList() {
 
 	resp := new(data_manage.MyChartClassifyResp)
 	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
-		items := make([]*data_manage.MyChartClassify, 0)
+		items := make([]*data_manage.MyChartClassifyItem, 0)
 		resp.List = items
 		br.Ret = 200
 		br.Success = true
 		br.Msg = "获取成功"
 		return
 	}
-	resp.List = list
+	//resp.List = list
+
+	// 获取图表分类下各自的图表数
+	chartsNumMap, e := data.GetMyChartClassifyIdNumMap(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败, GetMyChartClassifyIdNumMap Err: " + e.Error()
+		return
+	}
+
+	results := make([]*data_manage.MyChartClassifyItem, 0)
+	for _, v := range list {
+		results = append(results, data_manage.FormatMyChartClassify2Item(v, chartsNumMap[v.MyChartClassifyId]))
+	}
+	resp.List = results
 
 	language := `CN`
 	// 指标显示的语言
@@ -1670,15 +1685,14 @@ func (this *MyChartController) PublicClassifyList() {
 
 	resp := new(data_manage.PublicChartClassifyResp)
 	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
-		items := make([]data_manage.PublicChartClassifyItem, 0)
-		resp.List = items
+		resp.List = make([]data_manage.PublicChartClassifyList, 0)
 		br.Ret = 200
 		br.Success = true
 		br.Msg = "获取成功"
 		return
 	}
-	publicChartClassifyItemList := make([]data_manage.PublicChartClassifyItem, 0)
 
+	// 创建人姓名
 	adminIdStr := make([]string, 0)
 	for _, v := range list {
 		adminIdStr = append(adminIdStr, fmt.Sprint(v.AdminId))
@@ -1691,22 +1705,42 @@ func (this *MyChartController) PublicClassifyList() {
 		}
 	}
 
+	respList := make([]data_manage.PublicChartClassifyList, 0)
+	existMap := make(map[int]bool, 0)
+	itemsMap := make(map[int][]data_manage.PublicChartClassifyItem, 0)
 	for _, v := range list {
-		realName, ok := adminMap[v.AdminId]
-		if !ok {
-			realName = ``
+		realName := adminMap[v.AdminId]
+		if realName == "" {
+			// 忽略掉被删掉的用户
+			continue
 		}
-		publicChartClassifyItem := data_manage.PublicChartClassifyItem{
+
+		if itemsMap[v.AdminId] == nil {
+			itemsMap[v.AdminId] = make([]data_manage.PublicChartClassifyItem, 0)
+		}
+		itemsMap[v.AdminId] = append(itemsMap[v.AdminId], data_manage.PublicChartClassifyItem{
 			MyChartClassifyId:   v.MyChartClassifyId,
 			MyChartClassifyName: v.MyChartClassifyName,
 			AdminId:             v.AdminId,
 			RealName:            realName,
 			IsPublic:            v.IsPublic,
 			IsCompanyPublic:     v.IsCompanyPublic,
+		})
+
+		var menu data_manage.PublicChartClassifyList
+		if existMap[v.AdminId] {
+			continue
 		}
-		publicChartClassifyItemList = append(publicChartClassifyItemList, publicChartClassifyItem)
+		existMap[v.AdminId] = true
+		menu.MenuAdminId = v.AdminId
+		menu.MenuName = fmt.Sprintf("%s的图库", realName)
+		respList = append(respList, menu)
+	}
+
+	for k, v := range respList {
+		respList[k].Items = itemsMap[v.MenuAdminId]
 	}
-	resp.List = publicChartClassifyItemList
+	resp.List = respList
 
 	language := `CN`
 	// 指标显示的语言
@@ -1995,7 +2029,7 @@ func (this *MyChartController) CompanyPublicClassifyList() {
 
 	resp := new(data_manage.MyChartClassifyResp)
 	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
-		items := make([]*data_manage.MyChartClassify, 0)
+		items := make([]*data_manage.MyChartClassifyItem, 0)
 		resp.List = items
 		br.Ret = 200
 		br.Success = true
@@ -2003,7 +2037,13 @@ func (this *MyChartController) CompanyPublicClassifyList() {
 		return
 	}
 
-	resp.List = list
+	results := make([]*data_manage.MyChartClassifyItem, 0)
+	for _, v := range list {
+		results = append(results, data_manage.FormatMyChartClassify2Item(v, 0))
+	}
+	resp.List = results
+
+	//resp.List = list
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
@@ -2066,7 +2106,7 @@ func (this *MyChartController) ClassifyFrameworkNodeList() {
 	}
 	resp := make([]*data_manage.ChartFrameworkNodeItem, 0)
 	for _, v := range nodes {
-		resp = append(resp, data_manage.FormatChartFrameworkNode2Item(v))
+		resp = append(resp, data_manage.FormatChartFrameworkNode2Item(v, 0))
 	}
 
 	br.Data = resp

+ 33 - 37
controllers/data_manage/predict_edb_info.go

@@ -913,6 +913,8 @@ func (this *PredictEdbInfoController) Detail() {
 				RuleType:         v.RuleType,
 				FixedValue:       v.FixedValue,
 				Value:            v.Value,
+				EmptyType:        v.EmptyType,
+				MaxEmptyType:     v.MaxEmptyType,
 				EndDate:          v.EndDate,
 				ModifyTime:       v.ModifyTime,
 				CreateTime:       v.CreateTime,
@@ -1485,7 +1487,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 		switch v.RuleType {
 		case 9:
 			// 获取计算参数
-			formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(v)
+			/*formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(v)
 			if err != nil {
 				br.Msg = "计算失败"
 				if errMsg != "" {
@@ -1496,13 +1498,26 @@ func (this *PredictEdbInfoController) ChartDataList() {
 				return
 			}
 			// 获取计算数据
-			tmpDataList, err = data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes)
+			tmpDataList, err = data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes, v.EmptyType, v.MaxEmptyType)
 			if err != nil {
 				br.Msg = "计算失败"
 				br.ErrMsg = err.Error()
 				br.IsSendEmail = false
 				return
+			}*/
+			reqJson, err := json.Marshal(v)
+			respItem, err := data.PredictCalculateByNinePreview(string(reqJson))
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取失败,Err:" + err.Error()
+				return
+			}
+			if respItem.Ret != 200 {
+				br.Msg = respItem.Msg
+				br.ErrMsg = respItem.ErrMsg
+				return
 			}
+			tmpDataList = respItem.Data.DataList
 		}
 		tmpPredictEdbConfAndData := data_manage.PredictEdbConfAndData{
 			ConfigId:         0,
@@ -1641,7 +1656,6 @@ func (this *PredictEdbInfoController) PredictRuleCalculateByNine() {
 		this.ServeJSON()
 	}()
 	sysUser := this.SysUser
-	time.Now().AddDate(0, -1, -1).Format(utils.FormatDate)
 	if sysUser == nil {
 		br.Msg = "请登录"
 		br.ErrMsg = "请登录,SysUser Is Empty"
@@ -1650,49 +1664,31 @@ func (this *PredictEdbInfoController) PredictRuleCalculateByNine() {
 	}
 	var req request.RuleConfig
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
-
-	// 获取计算参数
-	formula, edbInfoList, edbInfoIdBytes, err, errMsg := data.GetCalculateByRuleByNineParams(req)
 	if err != nil {
-		br.Msg = "计算失败"
-		if errMsg != "" {
-			br.Msg = errMsg
-		}
-		br.Msg = err.Error()
-		br.IsSendEmail = false
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
-	// 获取计算数据
-	dataList, err := data.CalculateByRuleByNine(formula, edbInfoList, edbInfoIdBytes)
+	// 添加计算指标
+	reqJson, err := json.Marshal(req)
 	if err != nil {
-		br.Msg = "数据计算失败"
-		br.ErrMsg = "数据计算失败:Err:" + err.Error()
-		br.IsSendEmail = false
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
 
-	latestDate := time.Now()
-	for _, v := range edbInfoList {
-		tmpLatestDate, err := time.ParseInLocation(utils.FormatDate, v.LatestDate, time.Local)
-		if err != nil {
-			continue
-		}
-		if tmpLatestDate.Before(latestDate) {
-			latestDate = tmpLatestDate
-		}
-	}
-
-	newDataList := make([]*data_manage.EdbDataList, 0)
-	lenData := len(dataList)
-	if lenData > 0 {
-		for i := lenData - 1; i >= 0; i-- {
-			newDataList = append(newDataList, dataList[i])
-		}
+	respItem, err := data.PredictCalculateByNinePreview(string(reqJson))
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
 	}
-	resp := response.PredictRuleCalculateByNineResp{
-		LatestDate: latestDate.Format(utils.FormatDate),
-		DataList:   newDataList,
+	if respItem.Ret != 200 {
+		br.Msg = respItem.Msg
+		br.ErrMsg = respItem.ErrMsg
+		return
 	}
+	resp := respItem.Data
 
 	br.Ret = 200
 	br.Success = true

+ 443 - 0
controllers/data_manage/yongyi_data.go

@@ -0,0 +1,443 @@
+package data_manage
+
+import (
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/tealeg/xlsx"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+// YongyiClassify
+// @Title 涌益咨询数据分类
+// @Description 涌益咨询数据分类接口
+// @Success 200 {object} data_manage.BaseFromYongyiClassify
+// @router /yongyi/classify [get]
+func (this *EdbInfoController) YongyiClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	classifyAll, err := data_manage.GetAllBaseFromYongyiClassify()
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	var ret data_manage.BaseFromYongyiClassifyResp
+	ret.List = classifyAll
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
+// YongyiIndexData
+// @Title 获取钢联数据
+// @Description 获取钢联数据接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ClassifyId   query   string  true       "分类id"
+// @Success 200 {object} data_manage.LzFrequency
+// @router /yongyi/index/data [get]
+func (this *EdbInfoController) YongyiIndexData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		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 = utils.StartIndex(currentIndex, pageSize)
+
+	classifyId, _ := this.GetInt("ClassifyId")
+	if classifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	//获取指标
+	var condition string
+	var pars []interface{}
+
+	if classifyId >= 0 {
+		condition += ` AND classify_id=? `
+		pars = append(pars, classifyId)
+	}
+
+	yongyiList, err := data_manage.GetYongyiIndex(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	resultList := make([]*data_manage.BaseFromYongyiIndexList, 0)
+	for _, v := range yongyiList {
+		product := new(data_manage.BaseFromYongyiIndexList)
+		product.YongyiIndexId = v.YongyiIndexId
+		product.Unit = v.Unit
+		product.IndexCode = v.IndexCode
+		product.IndexName = v.IndexName
+		product.Frequency = v.Frequency
+		product.ModifyTime = v.ModifyTime
+
+		total, err := data_manage.GetYongyiIndexDataCount(v.IndexCode)
+		page := paging.GetPaging(currentIndex, pageSize, total)
+		dataList, err := data_manage.GetYongyiIndexData(v.IndexCode, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		if dataList == nil {
+			dataList = make([]*data_manage.BaseFromYongyiData, 0)
+		}
+		product.DataList = dataList
+		product.Paging = page
+		resultList = append(resultList, product)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resultList
+}
+
+// YongyiSearchList
+// @Title Yongyi模糊搜索
+// @Description Yongyi模糊搜索
+// @Param   Keyword   query   string  ture       "关键字搜索"
+// @Success 200 {object} models.BaseResponse
+// @router /yongyi/search_list [get]
+func (this *EdbInfoController) YongyiSearchList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	list := make([]*data_manage.BaseFromYongyiIndexSearchItem, 0)
+	var err error
+	//关键字
+	keyword := this.GetString("Keyword")
+	if keyword != "" {
+		keyWordArr := strings.Split(keyword, " ")
+
+		if len(keyWordArr) > 0 {
+			condition := ""
+			for _, v := range keyWordArr {
+				condition += ` AND CONCAT(index_name,index_code) LIKE '%` + v + `%'`
+			}
+			list, err = data_manage.GetYongyiItemList(condition)
+			if err != nil {
+				br.ErrMsg = "获取失败,Err:" + err.Error()
+				br.Msg = "获取失败"
+				return
+			}
+		}
+
+	} else {
+		// todo es 模糊搜索
+		list, err = data_manage.GetYongyiItemList("")
+		if err != nil {
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			br.Msg = "获取失败"
+			return
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// YongyiSingleData
+// @Title 获取Yongyi数据
+// @Description 获取Yongyi单条数据接口
+// @Param   IndexCode   query   string  true       "指标唯一编码"
+// @Success 200 {object} models.BaseResponse
+// @router /yongyi/single_data [get]
+func (this *EdbInfoController) YongyiSingleData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	indexCode := this.GetString("IndexCode")
+	indexInfo, err := data_manage.GetBaseFromYongyiIndexByIndexCode(indexCode)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	dataTmpList, err := data_manage.GetYongyiIndexDataByCode(indexCode)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	var ret data_manage.YongyiSingleDataResp
+	var dataList []*data_manage.YongyiSingleData
+
+	ret.ClassifyId = indexInfo.ClassifyId
+	ret.YongyiIndexId = indexInfo.YongyiIndexId
+	ret.IndexCode = indexInfo.IndexCode
+	ret.IndexName = indexInfo.IndexName
+	ret.Frequency = indexInfo.Frequency
+	ret.CreateTime = indexInfo.CreateTime.Format(utils.FormatDateTime)
+	ret.ModifyTime = indexInfo.ModifyTime.Format(utils.FormatDateTime)
+	ret.Unit = indexInfo.Unit
+	for _, v := range dataTmpList {
+		tmp := &data_manage.YongyiSingleData{
+			Value:    v.Value,
+			DataTime: v.DataTime,
+		}
+		dataList = append(dataList, tmp)
+	}
+	ret.Data = dataList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
+// ExportYongyiList
+// @Title 导出Yongyi数据
+// @Description 导出Yongyi数据
+// @Param   IndexName   query   string  false       "名称关键词"
+// @Param   IndexCode   query   string  false       "指标唯一编码"
+// @Param   ClassifyId   query   string  true       "分类"
+// @Success 200  导出成功
+// @router /yongyi/export [get]
+func (this *EdbInfoController) ExportYongyiList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	indexCode := this.GetString("IndexCode") //指标唯一编码
+	classifyId, _ := this.GetInt("ClassifyId")
+	//secNameList := make([]*models.EdbdataExportList, 0)
+
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+
+	var pars []interface{}
+	condition := ""
+	if classifyId > 0 {
+		//获取指标
+		condition += " AND classify_id=?"
+		pars = append(pars, classifyId)
+	}
+	if indexCode != "" {
+		//获取指标
+		condition += " AND index_code=?"
+		pars = append(pars, indexCode)
+	}
+	indexList, err := data_manage.GetYongyiIndex(condition, pars)
+	if err != nil {
+		fmt.Println("获取数据失败,Err:" + err.Error())
+		return
+	}
+	if len(indexList) <= 0 {
+		fmt.Println("indexList 为空")
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "success"
+		return
+	}
+	sheetNew := new(xlsx.Sheet)
+	// todo 分类名称
+	sheetNew, err = xlsxFile.AddSheet("涌益咨询")
+	//sheetNew.SetColWidth()
+	//获取指标数据
+	windRow := sheetNew.AddRow()
+	secNameRow := sheetNew.AddRow()
+	indexCodeRow := sheetNew.AddRow()
+	frequencyRow := sheetNew.AddRow()
+	unitRow := sheetNew.AddRow()
+	lastModifyDateRow := sheetNew.AddRow()
+	//获取分类下指标最大数据量
+	var dataMax int
+	setRowIndex := 6
+	indexCodeList := make([]string, 0)
+	for _, v := range indexList {
+		indexCodeList = append(indexCodeList, v.IndexCode)
+	}
+	dataListMap := make(map[string][]*data_manage.BaseFromYongyiData)
+	if len(indexList) > 0 {
+		allDataList, e := data_manage.GetYongyiIndexDataByCodes(indexCodeList)
+		if e != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取数据失败,Err:" + e.Error()
+			return
+		}
+		for _, v := range allDataList {
+			dataListMap[v.IndexCode] = append(dataListMap[v.IndexCode], v)
+		}
+		for _, v := range dataListMap {
+			if len(v) > dataMax {
+				dataMax = len(v)
+			}
+		}
+	}
+
+	for k, sv := range indexList {
+		//获取数据
+		dataList, ok := dataListMap[sv.IndexCode]
+		if !ok {
+			continue
+		}
+		if len(dataList) > 0 {
+			windRow.AddCell().SetValue("涌益咨询")
+			secNameRow.AddCell().SetValue("指标名称")
+			indexCodeRow.AddCell().SetValue("指标ID")
+			frequencyRow.AddCell().SetValue("频率")
+			unitRow.AddCell().SetValue("单位")
+			lastModifyDateRow.AddCell().SetValue("更新时间")
+
+			secNameRow.AddCell().SetValue(sv.IndexName)
+			indexCodeRow.AddCell().SetValue(sv.IndexCode)
+			frequencyRow.AddCell().SetValue(sv.Frequency)
+
+			unitRow.AddCell().SetValue(sv.Unit)
+			lastModifyDateRow.AddCell().SetValue(sv.ModifyTime)
+
+			windRow.AddCell()
+			windRow.AddCell()
+			secNameRow.AddCell()
+			indexCodeRow.AddCell()
+			frequencyRow.AddCell()
+			unitRow.AddCell()
+			lastModifyDateRow.AddCell()
+			min := k * 3
+			sheetNew.SetColWidth(min, min, 15)
+
+			if len(dataList) <= 0 {
+				for n := 0; n < dataMax; n++ {
+					rowIndex := setRowIndex + n
+					row := sheetNew.Row(rowIndex)
+					row.AddCell()
+					row.AddCell()
+					row.AddCell()
+				}
+			} else {
+				endRowIndex := 0
+				for rk, dv := range dataList {
+					rowIndex := setRowIndex + rk
+					row := sheetNew.Row(rowIndex)
+					displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
+					displayDateCell := row.AddCell()
+					style := new(xlsx.Style)
+					style.ApplyAlignment = true
+					style.Alignment.WrapText = true
+					displayDateCell.SetStyle(style)
+					displayDateCell.SetDate(displayDate)
+
+					row.AddCell().SetValue(dv.Value)
+					row.AddCell()
+					endRowIndex = rowIndex
+				}
+				if len(dataList) < dataMax {
+					dataLen := dataMax - len(dataList)
+					for n := 0; n < dataLen; n++ {
+						rowIndex := (endRowIndex + 1) + n
+						row := sheetNew.Row(rowIndex)
+						row.AddCell()
+						row.AddCell()
+						row.AddCell()
+					}
+				}
+			}
+		}
+	}
+
+	err = xlsxFile.Save(downLoadnFilePath)
+	if err != nil {
+		//有指标无数据时先导出一遍空表
+		sheet, err := xlsxFile.AddSheet("无数据")
+		if err != nil {
+			br.Msg = "新增Sheet失败"
+			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
+			return
+		}
+		rowSecName := sheet.AddRow()
+		celSecName := rowSecName.AddCell()
+		celSecName.SetValue("")
+		err = xlsxFile.Save(downLoadnFilePath)
+		if err != nil {
+			br.Msg = "保存文件失败"
+			br.ErrMsg = "保存文件失败"
+			return
+		}
+	}
+	fileName := `涌益咨询数据`
+	if len(indexList) > 0 {
+		fileName = indexList[0].IndexName
+	}
+	fileName += time.Now().Format("06.01.02") + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+
+}

+ 13 - 4
controllers/smart_report/smart_report.go

@@ -97,7 +97,10 @@ func (this *SmartReportController) Add() {
 	item.CreateTime = time.Now().Local()
 	item.ModifyTime = time.Now().Local()
 	item.ContentModifyTime = time.Now().Local()
-
+	item.HeadImg = req.HeadImg
+	item.EndImg = req.EndImg
+	item.CanvasColor = req.CanvasColor
+	
 	// 继承报告
 	if req.AddType == 2 {
 		ob := new(smart_report.SmartReport)
@@ -233,7 +236,7 @@ func (this *SmartReportController) Edit() {
 		contentModify = true
 	}
 	cols := []string{"ClassifyIdFirst", "ClassifyNameFirst", "ClassifyIdSecond", "ClassifyNameSecond", "Title", "Abstract", "Author",
-		"Frequency", "Content", "ContentSub", "ContentStruct", "ModifyTime"}
+		"Frequency", "Content", "ContentSub", "ContentStruct", "ModifyTime", "HeadImg", "EndImg", "CanvasColor"}
 	item.ClassifyIdFirst = req.ClassifyIdFirst
 	item.ClassifyNameFirst = req.ClassifyNameFirst
 	item.ClassifyIdSecond = req.ClassifyIdSecond
@@ -246,6 +249,9 @@ func (this *SmartReportController) Edit() {
 	item.ContentSub = subContent
 	item.ContentStruct = req.ContentStruct
 	item.ModifyTime = time.Now().Local()
+	item.HeadImg = req.HeadImg
+	item.EndImg = req.EndImg
+	item.CanvasColor = req.CanvasColor
 	if contentModify {
 		//fmt.Println(contentModify)
 		item.LastModifyAdminId = sysUser.AdminId
@@ -756,7 +762,10 @@ func (this *SmartReportController) SaveContent() {
 		item.LastModifyAdminId = sysUser.AdminId
 		item.LastModifyAdminName = sysUser.RealName
 		item.ModifyTime = time.Now().Local()
-		cols := []string{"Content", "ContentSub", "ContentStruct", "ContentModifyTime", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}
+		item.HeadImg = req.HeadImg
+		item.EndImg = req.EndImg
+		item.CanvasColor = req.CanvasColor
+		cols := []string{"Content", "ContentSub", "ContentStruct", "ContentModifyTime", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime", "HeadImg", "EndImg", "CanvasColor"}
 		if e = item.Update(cols); e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = "更新报告内容失败"
@@ -973,7 +982,7 @@ func (this *SmartReportController) List() {
 		"smart_report_id", "report_code", "classify_id_first", "classify_name_first", "classify_id_second", "classify_name_second", "add_type",
 		"title", "abstract", "author", "frequency", "stage", "video_url", "video_name", "video_play_seconds", "video_size", "detail_img_url", "detail_pdf_url",
 		"admin_id", "admin_real_name", "state", "publish_time", "pre_publish_time", "pre_msg_send", "msg_is_send", "msg_send_time", "create_time", "modify_time",
-		"last_modify_admin_id", "last_modify_admin_name", "content_modify_time", "pv", "uv",
+		"last_modify_admin_id", "last_modify_admin_name", "content_modify_time", "pv", "uv", "head_img", "end_img", "canvas_color",
 	}
 	list, e := reportOB.GetPageItemsByCondition(condition, pars, fields, "", startSize, params.PageSize)
 	if e != nil {

+ 307 - 0
controllers/smart_report/smart_resource.go

@@ -0,0 +1,307 @@
+package smart_report
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/smart_report"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// SmartReportResourceController 智能研报资源库
+type SmartReportResourceController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 资源库列表
+// @Description 资源库列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Param   Type				query	int		false	"资源类型: 1-版头; 2-版尾"
+// @Param   Keyword				query	string	false	"搜索关键词"
+// @Success 200 {object} smart_report.SmartReportListResp
+// @router /resource/list [get]
+func (this *SmartReportResourceController) List() {
+	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
+	}
+	type SmartReportResourceListReq struct {
+		PageSize     int    `form:"PageSize"`
+		CurrentIndex int    `form:"CurrentIndex"`
+		Type         int    `form:"Type"`
+		Keyword      string `form:"Keyword"`
+	}
+	params := new(SmartReportResourceListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+
+	var condition string
+	var pars []interface{}
+	// 筛选项
+	{
+		keyword := strings.TrimSpace(params.Keyword)
+		if keyword != "" {
+			kw := fmt.Sprint("%", keyword, "%")
+			condition += fmt.Sprintf(` AND img_name LIKE ?`)
+			pars = append(pars, kw)
+		}
+
+		if params.Type > 0 {
+			condition += ` AND type = ?`
+			pars = append(pars, params.Type)
+		}
+	}
+
+	resp := new(smart_report.SmartReportResourceListResp)
+	reportOB := new(smart_report.SmartReportResource)
+	total, e := reportOB.GetCountByCondition(condition, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取报告总数失败, Err:" + e.Error()
+		return
+	}
+	if total <= 0 {
+		page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+		resp.Paging = page
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+
+	// 分页列表
+	var startSize int
+	if params.PageSize <= 0 {
+		params.PageSize = utils.PageSize20
+	}
+	if params.CurrentIndex <= 0 {
+		params.CurrentIndex = 1
+	}
+	startSize = utils.StartIndex(params.CurrentIndex, params.PageSize)
+
+	fields := []string{
+		"resource_id",  "create_time", "img_name", "img_url", "type",
+	}
+	list, e := reportOB.GetPageItemsByCondition(condition, pars, fields, startSize, params.PageSize)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取资源库分页列表失败, Err:" + e.Error()
+		return
+	}
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Rename
+// @Title 重命名
+// @Description 重命名
+// @Param	request	body smart_report.SmartReportPublishReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /resource/rename [post]
+func (this *SmartReportResourceController) Rename() {
+	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
+	}
+	var req smart_report.SmartReportRenameReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ResourceId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = "报告ID为空"
+		return
+	}
+
+	ob := new(smart_report.SmartReportResource)
+	item, e := ob.GetItemById(req.ResourceId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "资源不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取资源图片失败, Err: " + e.Error()
+		return
+	}
+
+	cols := []string{"ImgName"}
+	item.ImgName = req.ImgName
+
+	if e = item.Update(cols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新资源失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Remove
+// @Title 删除
+// @Description 删除
+// @Param	request	body smart_report.SmartReportRemoveReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /resource/remove [post]
+func (this *SmartReportResourceController) Remove() {
+	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
+	}
+	var req smart_report.SmartReportResourceRemoveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ResourceIds == "" {
+		br.Msg = "参数有误"
+		br.ErrMsg = "图片ID为空"
+		return
+	}
+
+	ids := strings.Split(req.ResourceIds, ",")
+	for _, idStr := range ids {
+		ob := new(smart_report.SmartReportResource)
+		id,err := strconv.Atoi(idStr)
+		if err != nil {
+			br.Msg = "参数解析异常!"
+			br.ErrMsg = "参数解析失败,Err:" + err.Error()
+			return
+		}
+		item, e := ob.GetItemById(id)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Ret = 200
+				br.Success = true
+				br.Msg = "操作成功"
+				return
+			}
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取资源失败, Err: " + e.Error()
+			return
+		}
+		if e = item.Del(); e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "删除资源失败, Err: " + e.Error()
+			return
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Add
+// @Title 新增
+// @Description 新增
+// @Param	request	body smart_report.SmartReportAddReq true "type json string"
+// @Success 200 {object} smart_report.SmartReportItem
+// @router /resource/add [post]
+func (this *SmartReportResourceController) Add() {
+	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
+	}
+	var req smart_report.SmartReportResourceAddReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.Type != 1 && req.Type != 2 {
+		br.Msg = "请选择新增方式"
+		return
+	}
+
+	req.ImgName = strings.TrimSpace(req.ImgName)
+	if req.ImgName == "" {
+		br.Msg = "请输入图片名称"
+		return
+	}
+
+	item := new(smart_report.SmartReportResource)
+	item.Type = req.Type
+	item.ImgName = req.ImgName
+	item.ImgUrl = req.ImgUrl
+	item.CreateTime = time.Now().Local()
+
+	if e := item.Create(); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "新增资源失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 146 - 0
models/data_manage/base_from_yongyi.go

@@ -0,0 +1,146 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type BaseFromYongyiIndex struct {
+	YongyiIndexId int `orm:"column(yongyi_index_id);pk"`
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	Sort          int
+	CreateTime    time.Time
+	ModifyTime    time.Time
+}
+
+type BaseFromYongyiIndexList struct {
+	YongyiIndexId int `orm:"column(yongyi_index_id);pk"`
+	ClassifyId    int
+	Interface     string
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	Sort          int
+	CreateTime    string
+	ModifyTime    string
+	DataList      []*BaseFromYongyiData
+	Paging        *paging.PagingItem `description:"分页数据"`
+}
+
+type YongyiSingleDataResp struct {
+	YongyiIndexId int
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+	Frequency     string
+	Unit          string
+	StartTime     string
+	CreateTime    string
+	ModifyTime    string
+	Data          []*YongyiSingleData
+}
+
+type YongyiSingleData struct {
+	Value    string `orm:"column(value)" description:"日期"`
+	DataTime string `orm:"column(data_time)" description:"值"`
+}
+
+func GetYongyiIndex(condition string, pars interface{}) (items []*BaseFromYongyiIndexList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_yongyi_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC, yongyi_index_id asc`
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func GetYongyiIndexDataCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count  FROM base_from_yongyi_data WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+func GetYongyiIndexData(indexCode string, startSize, pageSize int) (items []*BaseFromYongyiData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_yongyi_data WHERE index_code=? ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetYongyiIndexDataByCodes(indexCode []string) (items []*BaseFromYongyiData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_yongyi_data WHERE index_code in (` + utils.GetOrmInReplace(len(indexCode)) + `) ORDER BY data_time DESC  `
+	_, err = o.Raw(sql, indexCode).QueryRows(&items)
+	return
+}
+
+type BaseFromYongyiData struct {
+	YongyiDataId  int `orm:"column(yongyi_data_id);pk"`
+	YongyiIndexId int
+	IndexCode     string
+	DataTime      string
+	Value         string
+	CreateTime    string
+	ModifyTime    string
+	DataTimestamp int64
+}
+
+type BaseFromYongyiIndexSearchItem struct {
+	YongyiIndexId int `orm:"column(yongyi_index_id);pk"`
+	ClassifyId    int
+	IndexCode     string
+	IndexName     string
+}
+
+// GetYongyiItemList 模糊查询Yongyi数据库指标列表
+func GetYongyiItemList(condition string) (items []*BaseFromYongyiIndexSearchItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM base_from_yongyi_index  WHERE 1=1"
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+func GetYongyiIndexDataByCode(indexCode string) (list []*BaseFromYongyiData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_yongyi_data WHERE index_code=? `
+	_, err = o.Raw(sql, indexCode).QueryRows(&list)
+	return
+}
+
+func GetBaseFromYongyiIndexByIndexCode(indexCode string) (list *BaseFromYongyiIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_yongyi_index WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&list)
+	return
+}
+
+type BaseFromYongyiIndexType struct {
+	Type2 string `orm:"column(type_2)"`
+	Type3 string `orm:"column(type_3)"`
+}
+
+// Update 更新Yongyi指标基础信息
+func (item *BaseFromYongyiIndex) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// EditYongyiIndexInfoResp 新增指标的返回
+type EditYongyiIndexInfoResp struct {
+	YongyiIndexId int    `description:"指标ID"`
+	IndexCode     string `description:"指标code"`
+}

+ 223 - 0
models/data_manage/base_from_yongyi_classify.go

@@ -0,0 +1,223 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// BaseFromYongyiClassify Yongyi原始数据分类表
+type BaseFromYongyiClassify struct {
+	ClassifyId      int       `orm:"column(classify_id);pk"`
+	ClassifyName    string    `description:"分类名称"`
+	ParentId        int       `description:"父级id"`
+	SysUserId       int       `description:"创建人id"`
+	SysUserRealName string    `description:"创建人姓名"`
+	Level           int       `description:"层级"`
+	Sort            int       `description:"排序字段,越小越靠前,默认值:10"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+}
+
+// AddBaseFromYongyiClassify 添加Yongyi原始数据分类
+func AddBaseFromYongyiClassify(item *BaseFromYongyiClassify) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	lastId, err = o.Insert(item)
+	return
+}
+
+// GetBaseFromYongyiClassifyCount 获取分类名称的个数
+func GetBaseFromYongyiClassifyCount(classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(1) AS count FROM base_from_yongyi_classify WHERE classify_name=? AND parent_id=? `
+	err = o.Raw(sql, classifyName, parentId).QueryRow(&count)
+	return
+}
+
+// GetBaseFromYongyiClassifyById 通过分类id的获取分类信息
+func GetBaseFromYongyiClassifyById(classifyId int) (item *BaseFromYongyiClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM base_from_yongyi_classify WHERE classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}
+
+// EditBaseFromYongyiClassify 修改Yongyi原始数据分类
+func EditBaseFromYongyiClassify(classifyId int, classifyName string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE base_from_yongyi_classify SET classify_name=?,modify_time=NOW() WHERE classify_id=? `
+	_, err = o.Raw(sql, classifyName, classifyId).Exec()
+	return
+}
+
+// UpdateBaseFromYongyiClassifySort 修改Yongyi原始数据分类的排序
+func UpdateBaseFromYongyiClassifySort(classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE base_from_yongyi_classify SET sort=classify_id, modify_time=NOW() WHERE classify_id=? `
+	_, err = o.Raw(sql, classifyId).Exec()
+	return
+}
+
+type BaseFromYongyiClassifyItems struct {
+	ClassifyId      int    `description:"分类ID"`
+	YongyiIndexId   int    `description:"指标类型ID"`
+	YongyiIndexCode string `description:"指标唯一编码"`
+	ClassifyName    string `description:"分类名称"`
+	ParentId        int    `description:"父级id"`
+	Level           int    `description:"层级"`
+	Sort            int    `description:"排序字段,越小越靠前,默认值:10"`
+}
+
+type BaseFromYongyiClassifyNameItems struct {
+	ClassifyId   int    `description:"分类ID"`
+	ClassifyName string `description:"分类名称"`
+	ParentId     int    `description:"父级id"`
+}
+
+type BaseFromYongyiClassifyResp struct {
+	List []*BaseFromYongyiClassifyItems
+}
+
+type BaseFromYongyiClassifyNameResp struct {
+	List []*BaseFromYongyiClassifyNameItems
+}
+
+type BaseFromYongyiClassifyItemsButton struct {
+	AddButton    bool `description:"是否可添加"`
+	OpButton     bool `description:"是否可编辑"`
+	DeleteButton bool `description:"是否可删除"`
+	MoveButton   bool `description:"是否可移动"`
+}
+
+// GetBaseFromYongyiClassifyByParentId 根据上级id获取当下的分类列表数据
+func GetBaseFromYongyiClassifyByParentId(parentId int) (items []*BaseFromYongyiClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_yongyi_classify WHERE parent_id=? order by sort asc,classify_id asc`
+	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	return
+}
+
+// GetAllBaseFromYongyiClassify 获取所有的分类列表数据
+func GetAllBaseFromYongyiClassify() (items []*BaseFromYongyiClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_yongyi_classify order by sort asc,classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+type DeleteBaseFromYongyiClassifyReq struct {
+	ClassifyId int `description:"分类id"`
+	EdbInfoId  int `description:"指标id"`
+}
+
+type BaseFromYongyiClassifyListResp struct {
+	AllNodes      []*BaseFromYongyiClassifyItems
+	CanOpClassify bool `description:"是否允许操作分类"`
+}
+
+type BaseFromYongyiClassifySimplify struct {
+	ClassifyId   int    `description:"分类id"`
+	ClassifyName string `description:"分类名称"`
+	ParentId     int
+}
+
+// GetFirstBaseFromYongyiClassify 获取当前分类下,且排序数相同 的排序第一条的数据
+func GetFirstBaseFromYongyiClassify() (item *BaseFromYongyiClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_yongyi_classify order by sort asc,classify_id asc limit 1`
+	err = o.Raw(sql).QueryRow(&item)
+	return
+}
+
+// UpdateBaseFromYongyiClassifySortByClassifyId 根据分类id更新排序
+func UpdateBaseFromYongyiClassifySortByClassifyId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` update base_from_yongyi_classify set sort = ` + updateSort + ` WHERE parent_id=? AND sort > ? `
+	if classifyId > 0 {
+		sql += ` or ( classify_id > ` + fmt.Sprint(classifyId) + ` and sort = ` + fmt.Sprint(nowSort) + `)`
+	}
+	_, err = o.Raw(sql, parentId, nowSort).Exec()
+	return
+}
+
+// MoveUpYongyiIndexClassifyBySort 往上移动
+func MoveUpYongyiIndexClassifyBySort(parentId, nextSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_yongyi_classify set sort = sort + 1 where parent_id=? and sort >= ? and sort< ?`
+	_, err = o.Raw(sql, parentId, nextSort, currentSort).Exec()
+	return
+}
+
+// MoveDownYongyiIndexClassifyBySort 往下移动
+func MoveDownYongyiIndexClassifyBySort(parentId, prevSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_yongyi_classify set sort = sort - 1 where parent_id=? and sort <= ? and sort> ? `
+	_, err = o.Raw(sql, parentId, prevSort, currentSort).Exec()
+	return
+}
+
+// GetYongyiIndexClassifyMinSort 获取最小不等于0的排序
+func GetYongyiIndexClassifyMinSort(parentId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `select min(sort) from base_from_yongyi_classify where parent_id=? and sort <> 0 `
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+// Update 更新分类基础信息
+func (BaseFromYongyiClassify *BaseFromYongyiClassify) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(BaseFromYongyiClassify, cols...)
+	return
+}
+
+type AddYongyiClassifyResp struct {
+	ClassifyId int
+}
+
+// DeleteYongyiClassifyByClassifyId 根据分类id删除对应的指标分类
+func DeleteYongyiClassifyByClassifyId(classifyIdList []int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	num := len(classifyIdList)
+	if num <= 0 {
+		return
+	}
+	//删除分类
+	sql := `DELETE FROM base_from_yongyi_classify WHERE classify_id IN (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, classifyIdList).Exec()
+	return
+}
+
+// AddYongyiClassifyMulti 批量新增SMM类别
+func AddYongyiClassifyMulti(list []*BaseFromYongyiClassify) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(1, list)
+	return
+}
+
+// InitYongyiClassifySort 初始化sort值
+func InitYongyiClassifySort() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE base_from_yongyi_classify 
+SET modify_time=NOW(), sort = classify_id`
+	_, err = o.Raw(sql).Exec()
+	return
+}
+
+// InitYongyiIndexClassifyId 历史数据的classifyId值
+func InitYongyiIndexClassifyId() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE base_from_yongyiindex s
+LEFT JOIN (
+SELECT
+	c1.classify_id,
+	CONCAT( c2.classify_name, c1.classify_name ) AS type_name 
+FROM
+	base_from_yongyi_classify c1
+	LEFT JOIN base_from_yongyi_classify c2 ON c1.parent_id = c2.classify_id 
+	) AS t ON CONCAT( s.type_2, s.type_3 ) = t.type_name
+	SET s.classify_id = t.classify_id, s.modify_time=NOW() where s.type_2 <>""`
+	_, err = o.Raw(sql).Exec()
+	return
+}

+ 16 - 13
models/data_manage/chart_framework.go

@@ -258,6 +258,7 @@ type ChartFrameworkAddReq struct {
 // ChartFrameworkNodeReq 图库框架节点请求体
 type ChartFrameworkNodeReq struct {
 	MyChartClassifyId int    `description:"我的图表分类ID"`
+	NodeId            string `description:"节点ID"`
 	NodeName          string `description:"节点名称"`
 }
 
@@ -312,22 +313,23 @@ func GetFirstChartFramework(adminId int) (item *ChartFramework, err error) {
 
 // ChartFrameworkItem 图库框架表信息
 type ChartFrameworkItem struct {
-	ChartFrameworkId int    `description:"框架ID"`
-	FrameworkCode    string `description:"框架唯一编码"`
-	FrameworkName    string `description:"框架名称"`
-	FrameworkImg     string `description:"框架图片"`
-	FrameworkContent string `description:"框架内容"`
-	IsPublic         int    `description:"是否公开:0-私有;1-公开"`
-	PublicTime       string `description:"公开时间"`
-	Sort             int    `description:"排序"`
-	AdminId          int    `description:"创建人ID"`
-	AdminName        string `description:"创建人姓名"`
-	CreateTime       string `description:"创建时间"`
-	ModifyTime       string `description:"更新时间"`
+	ChartFrameworkId int                       `description:"框架ID"`
+	FrameworkCode    string                    `description:"框架唯一编码"`
+	FrameworkName    string                    `description:"框架名称"`
+	FrameworkImg     string                    `description:"框架图片"`
+	FrameworkContent string                    `description:"框架内容"`
+	IsPublic         int                       `description:"是否公开:0-私有;1-公开"`
+	PublicTime       string                    `description:"公开时间"`
+	Sort             int                       `description:"排序"`
+	AdminId          int                       `description:"创建人ID"`
+	AdminName        string                    `description:"创建人姓名"`
+	CreateTime       string                    `description:"创建时间"`
+	ModifyTime       string                    `description:"更新时间"`
+	Nodes            []*ChartFrameworkNodeItem `description:"框架节点"`
 }
 
 // FormatChartFramework2Item 格式化框架信息
-func FormatChartFramework2Item(origin *ChartFramework) (item *ChartFrameworkItem) {
+func FormatChartFramework2Item(origin *ChartFramework, nodes []*ChartFrameworkNodeItem) (item *ChartFrameworkItem) {
 	if origin == nil {
 		return
 	}
@@ -344,6 +346,7 @@ func FormatChartFramework2Item(origin *ChartFramework) (item *ChartFrameworkItem
 	item.AdminName = origin.AdminName
 	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
 	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	item.Nodes = nodes
 	return
 }
 

+ 6 - 1
models/data_manage/chart_framework_node.go

@@ -13,6 +13,7 @@ type ChartFrameworkNode struct {
 	ChartFrameworkNodeId int       `orm:"column(chart_framework_node_id);pk"`
 	ChartFrameworkId     int       `description:"框架ID"`
 	FrameworkName        string    `description:"框架名称"`
+	NodeId               string    `description:"节点ID"`
 	NodeName             string    `description:"节点名称"`
 	MyChartClassifyId    int       `description:"我的图表分类ID"`
 	CreateTime           time.Time `description:"创建时间"`
@@ -114,13 +115,15 @@ type ChartFrameworkNodeItem struct {
 	ChartFrameworkNodeId int
 	ChartFrameworkId     int    `description:"框架ID"`
 	FrameworkName        string `description:"框架名称"`
+	NodeId               string `description:"节点ID"`
 	NodeName             string `description:"节点名称"`
 	MyChartClassifyId    int    `description:"我的图表分类ID"`
+	ChartNum             int    `description:"分类下的图表数"`
 	CreateTime           string `description:"创建时间"`
 }
 
 // FormatChartFrameworkNode2Item 格式化框架节点信息
-func FormatChartFrameworkNode2Item(origin *ChartFrameworkNode) (item *ChartFrameworkNodeItem) {
+func FormatChartFrameworkNode2Item(origin *ChartFrameworkNode, chartNum int) (item *ChartFrameworkNodeItem) {
 	if origin == nil {
 		return
 	}
@@ -128,8 +131,10 @@ func FormatChartFrameworkNode2Item(origin *ChartFrameworkNode) (item *ChartFrame
 	item.ChartFrameworkNodeId = origin.ChartFrameworkNodeId
 	item.ChartFrameworkId = origin.ChartFrameworkId
 	item.FrameworkName = origin.FrameworkName
+	item.NodeId = origin.NodeId
 	item.NodeName = origin.NodeName
 	item.MyChartClassifyId = origin.MyChartClassifyId
+	item.ChartNum = chartNum
 	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
 	return
 }

+ 24 - 0
models/data_manage/edb_data_base.go

@@ -227,6 +227,23 @@ func GetEdbDataAllByEdbCode(edbCode string, source, subSource, limit int) (items
 	return
 }
 
+func GetBaseIndexInfoByEdbCode(edbCode string, source int) (item *BaseIndexInfo, err error) {
+	var pars []interface{}
+	pars = append(pars, edbCode)
+	o := orm.NewOrmUsingDB("data")
+
+	tableName := GetBaseIndexTableName(source)
+	if tableName == "" {
+		err = fmt.Errorf("未找到对应的表")
+		return
+	}
+	sql := ` SELECT * FROM %s WHERE index_code=? `
+
+	sql = fmt.Sprintf(sql, tableName)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
 func GetEdbDataBaseByCodeAndDate(source, subSource int, edbCode string, startDate string) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	tableName := GetEdbDataTableName(source, subSource)
@@ -236,6 +253,13 @@ func GetEdbDataBaseByCodeAndDate(source, subSource int, edbCode string, startDat
 	return
 }
 
+func GetBaseIndexTableName(source int) (tableName string) {
+	edbSource := EdbSourceIdMap[source]
+	if edbSource != nil {
+		tableName = edbSource.IndexTableName
+	}
+	return
+}
 func GetEdbDataAllByEdbCodeAndSubSource(edbCode string, source, subSource, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCode)

+ 10 - 0
models/data_manage/edb_info.go

@@ -47,6 +47,8 @@ type EdbInfo struct {
 	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
 	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
 	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
+	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	TerminalCode     string  `description:"终端编码,用于配置在机器上"`
 	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
 	ErDataUpdateDate string  `description:"本次更新,数据发生变化的最早日期"`
@@ -122,6 +124,12 @@ type EdbInfoSearchData struct {
 	Value    float64 `description:"数据"`
 }
 
+type BaseIndexInfo struct {
+	IndexName string `description:"数据日期"`
+	Unit      string `description:"单位"`
+	Frequency string `description:"频率"`
+}
+
 type EdbInfoSearchResp struct {
 	SearchItem      *EdbInfoSearch `description:"指标分类"`
 	Status          int            `description:"1:数据已存在于弘则数据库,2:新数据,3:数据已存在于弘则数据库,但是当前账号无权限"`
@@ -313,6 +321,8 @@ type EdbInfoList struct {
 	IsEnEdb          bool                    `description:"是否展示英文标识"`
 	DataInsertConfig EdbDataInsertConfigItem `description:"指标数据插入配置"`
 	DataDateType     string                  `description:"数据日期类型,枚举值:交易日、自然日"`
+	EmptyType        int                     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	SubSource        int                     `description:"子数据来源:0:经济数据库,1:日期序列"`
 	SubSourceName    string                  `description:"子数据来源名称"`
 	IndicatorCode    string                  `description:"指标代码"`

+ 6 - 0
models/data_manage/edb_info_calculate.go

@@ -18,6 +18,8 @@ type EdbInfoCalculateSaveReq struct {
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
 	Calendar         string           `description:"公历/农历"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -107,6 +109,8 @@ type EdbInfoCalculateEditReq struct {
 	Unit             string           `description:"单位"`
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -200,6 +204,8 @@ type EdbInfoCalculateBatchSaveReqByEdbLib struct {
 	MoveFrequency    string           `description:"移动频度:天/周/月/季/年"`
 	Calendar         string           `description:"公历/农历"`
 	Data             interface{}      `description:"数据列"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 }
 
 // EdbInfoCalculateBatchEditReqByEdbLib 编辑计算指标的请求参数

+ 1 - 0
models/data_manage/edb_source.go

@@ -23,6 +23,7 @@ type EdbSource struct {
 	BridgeFlag       string `description:"桥接服务对象标识"`
 	SourceExtend     string `description:"扩展字段做查询用"`
 	EdbCodeRequired  int    `description:"指标编码是否必填: 0-否; 1-是"`
+	IndexTableName   string `description:"数据源指标表名"`
 }
 
 // GetEdbSourceItemsByCondition 获取指标来源列表

+ 59 - 2
models/data_manage/my_chart.go

@@ -71,13 +71,13 @@ func GetPublicChartClassifyAllExceptMy(adminId int) (item []*MyChartClassify, er
 }
 
 type MyChartClassifyResp struct {
-	List     []*MyChartClassify
+	List     []*MyChartClassifyItem
 	Language string `description:"指标的展示语言,CN:中文,EN:英文"`
 }
 
 // PublicChartClassifyResp 公共分类返回数据结构体
 type PublicChartClassifyResp struct {
-	List     []PublicChartClassifyItem
+	List     []PublicChartClassifyList
 	Language string `description:"指标的展示语言,CN:中文,EN:英文"`
 }
 
@@ -91,6 +91,13 @@ type PublicChartClassifyItem struct {
 	IsCompanyPublic     int    `description:"是否为客户可见"`
 }
 
+// PublicChartClassifyList 公共分类结构体
+type PublicChartClassifyList struct {
+	MenuAdminId int                       `description:"目录创建人ID"`
+	MenuName    string                    `description:"目录名称"`
+	Items       []PublicChartClassifyItem `description:"分类数据"`
+}
+
 type MyChartClassifyAddReq struct {
 	MyChartClassifyName string `description:"分类名称"`
 }
@@ -901,3 +908,53 @@ func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err
 	err = o.Raw(sql, classifyId).QueryRow(&item)
 	return
 }
+
+// MyChartClassifyItem 我的图表分类信息
+type MyChartClassifyItem struct {
+	MyChartClassifyId   int    `description:"分类ID"`
+	MyChartClassifyName string `description:"分类名称"`
+	AdminId             int    `description:"创建人id"`
+	IsPublic            int    `description:"是否公共分类"`
+	IsCompanyPublic     int    `description:"是否为用户公共分类"`
+	ChartNum            int    `description:"分类下的图表数量"`
+}
+
+// FormatMyChartClassify2Item 格式化我的图表信息
+func FormatMyChartClassify2Item(origin *MyChartClassify, chartNum int) (item *MyChartClassifyItem) {
+	if origin == nil {
+		return
+	}
+	item = new(MyChartClassifyItem)
+	item.MyChartClassifyId = origin.MyChartClassifyId
+	item.MyChartClassifyName = origin.MyChartClassifyName
+	item.AdminId = origin.AdminId
+	item.IsPublic = origin.IsPublic
+	item.IsCompanyPublic = origin.IsCompanyPublic
+	item.ChartNum = chartNum
+	return
+}
+
+// MyChartClassifyIdAndNum 我的图表-分类ID及图表数
+type MyChartClassifyIdAndNum struct {
+	MyChartClassifyId int `description:"分类ID"`
+	ChartNum          int `description:"分类下的图表数量"`
+}
+
+// GetMyChartClassifyIdAndNum 我的图表-获取分类ID及图表数
+func GetMyChartClassifyIdAndNum(cond string, pars []interface{}) (items []*MyChartClassifyIdAndNum, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT
+			a.my_chart_classify_id,
+			COUNT(1) AS chart_num
+		FROM
+			my_chart_classify AS a
+		INNER JOIN my_chart_classify_mapping AS b ON a.my_chart_classify_id = b.my_chart_classify_id
+		INNER JOIN my_chart AS c ON b.my_chart_id = c.my_chart_id
+		INNER JOIN chart_info AS d ON c.chart_info_id = d.chart_info_id
+		WHERE
+			1 = 1 %s
+		GROUP BY
+			a.my_chart_classify_id`, cond)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}

+ 4 - 0
models/data_manage/predict_edb_conf.go

@@ -14,6 +14,8 @@ type PredictEdbConf struct {
 	RuleType         int       `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	FixedValue       float64   `description:"固定值"`
 	Value            string    `description:"配置的值"`
+	EmptyType        int       `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int       `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate          time.Time `description:"截止日期"`
 	ModifyTime       time.Time `description:"修改时间"`
 	CreateTime       time.Time `description:"添加时间"`
@@ -27,6 +29,8 @@ type PredictEdbConfDetail struct {
 	RuleType         int                                     `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	FixedValue       float64                                 `description:"固定值"`
 	Value            string                                  `description:"配置的值"`
+	EmptyType        int                                     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                                     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate          time.Time                               `description:"截止日期"`
 	ModifyTime       time.Time                               `description:"修改时间"`
 	CreateTime       time.Time                               `description:"添加时间"`

+ 2 - 0
models/data_manage/predict_edb_info_calculate.go

@@ -10,6 +10,8 @@ type PredictEdbInfoCalculateSaveReq struct {
 	Unit             string           `description:"单位"`
 	ClassifyId       int              `description:"分类id"`
 	CalculateFormula string           `description:"计算公式"`
+	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 

+ 2 - 0
models/data_manage/request/predict_edb_info.go

@@ -42,6 +42,8 @@ type AddPredictEdbInfoReq struct {
 type RuleConfig struct {
 	RuleType     int                          `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值,9:动态环差"`
 	Value        string                       `description:"值"`
+	EmptyType    int                          `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType int                          `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate      string                       `description:"截止日期"`
 	EdbInfoIdArr []data_manage.EdbInfoFromTag `description:"指标信息"`
 }

+ 1 - 1
models/data_manage/response/predit_edb_info.go

@@ -46,5 +46,5 @@ type PredictEdbInfoChartDataResp struct {
 // PredictRuleCalculateByNineResp 获取预测指标规则9的绘图数据返回
 type PredictRuleCalculateByNineResp struct {
 	LatestDate string
-	DataList   interface{}
+	DataList   []*data_manage.EdbDataList
 }

+ 1 - 0
models/db.go

@@ -485,6 +485,7 @@ func initSmartReport() {
 	orm.RegisterModel(
 		new(smart_report.SmartReport),        // 智能研报主表
 		new(smart_report.SmartReportSaveLog), // 智能研报-保存记录表
+		new(smart_report.SmartReportResource), // 智能研报-资源表
 	)
 }
 

+ 18 - 0
models/smart_report/smart_report.go

@@ -53,6 +53,9 @@ type SmartReport struct {
 	DetailPdfUrl        string    `description:"报告详情PDF地址"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"修改时间"`
+	HeadImg             string    `description:"报告头图地址"`
+	EndImg              string    `description:"报告尾图地址"`
+	CanvasColor         string    `description:"画布颜色"`
 }
 
 func (m *SmartReport) TableName() string {
@@ -206,6 +209,9 @@ type SmartReportItem struct {
 	ModifyTime          string  `description:"修改时间"`
 	CanEdit             bool    `description:"是否可编辑"`
 	Editor              string  `description:"当前编辑人"`
+	HeadImg             string  `description:"报告头图地址"`
+	EndImg              string  `description:"报告尾图地址"`
+	CanvasColor         string  `description:"画布颜色"`
 }
 
 // FormatSmartReport2Item 格式化智能研报数据格式
@@ -249,6 +255,9 @@ func FormatSmartReport2Item(origin *SmartReport) (item *SmartReportItem) {
 	item.DetailPdfUrl = origin.DetailPdfUrl
 	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
 	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	item.HeadImg = origin.HeadImg
+	item.EndImg = origin.EndImg
+	item.CanvasColor = origin.CanvasColor
 	return
 }
 
@@ -263,6 +272,9 @@ type SmartReportAddReq struct {
 	Abstract           string `description:"摘要"`
 	Author             string `description:"作者"`
 	Frequency          string `description:"频度"`
+	HeadImg            string `description:"报告头图地址"`
+	EndImg             string `description:"报告尾图地址"`
+	CanvasColor        string `description:"画布颜色"`
 }
 
 // SmartReportEditReq 编辑智能研报请求体
@@ -271,6 +283,9 @@ type SmartReportEditReq struct {
 	SmartReportId int    `description:"智能研报ID"`
 	Content       string `description:"内容"`
 	ContentStruct string `description:"内容结构"`
+	HeadImg       string `description:"报告头图地址"`
+	EndImg        string `description:"报告尾图地址"`
+	CanvasColor   string `description:"画布颜色"`
 }
 
 // SmartReportRemoveReq 删除智能研报请求体
@@ -297,6 +312,9 @@ type SmartReportSaveContentReq struct {
 	Content       string `description:"内容"`
 	ContentStruct string `description:"内容结构"`
 	NoChange      int    `description:"内容是否未改变:1:内容未改变"`
+	HeadImg       string `description:"报告头图地址"`
+	EndImg        string `description:"报告尾图地址"`
+	CanvasColor   string `description:"画布颜色"`
 }
 
 // SmartReportSaveContentResp 保存草稿响应体

+ 107 - 0
models/smart_report/smart_resource.go

@@ -0,0 +1,107 @@
+package smart_report
+
+import (
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strings"
+	"time"
+)
+
+type SmartReportResource struct {
+	ResourceId int       `orm:"column(resource_id);pk" description:"智能研报资源ID"`
+	ImgUrl     string    // 图片链接
+	ImgName    string    // 图片名称
+	Type       int       // 类型 1-版头 2-版尾
+	CreateTime time.Time // 创建时间
+}
+
+func (m *SmartReportResource) TableName() string {
+	return "smart_report_resource"
+}
+
+func (m *SmartReportResource) PrimaryId() string {
+	return "resource_id"
+}
+
+func (m *SmartReportResource) Create() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.ResourceId = int(id)
+	return
+}
+
+func (m *SmartReportResource) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *SmartReportResource) Del() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.ResourceId).Exec()
+	return
+}
+
+type SmartReportResourceItem struct {
+	ResourceId int    `orm:"column(resource_id);pk" description:"智能研报资源ID"`
+	ImgUrl     string // 图片链接
+	ImgName    string // 图片名称
+	Type       int    // 类型 1-版头 2-版尾
+	CreateTime string // 创建时间
+}
+
+// SmartReportResourceListResp 智能研报资源库
+type SmartReportResourceListResp struct {
+	List   []*SmartReportResourceItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+func (m *SmartReportResource) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *SmartReportResource) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, startSize, pageSize int) (items []*SmartReportResourceItem, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := ` ORDER BY create_time DESC`
+
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// SmartReportRenameReq 智能研报资源重命名请求体
+type SmartReportRenameReq struct {
+	ResourceId int    `description:"资源ID"`
+	ImgName    string `description:"图片名称"`
+}
+
+func (m *SmartReportResource) GetItemById(id int) (item *SmartReportResource, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// SmartReportResourceRemoveReq 删除智能研报资源请求体
+type SmartReportResourceRemoveReq struct {
+	ResourceIds string `description:"资源IDs"`
+}
+
+// SmartReportResourceAddReq 新增智能研报资源请求体
+type SmartReportResourceAddReq struct {
+	Type    int    `description:"类型 1-版头 2-版尾"`
+	ImgUrl  string `description:"图片链接"`
+	ImgName string `description:"图片名称"`
+}

+ 81 - 0
routers/commentsRouter.go

@@ -3463,6 +3463,51 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "YongyiClassify",
+            Router: `/yongyi/classify`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "ExportYongyiList",
+            Router: `/yongyi/export`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "YongyiIndexData",
+            Router: `/yongyi/index/data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "YongyiSearchList",
+            Router: `/yongyi/search_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "YongyiSingleData",
+            Router: `/yongyi/single_data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:JiaYueEdbSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:JiaYueEdbSourceController"],
         beego.ControllerComments{
             Method: "FrequencyList",
@@ -5344,6 +5389,42 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/resource/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/resource/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"],
+        beego.ControllerComments{
+            Method: "Remove",
+            Router: `/resource/remove`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/smart_report:SmartReportResourceController"],
+        beego.ControllerComments{
+            Method: "Rename",
+            Router: `/resource/rename`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/trade_analysis:TradeAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/trade_analysis:TradeAnalysisController"],
         beego.ControllerComments{
             Method: "GetClassifyName",

+ 1 - 0
routers/router.go

@@ -312,6 +312,7 @@ func init() {
 		web.NSNamespace("/smart_report",
 			web.NSInclude(
 				&smart_report.SmartReportController{},
+				&smart_report.SmartReportResourceController{},
 			),
 		),
 		web.NSNamespace("/ai",

+ 22 - 0
services/data/base_edb_lib.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/response"
 	"eta/eta_api/utils"
 	"fmt"
 	"io/ioutil"
@@ -131,6 +132,27 @@ func SaveBasePredictEdbData(edbInfoCalculateBatchSaveReqStr string) (resp *AddPr
 	return
 }
 
+type PredictRuleCalculateByNineRespResponse struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        response.PredictRuleCalculateByNineResp
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
+// PredictCalculateByNinePreview 预测指标动态环差演算
+func PredictCalculateByNinePreview(RuleConfigReqStr string) (resp *PredictRuleCalculateByNineRespResponse, err error) {
+	_, resultByte, err := postAddEdbData(RuleConfigReqStr, "predict/calculate_by_nine/preview")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
 // SavePredictEdbData 新增/编辑预测指标运算
 func SavePredictEdbData(edbInfoCalculateBatchSaveReqStr string) (resp *AddPredictEdbDataResponse, err error) {
 	_, resultByte, err := postAddEdbData(edbInfoCalculateBatchSaveReqStr, "predict_calculate/save")

+ 153 - 102
services/data/edb_info_calculate.go

@@ -9,13 +9,14 @@ import (
 	"github.com/shopspring/decimal"
 	"github.com/yidane/formula"
 	"math"
+	"regexp"
 	"strconv"
 	"strings"
 	"time"
 )
 
 func CheckFormula(formula string) map[string]string {
-	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN"}
+	mathFormula := []string{"MAX", "MIN", "ABS", "ACOS", "ASIN", "CEIL", "MOD", "POW", "ROUND", "SIGN", "SIN", "TAN", "LOG10", "LOG2", "LOG", "LN", "EXP"}
 
 	str := strings.ToUpper(formula)
 	for _, v := range mathFormula {
@@ -37,22 +38,23 @@ func CheckFormula(formula string) map[string]string {
 	return byteMap
 }
 
-// CheckFormula2 校验公式是否正常(比如说除法的分母不能为0之类的,实际上就是用预设的字段数据做一次计算)
-func CheckFormula2(edbInfoArr []*data_manage.EdbInfo, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) (ok bool, err error) {
-	valArr := make(map[int]float64)
-	for _, v := range edbInfoArr {
-		valArr[v.EdbInfoId] = 100
-	}
-	formulaStr = strings.ToUpper(formulaStr)
-	formulaFormStr := ReplaceFormula(edbInfoArr, valArr, formulaMap, formulaStr, edbInfoIdBytes)
-	if formulaFormStr == "" {
+type FormulaListItem struct {
+	Formula string `json:"f"`
+	Date    string `json:"d"`
+}
+
+// CheckFormulaJson 检测计算公式json串是否异常
+func CheckFormulaJson(formula string) (formulaSlice []string, err error) {
+	list := make([]FormulaListItem, 0)
+	err = json.Unmarshal([]byte(formula), &list)
+	if err != nil {
+		err = fmt.Errorf("公式串解析失败: json.Unmarshal Err: %v", err)
 		return
 	}
-	expression := formula.NewExpression(formulaFormStr)
-	_, err = expression.Evaluate()
-	if err != nil {
-	} else {
-		ok = true
+	formulaSlice = make([]string, 0)
+	// 日期排序
+	for _, v := range list {
+		formulaSlice = append(formulaSlice, v.Formula)
 	}
 	return
 }
@@ -62,91 +64,8 @@ type CalculateItems struct {
 	DataMap   map[string]float64
 }
 
-func Calculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCode, formulaStr string, edbInfoIdBytes []string) (err error) {
-	defer func() {
-		if err != nil {
-			utils.FileLog.Info("Calculate Err:%s" + err.Error())
-		}
-	}()
-	saveDataMap := make(map[string]map[int]float64)
-	for _, v := range edbInfoIdArr {
-		var condition string
-		var pars []interface{}
-		condition += " AND edb_info_id=? "
-		pars = append(pars, v.EdbInfoId)
-		dataList, err := data_manage.GetEdbDataListAll(condition, pars, v.Source, v.SubSource, 1)
-		if err != nil {
-			return err
-		}
-		dataMap := make(map[string]float64)
-		for _, dv := range dataList {
-			if val, ok := saveDataMap[dv.DataTime]; ok {
-				if _, ok := val[v.EdbInfoId]; !ok {
-					val[v.EdbInfoId] = dv.Value
-				}
-			} else {
-				temp := make(map[int]float64)
-				temp[v.EdbInfoId] = dv.Value
-				saveDataMap[dv.DataTime] = temp
-			}
-		}
-		item := new(CalculateItems)
-		item.EdbInfoId = v.EdbInfoId
-		item.DataMap = dataMap
-	}
-	formulaMap := CheckFormula(formulaStr)
-	addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	nowStr := time.Now().Format(utils.FormatDateTime)
-	var isAdd bool
-	for sk, sv := range saveDataMap {
-		formulaStr = strings.ToUpper(formulaStr)
-		formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
-		if formulaStr == "" {
-			return
-		}
-		if formulaFormStr != "" {
-			expression := formula.NewExpression(formulaFormStr)
-			calResult, err := expression.Evaluate()
-			if err != nil {
-				err = errors.New("计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
-				fmt.Println(err)
-				return err
-			}
-			calVal, err := calResult.Float64()
-			if err != nil {
-				err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
-				fmt.Println(err)
-				return err
-			}
-
-			//需要存入的数据
-			{
-				dataTime, _ := time.Parse(utils.FormatDate, sk)
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				addSql += "("
-				addSql += strconv.Itoa(edbInfoId) + "," + "'" + edbCode + "'" + "," + "'" + sk + "'" + "," + utils.SubFloatToString(calVal, 4) + "," + "'" + nowStr + "'" +
-					"," + "'" + nowStr + "'" + "," + "1"
-				addSql += "," + "'" + timeStr + "'"
-				addSql += "),"
-				isAdd = true
-			}
-		} else {
-			fmt.Println("formulaFormStr is empty")
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		data_manage.AddEdbDataCalculateBySql(addSql)
-		if err != nil {
-			fmt.Println("AddEdbDataCalculate Err:" + err.Error())
-			return err
-		}
-	}
-	return
-}
-
 func ReplaceFormula(edbInfoIdArr []*data_manage.EdbInfo, valArr map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) string {
+	// todo 处理min和max
 	funMap := GetFormulaMap()
 	for k, v := range funMap {
 		formulaStr = strings.Replace(formulaStr, k, v, -1)
@@ -548,7 +467,22 @@ func RefreshCalculate(edbInfoIdArr []*data_manage.EdbInfo, edbInfoId int, edbCod
 }
 
 // 处理整个数据
-func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo) {
+func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*data_manage.EdbInfo, emptyType int) {
+	var startDate, endDate string
+	var startDateT, endDateT time.Time
+	if emptyType == 2 || emptyType == 3 {
+		for k, _ := range realSaveDataMap {
+			if k > endDate {
+				endDate = k
+			}
+			if k < startDate || startDate == "" {
+				startDate = k
+			}
+		}
+
+		startDateT, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
+		endDateT, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+	}
 	for _, date := range dateList {
 		tmpDataMap := realSaveDataMap[date]
 		for _, edbInfo := range edbInfoIdArr {
@@ -569,8 +503,16 @@ func handleDateSaveDataMap(dateList []string, realSaveDataMap, saveDataMap map[s
 				//	day = 365
 				//}
 				// 需求池 255 指标运算文案修改,补数据遍历区间修改(2023-3-7 09:37:23修改)
-				day := 35
-				handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, day)
+				switch emptyType {
+				case 0:
+					handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, 35)
+				case 2:
+					handleDateDataMapBefore(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
+				case 3:
+					handleDateDataMapAfter(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
+				case 4:
+					handleDateDataMapZero(saveDataMap, date, tmpEdbInfoId)
+				}
 			}
 		}
 	}
@@ -711,3 +653,112 @@ func CallCalculateComputeCorrelation(data *data_manage.EdbInfoCalculateBatchSave
 
 	return
 }
+
+// handleDateDataMapBefore 前值填充:空值优先以最近的前值填充,没有前值时,用后值填充
+func handleDateDataMapBefore(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
+	currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
+
+	// 后一天
+	nextDateDay := currDate
+
+	// 前一天
+	preDateDay := currDate
+
+	for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
+		// 上个日期的数据
+		{
+			preDateDay = currDate.AddDate(0, 0, -i)
+			preDateDayStr := preDateDay.Format(utils.FormatDate)
+			if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
+				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
+					saveDataMap[date][edbInfoId] = val
+					return
+				}
+			}
+		}
+	}
+
+	for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
+		// 下个日期的数据
+		{
+			nextDateDay = currDate.AddDate(0, 0, i)
+			nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+			if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
+				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
+					saveDataMap[date][edbInfoId] = val
+					return
+				}
+			}
+		}
+	}
+	return
+}
+
+// handleDateDataMapAfter 后值填充:空值优先以最近的后值填充,没有后值时,用前值填充
+func handleDateDataMapAfter(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
+	currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
+
+	// 后一天
+	nextDateDay := currDate
+
+	// 前一天
+	preDateDay := currDate
+
+	for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
+		// 下个日期的数据
+		{
+			nextDateDay = currDate.AddDate(0, 0, i)
+			nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+			if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
+				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
+					saveDataMap[date][edbInfoId] = val
+					return
+				}
+			}
+		}
+	}
+
+	for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
+		// 上个日期的数据
+		{
+			preDateDay = currDate.AddDate(0, 0, -i)
+			preDateDayStr := preDateDay.Format(utils.FormatDate)
+			if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
+				if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
+					fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
+					saveDataMap[date][edbInfoId] = val
+					return
+				}
+			}
+		}
+	}
+	return
+}
+
+// handleDateDataMapZero 等于0
+func handleDateDataMapZero(saveDataMap map[string]map[int]float64, date string, edbInfoId int) {
+	saveDataMap[date][edbInfoId] = 0
+	return
+}
+
+func GetMaxMinEdbInfo(formula string) string {
+	//formula := "A+min(A,B,max(A,C))"
+	// todo 无法处理max里嵌套max或者min的情况
+	// 使用正则表达式匹配MAX和MIN函数及其参数
+	regex := regexp.MustCompile(`(?i)(MAX|MIN)\((.*?)\)`)
+	matches := regex.FindAllStringSubmatch(formula, -1)
+	// 遍历匹配结果,输出MAX和MIN函数及其参数
+	for _, match := range matches {
+		if len(match) == 3 {
+			parameter := strings.ToLower(match[0]) // 参数
+			formula = strings.ReplaceAll(formula, match[0], parameter)
+			fmt.Printf("formula: %s\n", formula)
+		}
+	}
+	formula = strings.ReplaceAll(formula, "max", "MAX")
+	formula = strings.ReplaceAll(formula, "min", "MIN")
+	return formula
+}

+ 43 - 0
services/data/my_chart.go

@@ -0,0 +1,43 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+)
+
+// GetMyChartClassifyIdNumMap 我的图表-获取分类ID及图表数map
+func GetMyChartClassifyIdNumMap(adminId int) (chartsNumMap map[int]int, err error) {
+	chartsNumMap = make(map[int]int)
+
+	// 获取当前账号的不可见指标
+	chartIds := make([]int, 0)
+	obj := data_manage.EdbInfoNoPermissionAdmin{}
+	charts, e := obj.GetAllChartListByAdminId(adminId)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("获取不可见指标配置数据失败, err: %s", e.Error())
+		return
+	}
+	for _, v := range charts {
+		chartIds = append(chartIds, v.ChartInfoId)
+	}
+
+	cond := ``
+	pars := make([]interface{}, 0)
+	lenChart := len(chartIds)
+	if lenChart > 0 {
+		cond += ` AND d.chart_info_id NOT IN (` + utils.GetOrmInReplace(lenChart) + `) `
+		pars = append(pars, chartIds)
+	}
+
+	// 分类图表数
+	chartsNum, e := data_manage.GetMyChartClassifyIdAndNum(cond, pars)
+	if e != nil {
+		err = fmt.Errorf("获取分类图表数失败, err: %s", e.Error())
+		return
+	}
+	for _, v := range chartsNum {
+		chartsNumMap[v.MyChartClassifyId] = v.ChartNum
+	}
+	return
+}

+ 0 - 154
services/data/predict_edb_info.go

@@ -9,7 +9,6 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/shopspring/decimal"
-	"github.com/yidane/formula"
 	"strconv"
 	"strings"
 	"time"
@@ -1127,159 +1126,6 @@ func GetPredictCalculateDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, s
 	return
 }
 
-// GetCalculateByRuleByNineParams 获取预测规则9的计算参数
-func GetCalculateByRuleByNineParams(req request.RuleConfig) (formula string, edbInfoList []*data_manage.EdbInfo, edbInfoIdBytes []string, err error, errMsg string) {
-	formula = req.Value
-	formula = strings.Replace(formula, "(", "(", -1)
-	formula = strings.Replace(formula, ")", ")", -1)
-	formula = strings.Replace(formula, ",", ",", -1)
-	formula = strings.Replace(formula, "。", ".", -1)
-	formula = strings.Replace(formula, "%", "*0.01", -1)
-
-	//检验公式
-	var checkFormulaStr string
-	for _, tmpEdbInfoId := range req.EdbInfoIdArr {
-		checkFormulaStr += tmpEdbInfoId.FromTag + ","
-		edbInfoIdBytes = append(edbInfoIdBytes, tmpEdbInfoId.FromTag)
-	}
-	formulaMap := CheckFormula(formula)
-	for _, tmpFormula := range formulaMap {
-		if !strings.Contains(checkFormulaStr, tmpFormula) {
-			errMsg = "公式错误,请重新填写"
-			return
-		}
-	}
-
-	//关联的指标信息
-	edbInfoList = make([]*data_manage.EdbInfo, 0)
-
-	for _, tmpEdbInfoId := range req.EdbInfoIdArr {
-		fromEdbInfo, tmpErr := data_manage.GetEdbInfoById(tmpEdbInfoId.EdbInfoId)
-		if tmpErr != nil {
-			if tmpErr.Error() == utils.ErrNoRow() {
-				err = errors.New("指标 " + strconv.Itoa(tmpEdbInfoId.EdbInfoId) + " 不存在")
-			} else {
-				err = errors.New("获取指标失败:Err:" + tmpErr.Error())
-			}
-			errMsg = "数据计算失败"
-			return
-		}
-		edbInfoList = append(edbInfoList, fromEdbInfo)
-	}
-	ok, _ := CheckFormula2(edbInfoList, formulaMap, formula, edbInfoIdBytes)
-	if !ok {
-		errMsg = "生成计算指标失败,请使用正确的计算公式"
-		err = errors.New(errMsg)
-	}
-	return
-}
-
-// CalculateByRuleByNine 动态环差规则计算入库
-func CalculateByRuleByNine(formulaStr string, edbInfoList []*data_manage.EdbInfo, edbInfoIdBytes []string) (dataList []*data_manage.EdbDataList, err error) {
-	realSaveDataMap := make(map[string]map[int]float64)
-	saveDataMap := make(map[string]map[int]float64)
-	dateList := make([]string, 0) //日期
-
-	formulaStr = strings.ToUpper(formulaStr)
-	// 获取关联指标数据
-	for edbInfoIndex, v := range edbInfoList {
-		sourceDataList, _, _, tmpErr, _ := GetPredictDataListByPredictEdbInfo(v, "", "", false)
-		if tmpErr != nil {
-			err = tmpErr
-			return
-		}
-		dataMap := make(map[string]float64)
-		for _, dv := range sourceDataList {
-			// 实际数据
-			if val, ok := realSaveDataMap[dv.DataTime]; ok {
-				if _, ok := val[v.EdbInfoId]; !ok {
-					val[v.EdbInfoId] = dv.Value
-				}
-			} else {
-				temp := make(map[int]float64)
-				temp[v.EdbInfoId] = dv.Value
-				realSaveDataMap[dv.DataTime] = temp
-			}
-
-			// saveDataMap 待计算的数据
-			if val, ok := saveDataMap[dv.DataTime]; ok {
-				if _, ok := val[v.EdbInfoId]; !ok {
-					val[v.EdbInfoId] = dv.Value
-				}
-			} else {
-				temp2 := make(map[int]float64)
-				temp2[v.EdbInfoId] = dv.Value
-				saveDataMap[dv.DataTime] = temp2
-			}
-
-			// 以第一个指标的日期作为基准日期
-			if edbInfoIndex == 0 {
-				dateList = append(dateList, dv.DataTime)
-			}
-		}
-		item := new(CalculateItems)
-		item.EdbInfoId = v.EdbInfoId
-		item.DataMap = dataMap
-	}
-
-	//数据处理,将日期内不全的数据做补全
-	handleDateSaveDataMap(dateList, realSaveDataMap, saveDataMap, edbInfoList)
-
-	// 添加数据
-	dataList = make([]*data_manage.EdbDataList, 0)
-
-	// 计算规则
-	formulaMap := CheckFormula(formulaStr)
-
-	existDataMap := make(map[string]string)
-
-	for k, date := range dateList {
-		sv := saveDataMap[date]
-		//fmt.Println(date, sv)
-
-		formulaFormStr := ReplaceFormula(edbInfoList, sv, formulaMap, formulaStr, edbInfoIdBytes)
-		if formulaFormStr == `` {
-			//计算公式异常,那么就移除该指标
-			continue
-		}
-
-		//fmt.Println(fmt.Sprintf("formulaFormStr:%s", formulaFormStr))
-		expression := formula.NewExpression(formulaFormStr)
-		calResult, tmpErr := expression.Evaluate()
-		if tmpErr != nil {
-			// 分母为0的报错
-			if strings.Contains(tmpErr.Error(), "divide by zero") {
-				continue
-			}
-			err = errors.New("计算失败:Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr)
-			return
-		}
-		calVal, tmpErr := calResult.Float64()
-		if tmpErr != nil {
-			err = errors.New("计算失败:获取计算值失败 Err:" + tmpErr.Error() + ";formulaStr:" + formulaFormStr)
-			fmt.Println(err)
-			return
-		}
-
-		saveValue, _ := decimal.NewFromFloat(calVal).RoundCeil(4).Float64() //utils.SubFloatToString(calVal, 4)
-		dataTime, _ := time.Parse(utils.FormatDate, date)
-		timestamp := dataTime.UnixNano() / 1e6
-
-		if _, existOk := existDataMap[date]; !existOk {
-			tmpPredictEdbRuleData := &data_manage.EdbDataList{
-				EdbDataId:     k,
-				EdbInfoId:     0,
-				DataTime:      date,
-				DataTimestamp: timestamp,
-				Value:         saveValue,
-			}
-			dataList = append(dataList, tmpPredictEdbRuleData)
-		}
-		existDataMap[date] = date
-	}
-	return
-}
-
 // ModifyPredictEdbBaseInfoBySourceEdb  根据来源ETA指标修改预测指标的基础信息
 func ModifyPredictEdbBaseInfoBySourceEdb(sourceEDdbInfo *data_manage.EdbInfo) {
 	list, err := data_manage.GetGroupPredictEdbBySourceEdbInfoId(sourceEDdbInfo.EdbInfoId)