Эх сурвалжийг харах

Merge branch 'master' into feature/minio_1120

hsun 1 жил өмнө
parent
commit
28c957094b
100 өөрчлөгдсөн 12678 нэмэгдсэн , 2115 устгасан
  1. 1 1
      .gitignore
  2. 336 0
      controllers/ai/ai.go
  3. 35 23
      controllers/base_auth.go
  4. 7 38
      controllers/base_common.go
  5. 52 0
      controllers/business_conf.go
  6. 28 0
      controllers/classify.go
  7. 2 3
      controllers/cloud_disk.go
  8. 2 1
      controllers/commodity_trade_base_index.go
  9. 9 56
      controllers/data_manage/chart_classify.go
  10. 12 0
      controllers/data_manage/chart_common.go
  11. 80 6
      controllers/data_manage/chart_framework.go
  12. 52 13
      controllers/data_manage/chart_info.go
  13. 3 3
      controllers/data_manage/com_trade.go
  14. 1 27
      controllers/data_manage/correlation/correlation_chart_classify.go
  15. 1558 0
      controllers/data_manage/cross_variety/chart_info.go
  16. 554 0
      controllers/data_manage/cross_variety/classify.go
  17. 408 0
      controllers/data_manage/cross_variety/tag.go
  18. 295 0
      controllers/data_manage/cross_variety/variety.go
  19. 1271 162
      controllers/data_manage/edb_info.go
  20. 19 7
      controllers/data_manage/edb_info_calculate.go
  21. 195 24
      controllers/data_manage/excel/excel_info.go
  22. 237 0
      controllers/data_manage/excel/mixed_table.go
  23. 2 28
      controllers/data_manage/future_good/future_good_chart_classify.go
  24. 3 3
      controllers/data_manage/future_good/future_good_chart_info.go
  25. 1 1
      controllers/data_manage/future_good/future_good_edb_info.go
  26. 1 27
      controllers/data_manage/line_equation/line_chart_classify.go
  27. 1 27
      controllers/data_manage/line_feature/classify.go
  28. 75 17
      controllers/data_manage/my_chart.go
  29. 108 56
      controllers/data_manage/mysteel_chemical_data.go
  30. 42 46
      controllers/data_manage/predict_edb_info.go
  31. 197 0
      controllers/data_manage/smm_api.go
  32. 82 9
      controllers/data_manage/smm_data.go
  33. 2 2
      controllers/data_manage/supply_analysis/variety.go
  34. 2 2
      controllers/data_manage/supply_analysis/variety_edb.go
  35. 443 0
      controllers/data_manage/yongyi_data.go
  36. 842 0
      controllers/data_stat/edb_source_stat.go
  37. 200 0
      controllers/data_stat/edb_terminal.go
  38. 18 0
      controllers/english_report/english_classify.go
  39. 3 4
      controllers/english_report/english_company.go
  40. 288 22
      controllers/english_report/report.go
  41. 21 0
      controllers/error.go
  42. 104 11
      controllers/ppt_english.go
  43. 106 8
      controllers/ppt_v2.go
  44. 333 59
      controllers/report.go
  45. 931 0
      controllers/report_approve/report_approve.go
  46. 741 0
      controllers/report_approve/report_approve_flow.go
  47. 2 2
      controllers/report_author.go
  48. 78 43
      controllers/sandbox/sandbox.go
  49. 1 1
      controllers/semantic_analysis/sa_compare.go
  50. 279 26
      controllers/smart_report/smart_report.go
  51. 307 0
      controllers/smart_report/smart_resource.go
  52. 9 12
      controllers/sys_admin.go
  53. 11 12
      controllers/sys_role.go
  54. 2 3
      controllers/sys_role_admin.go
  55. 6 5
      controllers/target.go
  56. 42 24
      controllers/user_login.go
  57. 0 0
      etalogs/binlog/20231023.log
  58. 2 5
      go.mod
  59. 2 8
      go.sum
  60. 6 1
      main.go
  61. 151 0
      models/aimod/ai.go
  62. 31 0
      models/api_uri.go
  63. 20 6
      models/business_conf.go
  64. 27 12
      models/classify.go
  65. 2 2
      models/data_manage/baiinfo_data.go
  66. 1 1
      models/data_manage/base_from_eia_stero.go
  67. 98 0
      models/data_manage/base_from_smm.go
  68. 9 1
      models/data_manage/base_from_smm_classify.go
  69. 146 0
      models/data_manage/base_from_yongyi.go
  70. 223 0
      models/data_manage/base_from_yongyi_classify.go
  71. 23 0
      models/data_manage/chart_classify.go
  72. 108 7
      models/data_manage/chart_edb_mapping.go
  73. 16 13
      models/data_manage/chart_framework.go
  74. 6 1
      models/data_manage/chart_framework_node.go
  75. 18 14
      models/data_manage/chart_info.go
  76. 3 2
      models/data_manage/coal_data.go
  77. 264 0
      models/data_manage/cross_variety/chart_info_cross_variety.go
  78. 148 0
      models/data_manage/cross_variety/chart_tag.go
  79. 262 0
      models/data_manage/cross_variety/chart_tag_variety.go
  80. 121 0
      models/data_manage/cross_variety/chart_variety.go
  81. 67 0
      models/data_manage/cross_variety/chart_variety_mapping.go
  82. 80 0
      models/data_manage/cross_variety/request/chart.go
  83. 31 0
      models/data_manage/cross_variety/request/tag.go
  84. 17 0
      models/data_manage/cross_variety/request/variety.go
  85. 21 0
      models/data_manage/cross_variety/response/chart.go
  86. 26 0
      models/data_manage/cross_variety/response/tag.go
  87. 19 0
      models/data_manage/cross_variety/response/variety.go
  88. 2 2
      models/data_manage/edb_data_baiinfo.go
  89. 93 6
      models/data_manage/edb_data_base.go
  90. 4 4
      models/data_manage/edb_data_calculate.go
  91. 8 8
      models/data_manage/edb_data_calculate_time_shift.go
  92. 2 79
      models/data_manage/edb_data_cffex.go
  93. 2 2
      models/data_manage/edb_data_coal.go
  94. 0 348
      models/data_manage/edb_data_dl.go
  95. 0 469
      models/data_manage/edb_data_gie.go
  96. 2 2
      models/data_manage/edb_data_gl.go
  97. 1 1
      models/data_manage/edb_data_insert_config.go
  98. 2 2
      models/data_manage/edb_data_lz.go
  99. 0 303
      models/data_manage/edb_data_manual.go
  100. 174 2
      models/data_manage/edb_data_quarter.go

+ 1 - 1
.gitignore

@@ -18,4 +18,4 @@
 eta_api.exe
 eta_api.exe~
 /static/tmpFile/*
-/etalogs
+etalogs/

+ 336 - 0
controllers/ai/ai.go

@@ -0,0 +1,336 @@
+package ai
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/aimod"
+	"eta/eta_api/services/aiser"
+	"eta/eta_api/utils"
+	"fmt"
+	"strconv"
+	"time"
+)
+
+// AI
+type AiController struct {
+	controllers.BaseAuthController
+}
+
+// @Title 聊天接口
+// @Description 聊天接口
+// @Param	request	body aimod.ChatReq true "type json string"
+// @Success 200 {object} response.ListResp
+// @router /chat [post]
+func (this *AiController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req aimod.ChatReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.Ask == "" {
+		br.Msg = "请输入提问内容!"
+		br.ErrMsg = "请输入提问内容"
+		return
+	}
+
+	if utils.Re == nil {
+		key := "CACHE_CHAT_" + strconv.Itoa(this.SysUser.AdminId)
+		cacheVal, err := utils.Rc.RedisInt(key)
+		fmt.Println("RedisString:", cacheVal, "err:", err)
+		if err != nil && err.Error() != "redigo: nil returned" {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		putVal := 0
+		if cacheVal <= 0 {
+			putVal = utils.AiChatLimit
+		} else {
+			putVal = cacheVal - 1
+		}
+
+		if putVal <= 0 {
+			br.Msg = "您今日50次问答已达上限,请明天再来!"
+			br.ErrMsg = "您今日50次问答已达上限,请明天再来!"
+			return
+		}
+		lastSecond := utils.GetTodayLastSecond()
+		utils.Rc.Put(key, putVal, lastSecond)
+	}
+
+	//根据提问,获取信息
+	askUuid := utils.MD5(req.Ask)
+	chatMode, err := aimod.GetAiChatByAsk(askUuid)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取数据失败!"
+		br.ErrMsg = "获取数据失败,GetAiChatByAsk,Err:" + err.Error()
+		return
+	}
+	resp := new(aimod.ChatResp)
+	var answer string
+	//answerArr := []string{
+	//	"周度数据显示,成品油现货市场价格跟随原油下跌,但近期相对抗跌,裂解价差走扩。批零价差方面汽油收窄,柴油走扩",
+	//	"出口利润在原油下跌海外成品油矛盾更大的情况下汽柴油出口窗口完全关闭",
+	//	"汽油需求在经历五一假期的一段高峰后将回归平稳,总体没有明显矛盾,后期我们担心更多的还是柴油。"}
+	if chatMode != nil && chatMode.Answer != "" {
+		answer = chatMode.Answer
+	} else {
+		//获取主题下的所有信息
+		//AiChatTopicId
+		historyList, err := aimod.GetAiChatList(req.AiChatTopicId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取主题历史数据失败!"
+			br.ErrMsg = "获取主题历史数据失败,Err:" + err.Error()
+			return
+		}
+
+		historyChatList := make([]aimod.HistoryChat, 0)
+		for _, v := range historyList {
+			historyChat := new(aimod.HistoryChat)
+			historyChat.Ask = v.Ask
+			historyChat.Answer = v.Answer
+			historyChatList = append(historyChatList, *historyChat)
+		}
+
+		answer, err = aiser.ChatAutoMsg(req.Ask, historyChatList)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,ChatAutoMsg,Err:" + err.Error()
+			return
+		}
+	}
+	resp.Ask = req.Ask
+	resp.Answer = answer
+
+	if req.AiChatTopicId <= 0 { //新增
+		topic := new(aimod.AiChatTopic)
+		topic.TopicName = req.Ask
+		topic.SysUserId = this.SysUser.AdminId
+		topic.SysUserRealName = this.SysUser.RealName
+		topic.CreateTime = time.Now()
+		topic.ModifyTime = time.Now()
+		topicId, err := aimod.AddAiChatTopic(topic)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题失败,Err:" + err.Error()
+			return
+		}
+		resp.AiChatTopicId = int(topicId)
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = resp.AiChatTopicId
+		chatItem.Ask = req.Ask
+		chatItem.AskUuid = utils.MD5(req.Ask)
+		chatItem.Answer = answer
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		resp.AiChatTopicId = req.AiChatTopicId
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = resp.AiChatTopicId
+		chatItem.Ask = req.Ask
+		chatItem.AskUuid = utils.MD5(req.Ask)
+		chatItem.Answer = answer
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// @Title 获取话题列表
+// @Description 获取话题列表接口
+// @Success 200 {object} aimod.AiChatTopicListResp
+// @router /topic/list [get]
+func (this *AiController) TopicList() {
+	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
+	}
+	list, err := aimod.GetAiChatTopicList(sysUser.AdminId)
+	if err != nil {
+		br.Msg = "获取数据失败!"
+		br.ErrMsg = "获取主题记录信息失败,Err:" + err.Error()
+		return
+	}
+	resp := new(aimod.AiChatTopicListResp)
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// @Title 获取话题详情
+// @Description 获取话题详情接口
+// @Param   AiChatTopicId   query   int  true       "主题id"
+// @Success 200 {object} aimod.AiChatDetailResp
+// @router /topic/detail [get]
+func (this *AiController) TopicDetail() {
+	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
+	}
+
+	aiChatTopicId, _ := this.GetInt("AiChatTopicId")
+	list, err := aimod.GetAiChatList(aiChatTopicId)
+	if err != nil {
+		br.Msg = "获取数据失败!"
+		br.ErrMsg = "获取主题记录信息失败,Err:" + err.Error()
+		return
+	}
+	resp := new(aimod.AiChatDetailResp)
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// @Title 删除话题接口
+// @Description 删除话题接口
+// @Param	request	body aimod.TopicDeleteReq true "type json string"
+// @Success Ret=200 删除成功
+// @router /topic/delete [post]
+func (this *AiController) TopicDelete() {
+	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
+	}
+
+	var req aimod.TopicDeleteReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.AiChatTopicId <= 0 {
+		br.Msg = "参数错误!"
+		br.ErrMsg = "参数错误!AiChatTopicId:" + strconv.Itoa(req.AiChatTopicId)
+		return
+	}
+	err = aimod.DeleteTopic(req.AiChatTopicId)
+	if err != nil {
+		br.Msg = "删除失败!"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "删除成功"
+	br.IsAddLog = true
+}
+
+// @Title 编辑话题接口
+// @Description 编辑话题接口
+// @Param	request	body aimod.TopicEditReq true "type json string"
+// @Success Ret=200 编辑成功
+// @router /topic/edit [post]
+func (this *AiController) TopicEdit() {
+	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
+	}
+
+	var req aimod.TopicEditReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.AiChatTopicId <= 0 {
+		br.Msg = "参数错误!"
+		br.ErrMsg = "参数错误!AiChatTopicId:" + strconv.Itoa(req.AiChatTopicId)
+		return
+	}
+	topic, err := aimod.GetAiChatTopicByTopicName(req.TopicName)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "编辑失败!"
+		br.ErrMsg = "获取数据失败!Err:" + err.Error()
+		return
+	}
+	if topic != nil && topic.AiChatTopicId != req.AiChatTopicId {
+		br.Msg = "话题名称已存在,请重新修改!"
+		return
+	}
+
+	err = aimod.EditTopic(req.AiChatTopicId, req.TopicName)
+	if err != nil {
+		br.Msg = "编辑失败!"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+	br.IsAddLog = true
+}

+ 35 - 23
controllers/base_auth.go

@@ -7,7 +7,6 @@ import (
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
 	"fmt"
-	"github.com/sirupsen/logrus"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -185,6 +184,35 @@ func (c *BaseAuthController) Prepare() {
 
 			admin.RoleTypeCode = GetSysUserRoleTypeCode(admin.RoleTypeCode)
 			c.SysUser = admin
+
+			//接口权限校验
+			roleId := admin.RoleId
+			list, e := system.GetMenuButtonApisByRoleId(roleId)
+			if e != nil {
+				c.JSON(models.BaseResponse{Ret: 403, Msg: "获取接口权限出错!", ErrMsg: "获取接口权限出错!"}, false, false)
+				c.StopRun()
+				return
+			}
+			var api string
+			for _, v := range list {
+				api += v.Api + "&"
+			}
+			//处理uri请求,去除前缀和参数
+			api = strings.TrimRight(api, "&")
+			uri = strings.Replace(uri, "/adminapi", "", 1)
+			uris := strings.Split(uri, "?")
+			uri = uris[0]
+			fmt.Println("uri:", uri)
+			apis := strings.Split(api, "&")
+			apiMap := make(map[string]bool, 0)
+			for _, s := range apis {
+				apiMap[s] = true
+			}
+			if !apiMap[uri] {
+				c.JSON(models.BaseResponse{Ret: 403, Msg: "无权访问!", ErrMsg: "无权访问!"}, false, false)
+				c.StopRun()
+				return
+			}
 		} else {
 			c.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
 			c.StopRun()
@@ -274,6 +302,8 @@ func (c *BaseAuthController) ServeJSON(encoding ...bool) {
 
 func (c *BaseAuthController) JSON(data interface{}, hasIndent bool, coding bool) error {
 	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+	desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
+	c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
 	var content []byte
 	var err error
 	if hasIndent {
@@ -293,10 +323,10 @@ func (c *BaseAuthController) JSON(data interface{}, hasIndent bool, coding bool)
 	if requestBody == "" {
 		requestBody = c.Ctx.Input.URI()
 	}
-	c.logUri(data, requestBody, ip)
+	c.logUri(content, requestBody, ip)
 	// 如果不是debug分支的话,那么需要加密返回
 	if utils.RunMode != "debug" {
-		content = utils.DesBase64Encrypt(content)
+		content = utils.DesBase64Encrypt(content, utils.DesKey)
 		// get请求时,不加双引号就获取不到数据,不知道什么原因,所以还是在前后加上双引号吧
 		content = []byte(`"` + string(content) + `"`)
 	}
@@ -356,7 +386,7 @@ func GetSysUserRoleTypeCode(roleTypeCode string) string {
 	return ""
 }
 
-func (c *BaseAuthController) logUri(data interface{}, requestBody, ip string) {
+func (c *BaseAuthController) logUri(respContent []byte, requestBody, ip string) {
 	authorization := ""
 	method := c.Ctx.Input.Method()
 	uri := c.Ctx.Input.URI()
@@ -394,24 +424,6 @@ func (c *BaseAuthController) logUri(data interface{}, requestBody, ip string) {
 		}
 	}
 
-	var reqData interface{}
-	err := json.Unmarshal([]byte(requestBody), &reqData)
-	if err != nil {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":           c.Ctx.Input.URI(),
-			"authorization": authorization,
-			"requestBody":   requestBody,
-			"responseBody":  data,
-			"ip":            ip,
-		}).Info("请求详情")
-	} else {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":           c.Ctx.Input.URI(),
-			"authorization": authorization,
-			"requestBody":   reqData,
-			"responseBody":  data,
-			"ip":            ip,
-		}).Info("请求详情")
-	}
+	utils.ApiLog.Info("uri:%s, authorization:%s, requestBody:%s, responseBody:%s, ip:%s", c.Ctx.Input.URI(), authorization, requestBody, respContent, ip)
 	return
 }

+ 7 - 38
controllers/base_common.go

@@ -8,7 +8,6 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/server/web"
-	"github.com/sirupsen/logrus"
 	"net/http"
 	"net/url"
 	"strings"
@@ -27,21 +26,7 @@ func (c *BaseCommonController) Prepare() {
 		requestBody, _ = url.QueryUnescape(string(c.Ctx.Input.RequestBody))
 	}
 	ip := c.Ctx.Input.IP()
-	var reqData interface{}
-	err := json.Unmarshal([]byte(requestBody), &reqData)
-	if err != nil {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":         c.Ctx.Input.URI(),
-			"requestBody": requestBody,
-			"ip":          ip,
-		}).Info("Prepare 请求详情")
-	} else {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":         c.Ctx.Input.URI(),
-			"requestBody": reqData,
-			"ip":          ip,
-		}).Info("Prepare 请求详情")
-	}
+	utils.ApiLog.Info("uri:%s, requestBody:%s, responseBody:%s, ip:%s", c.Ctx.Input.URI(), requestBody, ip)
 }
 
 func (c *BaseCommonController) ServeJSON(encoding ...bool) {
@@ -100,6 +85,8 @@ func (c *BaseCommonController) ServeJSON(encoding ...bool) {
 
 func (c *BaseCommonController) JSON(data interface{}, hasIndent bool, coding bool) error {
 	c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8")
+	desEncrypt := utils.DesBase64Encrypt([]byte(utils.DesKey), utils.DesKeySalt)
+	c.Ctx.Output.Header("Dk", string(desEncrypt)) // des3加解密key
 	var content []byte
 	var err error
 	if hasIndent {
@@ -116,10 +103,10 @@ func (c *BaseCommonController) JSON(data interface{}, hasIndent bool, coding boo
 	fmt.Println("params")
 	fmt.Println(params)
 	requestBody, _ := url.QueryUnescape(string(c.Ctx.Input.RequestBody))
-	c.logUri(data, requestBody, ip)
+	c.logUri(content, requestBody, ip)
 	// 如果不是debug分支的话,那么需要加密返回
 	if utils.RunMode != "debug" {
-		content = utils.DesBase64Encrypt(content)
+		content = utils.DesBase64Encrypt(content, utils.DesKey)
 		// get请求时,不加双引号就获取不到数据,不知道什么原因,所以还是在前后加上双引号吧
 		content = []byte(`"` + string(content) + `"`)
 	}
@@ -129,7 +116,7 @@ func (c *BaseCommonController) JSON(data interface{}, hasIndent bool, coding boo
 	return c.Ctx.Output.Body(content)
 }
 
-func (c *BaseCommonController) logUri(data interface{}, requestBody, ip string) {
+func (c *BaseCommonController) logUri(respContent []byte, requestBody, ip string) {
 	authorization := ""
 	method := c.Ctx.Input.Method()
 	uri := c.Ctx.Input.URI()
@@ -167,24 +154,6 @@ func (c *BaseCommonController) logUri(data interface{}, requestBody, ip string)
 		}
 	}
 
-	var reqData interface{}
-	err := json.Unmarshal([]byte(requestBody), &reqData)
-	if err != nil {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":           c.Ctx.Input.URI(),
-			"authorization": authorization,
-			"requestBody":   requestBody,
-			"responseBody":  data,
-			"ip":            ip,
-		}).Info("请求详情")
-	} else {
-		utils.ApiLog.WithFields(logrus.Fields{
-			"uri":           c.Ctx.Input.URI(),
-			"authorization": authorization,
-			"requestBody":   reqData,
-			"responseBody":  data,
-			"ip":            ip,
-		}).Info("请求详情")
-	}
+	utils.ApiLog.Info("uri:%s, authorization:%s, requestBody:%s, responseBody:%s, ip:%s", c.Ctx.Input.URI(), authorization, requestBody, respContent, ip)
 	return
 }

+ 52 - 0
controllers/business_conf.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"encoding/json"
 	"eta/eta_api/models"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"html"
@@ -62,6 +63,9 @@ func (this *BusinessConfController) Save() {
 		confMap[c.ConfKey] = c
 	}
 
+	openApprove := ""
+	approveType := ""
+
 	// 根据配置类型取值
 	updates := make([]models.BusinessConfUpdate, 0)
 	for k, v := range req {
@@ -86,6 +90,18 @@ func (this *BusinessConfController) Save() {
 				ConfKey: k,
 				ConfVal: str,
 			})
+
+			// 取出审批参数
+			if k == models.BusinessConfIsReportApprove {
+				openApprove = str
+			}
+			if k == models.BusinessConfReportApproveType {
+				// 打开审批默认为内部审批方式
+				if openApprove == "true" && str == "" {
+					str = models.BusinessConfReportApproveTypeEta
+				}
+				approveType = str
+			}
 		case 2: // 数值
 			num, ok := v.(float64)
 			if !ok {
@@ -138,6 +154,42 @@ func (this *BusinessConfController) Save() {
 		}
 	}
 
+	// 校验报告审批是否可以切换
+	confOpenApprove := confMap[models.BusinessConfIsReportApprove]
+	confApproveType := confMap[models.BusinessConfReportApproveType]
+	if confOpenApprove != nil && confApproveType != nil {
+		// 仅校验有审批->无审批, 或是有审批->切换审批方式的情况
+		if openApprove == "false" && confOpenApprove.ConfVal == "true" || (openApprove == "true" && openApprove == confOpenApprove.ConfVal && confApproveType.ConfVal != approveType) {
+			ok, e := services.CheckCloseReportApproveConf()
+			if e != nil {
+				br.Msg = "保存失败"
+				br.ErrMsg = "校验是否可以关闭报告审批失败, Err: " + e.Error()
+				return
+			}
+			if !ok {
+				br.Msg = "当前有未走完流程的报告,请走完流程后再做变更"
+				return
+			}
+		}
+		// 审批设置切换对未发布/待提交报告状态的重置
+		needReset := false
+		changeType := ""
+		if openApprove == "false" && confOpenApprove.ConfVal == "true" {
+			needReset = true
+		}
+		if openApprove == "true" && confOpenApprove.ConfVal == "false" {
+			needReset = true
+			changeType = approveType
+		}
+		if openApprove == "true" && openApprove == confOpenApprove.ConfVal && confApproveType.ConfVal != approveType {
+			needReset = true
+			changeType = approveType
+		}
+		if needReset {
+			go services.ConfigChangeResetReportState(changeType)
+		}
+	}
+
 	if len(updates) > 0 {
 		if e = models.UpdateBusinessConfMulti(updates); e != nil {
 			br.Msg = "保存失败"

+ 28 - 0
controllers/classify.go

@@ -3,9 +3,11 @@ package controllers
 import (
 	"encoding/json"
 	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
+	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
 	"time"
 )
@@ -284,6 +286,28 @@ func (this *ClassifyController) CheckDeleteClassify() {
 			return
 		}
 	}
+
+	// 查询该分类是否关联了审批流
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowCond := fmt.Sprintf(` AND (%s = ? OR %s = ?) AND (%s = ? OR %s = ?)`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowPars := make([]interface{}, 0)
+	flowPars = append(flowPars, report_approve.FlowReportTypeChinese, report_approve.FlowReportTypeSmart, classifyId, classifyId)
+	flowCount, e := flowOb.GetCountByCondition(flowCond, flowPars)
+	if e != nil {
+		br.Msg = "检测失败"
+		br.ErrMsg = "获取关联审批流失败, Err: " + e.Error()
+		return
+	}
+	if flowCount > 0 {
+		resp.Code = 5
+		resp.Msg = "该分类关联审批流,不允许删除"
+		br.Data = resp
+		br.Ret = 200
+		br.Msg = resp.Msg
+		br.Success = true
+		return
+	}
+
 	resp.Code = 0
 	resp.Msg = "检测完成,可进行删除操作"
 	br.Ret = 200
@@ -669,6 +693,10 @@ func (this *ClassifyController) ListClassify() {
 	keyWord := this.GetString("KeyWord")
 	companyType := this.GetString("CompanyType")
 	hideDayWeek, _ := this.GetInt("HideDayWeek")
+	// 商家不隐藏晨周报
+	if utils.BusinessCode != utils.BusinessCodeRelease {
+		hideDayWeek = 0
+	}
 
 	var startSize int
 	if pageSize <= 0 {

+ 2 - 3
controllers/cloud_disk.go

@@ -794,11 +794,10 @@ func (this *CloudDiskController) List() {
 	resourcePars := make([]interface{}, 0)
 	if keyword != "" {
 		// 有关键词时全局搜索
-		kw := "%" + keyword + "%"
 		menuCond += ` AND menu_name LIKE ? `
-		menuPars = append(menuPars, kw)
+		menuPars = append(menuPars, utils.GetLikeKeyword(keyword))
 		resourceCond += ` AND resource_name LIKE ? `
-		resourcePars = append(resourcePars, kw)
+		resourcePars = append(resourcePars, utils.GetLikeKeyword(keyword))
 	} else {
 		menuCond += ` AND parent_id = ? `
 		menuPars = append(menuPars, menuId)

+ 2 - 1
controllers/commodity_trade_base_index.go

@@ -15,8 +15,9 @@ import (
 )
 
 type TradeCommonController struct {
-	BaseCommonController
+	BaseAuthController
 }
+
 type Data []struct {
 	Title    string
 	ItemList []ShanghaiList

+ 9 - 56
controllers/data_manage/chart_classify.go

@@ -95,7 +95,7 @@ func (this *ChartClassifyController) ChartClassifyListV2() {
 			return
 		}
 		// 移除没有权限的图表
-		allNodes := handleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
+		allNodes := data.HandleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
 		resp.AllNodes = allNodes
 
 		br.Ret = 200
@@ -110,11 +110,11 @@ func (this *ChartClassifyController) ChartClassifyListV2() {
 	key := utils.CACHE_CHART_CLASSIFY
 	if utils.Re == nil {
 		if utils.Re == nil && utils.Rc.IsExist(key) {
-			if data, err1 := utils.Rc.RedisBytes(key); err1 == nil {
-				err := json.Unmarshal(data, &resp)
+			if redisData, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err := json.Unmarshal(redisData, &resp)
 				if err == nil && resp != nil {
 					// 移除没有权限的图表
-					allNodes := handleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
+					allNodes := data.HandleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
 					resp.AllNodes = allNodes
 
 					br.Ret = 200
@@ -185,12 +185,12 @@ func (this *ChartClassifyController) ChartClassifyListV2() {
 
 	// 将数据加入缓存
 	if utils.Re == nil {
-		data, _ := json.Marshal(resp)
-		utils.Rc.Put(key, data, 2*time.Hour)
+		redisData, _ := json.Marshal(resp)
+		utils.Rc.Put(key, redisData, 2*time.Hour)
 	}
 
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
 	resp.AllNodes = allNodes
 
 	br.Ret = 200
@@ -248,53 +248,6 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	return
 }
 
-// handleNoPermissionChart 图表列表返回,将没有权限的图表移除
-func handleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermissionChartIdMap map[int]bool) (newAllNodes []*data_manage.ChartClassifyItems) {
-	// 移除没有权限的图表
-	newAllNodes = make([]*data_manage.ChartClassifyItems, 0)
-	for _, node := range allNodes {
-		// 二级分类
-		tmpNodeInfo := *node
-		tmpNodeList := make([]*data_manage.ChartClassifyItems, 0)
-		if node.Children != nil {
-			for _, chartList := range node.Children {
-				tmpInfo := *chartList
-				tmpList := make([]*data_manage.ChartClassifyItems, 0)
-
-				if chartList.Children != nil {
-					for _, chartInfo := range chartList.Children {
-						thirdInfo := *chartInfo
-						thirdList := make([]*data_manage.ChartClassifyItems, 0)
-						// 如果指标不可见,那么就不返回该指标
-						if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-							continue
-						}
-						tmpList = append(tmpList, chartInfo)
-
-						if chartInfo.Children != nil {
-							for _, thirdChart := range chartInfo.Children {
-								// 如果指标不可见,那么就不返回该指标
-								if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-									continue
-								}
-								thirdList = append(thirdList, thirdChart)
-							}
-						}
-						thirdInfo.Children = thirdList
-						tmpList = append(tmpList, &thirdInfo)
-					}
-				}
-				tmpInfo.Children = tmpList
-				tmpNodeList = append(tmpNodeList, &tmpInfo)
-			}
-		}
-		tmpNodeInfo.Children = tmpNodeList
-		newAllNodes = append(newAllNodes, &tmpNodeInfo)
-	}
-
-	return
-}
-
 // ChartClassifyItems
 // @Title 获取所有图表分类接口-不包含图表
 // @Description 获取所有图表分类接口-不包含图表
@@ -1015,7 +968,7 @@ func (this *ChartClassifyController) ChartClassifyChartListV2() {
 			return
 		}
 		// 移除没有权限的图表
-		allNodes := handleNoPermissionChart(allChartInfo, noPermissionChartIdMap)
+		allNodes := data.HandleNoPermissionChart(allChartInfo, noPermissionChartIdMap)
 		resp.AllNodes = allNodes
 
 		br.Ret = 200
@@ -1033,7 +986,7 @@ func (this *ChartClassifyController) ChartClassifyChartListV2() {
 		return
 	}
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(allChartInfo, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(allChartInfo, noPermissionChartIdMap)
 
 	for k, item := range allNodes {
 		item.Button = data.GetChartOpButton(this.SysUser, item.SysUserId)

+ 12 - 0
controllers/data_manage/chart_common.go

@@ -2,6 +2,7 @@ package data_manage
 
 import (
 	"eta/eta_api/controllers/data_manage/correlation"
+	"eta/eta_api/controllers/data_manage/cross_variety"
 	"eta/eta_api/controllers/data_manage/future_good"
 	"eta/eta_api/controllers/data_manage/line_equation"
 	"eta/eta_api/controllers/data_manage/line_feature"
@@ -138,6 +139,17 @@ func (this *ChartInfoController) CommonChartInfoDetailFromUniqueCode() {
 		br.Success = true
 		br.Msg = "获取成功"
 		br.Data = resp
+	case utils.CHART_SOURCE_CROSS_HEDGING:
+		resp, isOk, msg, errMsg := cross_variety.GetChartInfoDetailFromUniqueCode(chartInfo, isCache, sysUser)
+		if !isOk {
+			br.Msg = msg
+			br.ErrMsg = errMsg
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
 	default:
 		br.Msg = "错误的图表"
 		br.ErrMsg = "错误的图表"

+ 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

+ 52 - 13
controllers/data_manage/chart_info.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/response"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/services/data"
@@ -1466,14 +1467,14 @@ func (this *ChartInfoController) ChartInfoEdbInfoDetail() {
 
 	switch edbInfo.EdbInfoType {
 	case 0: //普通源指标
-		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfoId, startDateReal, endDate)
+		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDateReal, endDate)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.Msg = "获取失败,Err:" + err.Error()
 			return
 		}
 		//查询区间内最大最小值
-		minData, maxData, err = data_manage.GetEdbDataListMinAndMax(edbInfo.Source, edbInfoId, startDateReal, endDate)
+		minData, maxData, err = data_manage.GetEdbDataListMinAndMax(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDateReal, endDate)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.Msg = "获取指标最新的最大最小值失败,Err:" + err.Error()
@@ -1490,7 +1491,7 @@ func (this *ChartInfoController) ChartInfoEdbInfoDetail() {
 		// 有预测数据,且为普通的预测指标
 		if len(dataList) > 0 && edbInfo.EdbInfoType == 0 {
 			//查询区间内最大最小值
-			minData, maxData, err = data_manage.GetEdbDataListMinAndMax(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, startDateReal, endDate)
+			minData, maxData, err = data_manage.GetEdbDataListMinAndMax(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, sourceEdbInfoItem.EdbInfoId, startDateReal, endDate)
 			if err != nil {
 				br.Msg = "获取失败"
 				br.Msg = "获取指标最新的最大最小值失败,Err:" + err.Error()
@@ -2297,24 +2298,22 @@ func (this *EdbInfoController) BatchChartInfoRefresh() {
 		return
 	}
 
-	err, isAsync := data.BatchChartInfoRefreshV2(chartInfoList)
+	redisKey := data.GetBatchChartRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+
+	// 图表中的指标刷新
+	err, isAsync := data.BatchChartInfoRefreshV2(chartInfoList, redisKey)
 	if err != nil {
 		br.Msg = "刷新失败"
 		br.ErrMsg = "刷新图表关联指标信息失败,Err:" + err.Error()
 		return
 	}
-
-	//清除图表缓存
-	for _, v := range chartInfoList {
-		key := utils.HZ_CHART_LIB_DETAIL + v.UniqueCode
-		_ = utils.Rc.Delete(key)
-	}
-	br.Ret = 200
-	br.Success = true
 	br.Msg = "刷新成功"
 	if isAsync {
-		br.Msg = "图表关联指标较多,请10分钟后刷新页面查看最新数据"
+		br.Msg = "研报中图表关联指标较多,请10分钟后刷新页面查看最新数据"
 	}
+	br.Ret = 200
+	br.Success = true
+
 }
 
 // CopyChartInfo
@@ -2744,6 +2743,46 @@ func (this *ChartInfoController) PreviewSectionScatterChartInfo() {
 	br.Data = resp
 }
 
+// GetBatchChartRefreshResult
+// @Title 获取批量刷新图表结果的接口
+// @Description 获取批量刷新图表结果的接口
+// @Param	request	body data_manage.BatchChartRefreshReq true "type json string"
+// @Success Ret=200 刷新成功
+// @router /chart_info/batch_refresh/result [post]
+func (this *EdbInfoController) GetBatchChartRefreshResult() {
+	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
+	}
+	var req data_manage.BatchChartRefreshReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 刷新结果,默认是刷新完成了
+	refreshResult := data.CheckBatchChartRefreshResult(req.Source, req.ReportId, req.ReportChapterId)
+
+	resp := response.ChartRefreshResp{
+		RefreshResult: refreshResult,
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+
+}
+
 //
 //修复数据时间戳
 

+ 3 - 3
controllers/data_manage/com_trade.go

@@ -1,11 +1,11 @@
 package data_manage
 
 import (
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"time"
 )
 
@@ -236,7 +236,7 @@ func (this *EdbInfoController) ComTradeList() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += ` AND ( index_name_cn like ? or index_code like ? ) `
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	list, err := data_manage.GetComTradeIndexList(condition, pars)

+ 1 - 27
controllers/data_manage/correlation/correlation_chart_classify.go

@@ -104,7 +104,7 @@ func (this *CorrelationChartClassifyController) ChartClassifyList() {
 	}
 
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(rootList, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(rootList, noPermissionChartIdMap)
 	resp.AllNodes = allNodes
 
 	br.Ret = 200
@@ -162,32 +162,6 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	return
 }
 
-// handleNoPermissionChart 图表列表返回,将没有权限的图表移除
-func handleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermissionChartIdMap map[int]bool) (newAllNodes []*data_manage.ChartClassifyItems) {
-	// 移除没有权限的图表
-	newAllNodes = make([]*data_manage.ChartClassifyItems, 0)
-	for _, node := range allNodes {
-		// 二级分类
-		tmpNodeInfo := *node
-		tmpNodeList := make([]*data_manage.ChartClassifyItems, 0)
-
-		if node.Children != nil {
-			for _, chartInfo := range node.Children {
-				// 如果指标不可见,那么就不返回该指标
-				if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-					continue
-				}
-				tmpNodeList = append(tmpNodeList, chartInfo)
-			}
-		}
-
-		tmpNodeInfo.Children = tmpNodeList
-		newAllNodes = append(newAllNodes, &tmpNodeInfo)
-	}
-
-	return
-}
-
 // ChartClassifyItems
 // @Title 获取所有相关性图表分类接口-不包含图表
 // @Description 获取所有相关性图表分类接口-不包含图表

+ 1558 - 0
controllers/data_manage/cross_variety/chart_info.go

@@ -0,0 +1,1558 @@
+package cross_variety
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	cross_varietyModels "eta/eta_api/models/data_manage/cross_variety"
+	"eta/eta_api/models/data_manage/cross_variety/request"
+	"eta/eta_api/models/data_manage/cross_variety/response"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	"eta/eta_api/services/data/cross_variety"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// ChartInfoController
+// @Description: 跨品种分析图表
+type ChartInfoController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 跨品种分析图表列表接口
+// @Description 跨品种分析图表列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ChartClassifyId   query   int  true       "分类id"
+// @Param   Keyword   query   string  true       "搜索关键词"
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Param   Source   query   int  true       "图表类型,10:跨品种分析
+// @Success 200 {object} data_manage.ChartListResp
+// @router /chart_info/list [get]
+func (c *ChartInfoController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	chartClassifyId, _ := c.GetInt("ChartClassifyId")
+
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+	keyword := c.GetString("KeyWord")
+
+	var total int
+	page := paging.GetPaging(currentIndex, pageSize, total)
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	source, _ := c.GetInt("Source")
+	if source <= 0 {
+		source = utils.CHART_SOURCE_CROSS_HEDGING
+	}
+
+	var condition string
+	var pars []interface{}
+
+	// 普通图表
+	condition += ` AND source = ? `
+	pars = append(pars, source)
+
+	if chartClassifyId > 0 {
+		chartClassifyId, err := data_manage.GetChartClassify(chartClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取图表信息失败"
+			br.ErrMsg = "获取信息失败,GetChartClassify,Err:" + err.Error()
+			return
+		}
+		condition += " AND chart_classify_id IN(" + chartClassifyId + ") "
+	}
+	if keyword != "" {
+		condition += ` AND  ( chart_name LIKE '%` + keyword + `%' )`
+	}
+
+	//只看我的
+	isShowMe, _ := c.GetBool("IsShowMe")
+	if isShowMe {
+		condition += ` AND sys_user_id = ? `
+		pars = append(pars, sysUser.AdminId)
+	}
+
+	// 获取当前账号的不可见指标
+	noPermissionChartIdList := make([]int, 0)
+	{
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllChartListByAdminId(c.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range confList {
+			noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
+		}
+	}
+
+	lenNoPermissionChartIdList := len(noPermissionChartIdList)
+	if lenNoPermissionChartIdList > 0 {
+		condition += ` AND chart_info_id not in (` + utils.GetOrmInReplace(lenNoPermissionChartIdList) + `) `
+		pars = append(pars, noPermissionChartIdList)
+	}
+
+	//获取图表信息
+	list, err := data_manage.GetChartListByCondition(condition, pars, startSize, pageSize)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Success = true
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	myChartList, err := data_manage.GetMyChartListByAdminId(sysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取我的图表信息失败,Err:" + err.Error()
+		return
+	}
+	myChartMap := make(map[int]*data_manage.MyChartView)
+	for _, v := range myChartList {
+		myChartMap[v.ChartInfoId] = v
+	}
+	listLen := len(list)
+	chartEdbMap := make(map[int][]*data_manage.ChartEdbInfoMapping)
+	if listLen > 0 {
+		chartInfoIds := ""
+		for _, v := range list {
+			chartInfoIds += strconv.Itoa(v.ChartInfoId) + ","
+		}
+		if chartInfoIds != "" {
+			chartInfoIds = strings.Trim(chartInfoIds, ",")
+			//判断是否需要展示英文标识
+			edbList, e := data_manage.GetChartEdbMappingListByChartInfoIds(chartInfoIds)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + e.Error()
+				return
+			}
+			for _, v := range edbList {
+				chartEdbMap[v.ChartInfoId] = append(chartEdbMap[v.ChartInfoId], v)
+			}
+		}
+	}
+	for i := 0; i < listLen; i++ {
+		//判断是否需要展示英文标识
+		if edbTmpList, ok := chartEdbMap[list[i].ChartInfoId]; ok {
+			list[i].IsEnChart = data.CheckIsEnChart(list[i].ChartNameEn, edbTmpList, list[i].Source, list[i].ChartType)
+		}
+
+		if existItem, ok := myChartMap[list[i].ChartInfoId]; ok {
+			list[i].IsAdd = true
+			list[i].MyChartId = existItem.MyChartId
+			list[i].MyChartClassifyId = existItem.MyChartClassifyId
+		}
+	}
+
+	resp := new(data_manage.ChartListResp)
+	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
+		items := make([]*data_manage.ChartInfoView, 0)
+		resp.Paging = page
+		resp.List = items
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		return
+	}
+
+	dataCount, err := data_manage.GetChartListCountByCondition(condition, pars)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
+		return
+	}
+	page = paging.GetPaging(currentIndex, pageSize, dataCount)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Preview
+// @Title 跨品种分析图表-预览数据
+// @Description 跨品种分析图表-获取预览数据
+// // @Param	request	body request.ChartConfigReq true "type json string"
+// @Success 200 {object} data_manage.ChartEdbInfoDetailResp
+// @router /chart_info/preview [post]
+func (c *ChartInfoController) Preview() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.ChartConfigReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.TagX <= 0 {
+		br.Msg = "请选择X轴坐标的标签"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.TagY <= 0 {
+		br.Msg = "请选择Y轴坐标的标签"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.CalculateValue <= 0 {
+		br.Msg = "请设置时间长度"
+		br.IsSendEmail = false
+		return
+	}
+	if req.CalculateUnit == `` {
+		br.Msg = "请设置时间频度"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 品种配置
+	varietyListList := len(req.VarietyList)
+	if varietyListList < 0 {
+		br.Msg = "请选择品种"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 日期配置
+	dateConfigList := len(req.DateConfigList)
+	if dateConfigList < 0 {
+		br.Msg = "请选择日期"
+		br.IsSendEmail = false
+		return
+	}
+	if dateConfigList > 5 {
+		br.Msg = "日期数量已达上限!"
+		br.IsSendEmail = false
+		return
+	}
+
+	chartInfo := new(data_manage.ChartInfoView)
+	chartInfo.ChartType = utils.CHART_SOURCE_CROSS_HEDGING
+
+	// 获取图表x轴y轴
+	edbInfoList, dataResp, err, errMsg, isSendEmail := cross_variety.GetChartData(0, req)
+	if err != nil {
+		br.IsSendEmail = isSendEmail
+		br.Msg = "获取失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	resp := response.ChartPreviewResp{
+		EdbInfoList: edbInfoList,
+		DataResp:    dataResp,
+	}
+	//resp.EdbInfoList = edbList
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Add
+// @Title 新增图表接口
+// @Description 新增图表接口
+// @Param	request	body request.AddChartInfoReq true "type json string"
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /chart_info/add [post]
+func (c *ChartInfoController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	cacheKey := "CACHE_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+
+	var req request.AddChartReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 添加图表
+	chartInfo, err, errMsg, isSendEmail := cross_variety.AddChartInfo(req, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "新增跨品种分析图表"
+		chartLog.Method = c.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = chartInfo.ChartType
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// Edit
+// @Title 编辑图表接口
+// @Description 编辑图表接口
+// @Param	request	body request.EditChartInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /chart_info/edit [post]
+func (c *ChartInfoController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.EditChartReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	chartItem, err, errMsg, isSendEmail := cross_variety.EditChartInfo(req, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartItem.ChartInfoId
+	resp.UniqueCode = chartItem.UniqueCode
+	//resp.ChartType = req.ChartType
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "编辑跨品种分析图表"
+		chartLog.Method = c.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// Detail
+// @Title 获取图表详情
+// @Description 获取图表详情接口
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Success 200 {object} data_manage.ChartInfoDetailResp
+// @router /chart_info/detail [get]
+func (c *ChartInfoController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	chartInfoId, _ := c.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+
+	var err error
+	chartInfo := new(data_manage.ChartInfoView)
+	chartInfo, err = data_manage.GetChartInfoViewById(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图被删除,请刷新页面"
+			br.ErrMsg = "图被删除,请刷新页面,Err:" + err.Error()
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	if chartInfo.ExtraConfig == `` {
+		br.Msg = "图表配置信息异常"
+		br.ErrMsg = "图表配置信息异常"
+		br.IsSendEmail = false
+		return
+	}
+	var config request.ChartConfigReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &config)
+	if err != nil {
+		br.Msg = "解析跨品种分析配置失败"
+		br.ErrMsg = "解析跨品种分析配置失败,Err:" + err.Error()
+		return
+	}
+
+	//mappingList, err := cross_varietyModel.GetChartVarietyMappingList(chartInfo.ChartInfoId)
+	//if err != nil {
+	//	br.Msg = "获取品种失败"
+	//	br.ErrMsg = "获取品种失败,Err:" + err.Error()
+	//	return
+	//}
+	// 获取跨品种分析配置
+	//chartInfoCrossVariety, err := cross_varietyModel.GetChartInfoCrossVarietyByChartInfoId(chartInfo.ChartInfoId)
+	//if err != nil {
+	//	br.Msg = "获取跨品种分析配置失败"
+	//	br.ErrMsg = "获取跨品种分析配置失败,Err:" + err.Error()
+	//	return
+	//}
+	//
+	//varietyIdList := make([]int,0)
+	//for _,v:=range mappingList{
+	//	varietyIdList = append(varietyIdList,v.ChartVarietyId)
+	//}
+	//config := request.ChartConfigReq{
+	//	TagX:           chartInfoCrossVariety.ChartXTagId,
+	//	TagY:           chartInfoCrossVariety.ChartYTagId,
+	//	CalculateValue: chartInfoCrossVariety.CalculateValue,
+	//	CalculateUnit:  chartInfoCrossVariety.CalculateUnit,
+	//	DateConfigList: config.DateConfigList,
+	//	VarietyList:    varietyIdList,
+	//}
+	//config.TagX =
+
+	// 获取图表x轴y轴
+	edbList, dataResp, err, errMsg, isSendEmail := cross_variety.GetChartData(0, config)
+	if err != nil {
+		br.IsSendEmail = isSendEmail
+		br.Msg = "获取失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	// 完善指标信息
+	//edbList, e := correlationServ.GetChartEdbInfoFormat(chartInfo.ChartInfoId, edbInfoMappingA, edbInfoMappingB)
+	//if e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取跨品种分析图表, 完善指标信息失败, Err:" + e.Error()
+	//	return
+	//}
+
+	// 判断是否加入我的图库
+	if chartInfoId > 0 && chartInfo != nil {
+		{
+			var myChartCondition string
+			var myChartPars []interface{}
+			myChartCondition += ` AND a.admin_id=? `
+			myChartPars = append(myChartPars, sysUser.AdminId)
+			myChartCondition += ` AND a.chart_info_id=? `
+			myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+			myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+				return
+			}
+			if myChartList != nil && len(myChartList) > 0 {
+				chartInfo.IsAdd = true
+				chartInfo.MyChartId = myChartList[0].MyChartId
+				chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+			}
+		}
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+	////判断是否需要展示英文标识
+	//chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
+	//chartInfo.UnitEn = edbInfoMappingA.UnitEn
+
+	// 另存为
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp := new(data_manage.ChartInfoDetailResp)
+	resp.ChartInfo = chartInfo
+	resp.DataResp = dataResp
+	resp.EdbInfoList = edbList
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Relation
+// @Title 获取图表的关联信息
+// @Description 获取图表的关联信息
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Success 200 {object} data_manage.ChartInfoDetailResp
+// @router /chart_info/relation [get]
+func (c *ChartInfoController) Relation() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	chartInfoId, _ := c.GetInt("ChartInfoId")
+	if chartInfoId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+
+	var err error
+	chartInfo := new(data_manage.ChartInfoView)
+	chartInfo, err = data_manage.GetChartInfoViewById(chartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图被删除,请刷新页面"
+			br.ErrMsg = "图被删除,请刷新页面,Err:" + err.Error()
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	if chartInfo.ExtraConfig == `` {
+		br.Msg = "图表配置信息异常"
+		br.ErrMsg = "图表配置信息异常"
+		br.IsSendEmail = false
+		return
+	}
+	var config request.ChartConfigReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &config)
+	if err != nil {
+		br.Msg = "解析跨品种分析配置失败"
+		br.ErrMsg = "解析跨品种分析配置失败,Err:" + err.Error()
+		return
+	}
+
+	tmpTagList, err := cross_varietyModels.GetTagListByIdList([]int{config.TagX, config.TagY})
+	if err != nil {
+		br.Msg = "获取标签信息失败"
+		br.ErrMsg = "获取标签信息失败,Err:" + err.Error()
+		return
+	}
+
+	var xTag, yTag *cross_varietyModels.ChartTag
+	for _, v := range tmpTagList {
+		if v.ChartTagId == config.TagX {
+			xTag = v
+		} else {
+			yTag = v
+		}
+	}
+	tagList := []*cross_varietyModels.ChartTag{
+		xTag, yTag,
+	}
+
+	// 获取品种列表
+	varietyList, err := cross_varietyModels.GetVarietyListByIdList(config.VarietyList)
+	if err != nil {
+		br.Msg = "获取品种信息失败"
+		br.ErrMsg = "获取品种信息失败,Err:" + err.Error()
+		return
+	}
+	resp := response.ChartRelationResp{
+		ChartInfo:   chartInfo,
+		TagList:     tagList,
+		VarietyList: varietyList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Copy
+// @Title 复制并新增图表接口
+// @Description 新增图表接口
+// @Param	request	body data_manage.CopyAddChartInfoReq true "type json string"
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /chart_info/copy [post]
+func (c *ChartInfoController) Copy() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	deleteCache := true
+	cacheKey := "CACHE_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		return
+	}
+	var req request.CopyAddChartInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 获取原图表信息
+	oldChartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		br.Msg = "获取原图表信息失败"
+		br.ErrMsg = "获取原图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	var config request.AddChartReq
+	err = json.Unmarshal([]byte(oldChartInfo.ExtraConfig), &config)
+	if err != nil {
+		br.Msg = "原图表信息配置解析异常!"
+		br.ErrMsg = "原图表信息配置解析失败,Err:" + err.Error()
+		return
+	}
+	config.ChartName = req.ChartName
+	config.ChartImage = oldChartInfo.ChartImage
+
+	// 添加图表
+	chartInfo, err, errMsg, isSendEmail := cross_variety.AddChartInfo(config, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "复制跨品种分析图表"
+		chartLog.Method = c.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = data_manage.AddChartInfoResp{
+		ChartInfoId: chartInfo.ChartInfoId,
+		UniqueCode:  chartInfo.UniqueCode,
+		ChartType:   chartInfo.ChartType,
+	}
+	br.IsAddLog = true
+}
+
+// Move
+// @Title 移动图表接口
+// @Description 移动图表接口
+// @Success 200 {object} data_manage.MoveChartInfoReq
+// @router /chart_info/move [post]
+func (c *ChartInfoController) Move() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.MoveChartInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "图表id小于等于0"
+		br.IsSendEmail = false
+		return
+	}
+
+	chartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		br.Msg = "移动失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	if chartInfo.Source != utils.CHART_SOURCE_CROSS_HEDGING {
+		br.Msg = "图表异常"
+		br.ErrMsg = "分类异常,不是跨品种分析的图表"
+		return
+	}
+
+	//移动排序
+	updateCol := make([]string, 0)
+	//如果有传入 上一个兄弟节点分类id
+	if req.PrevChartInfoId > 0 {
+		prevChartInfo, err := data_manage.GetChartInfoById(req.PrevChartInfoId)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+			return
+		}
+		if prevChartInfo.ChartClassifyId != chartInfo.ChartClassifyId {
+			br.Msg = "不允许跨分类移动"
+			br.ErrMsg = "不允许跨分类移动"
+			br.IsSendEmail = false
+			return
+		}
+
+		//如果是移动在两个兄弟节点之间
+		if req.NextChartInfoId > 0 {
+			//下一个兄弟节点
+			nextChartInfo, err := data_manage.GetChartInfoById(req.NextChartInfoId)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+				return
+			}
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevChartInfo.Sort == nextChartInfo.Sort || prevChartInfo.Sort == chartInfo.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+				_ = data_manage.UpdateChartInfoSortByClassifyId(prevChartInfo.ChartClassifyId, prevChartInfo.Sort, prevChartInfo.ChartInfoId, []int{chartInfo.Source}, updateSortStr)
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextChartInfo.Sort-prevChartInfo.Sort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+					_ = data_manage.UpdateChartInfoSortByClassifyId(prevChartInfo.ChartClassifyId, prevChartInfo.Sort, prevChartInfo.ChartInfoId, []int{chartInfo.Source}, updateSortStr)
+				}
+			}
+		}
+
+		chartInfo.Sort = prevChartInfo.Sort + 1
+		chartInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+
+	} else {
+		firstClassify, err := data_manage.GetFirstChartInfoByClassifyId(chartInfo.ChartClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+			return
+		}
+
+		if firstClassify != nil && firstClassify.ChartClassifyId != chartInfo.ChartClassifyId {
+			br.Msg = "不允许跨分类移动"
+			br.ErrMsg = "不允许跨分类移动"
+			br.IsSendEmail = false
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstClassify != nil && firstClassify.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = data_manage.UpdateChartInfoSortByClassifyId(firstClassify.ChartClassifyId, 0, firstClassify.ChartInfoId-1, []int{chartInfo.Source}, updateSortStr)
+		}
+
+		chartInfo.Sort = 0 //那就是排在第一位
+		chartInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = chartInfo.Update(updateCol)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "修改失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	if err != nil {
+		br.Msg = "移动失败"
+		br.ErrMsg = "修改失败,Err:" + err.Error()
+		return
+	}
+
+	//添加es数据
+	go data.EsAddOrEditChartInfo(req.ChartInfoId)
+	//修改my eta es数据
+	go data.EsAddOrEditMyChartInfoByChartInfoId(req.ChartInfoId)
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartInfo.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "移动跨品种分析图表"
+		chartLog.Method = c.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "移动成功"
+}
+
+// Refresh
+// @Title 图表刷新接口
+// @Description 图表刷新接口
+// @Param   ChartInfoId   query   int  true       "图表id"
+// @Param   UniqueCode   query   string  true       "唯一code"
+// @Success Ret=200 刷新成功
+// @router /chart_info/refresh [get]
+func (c *ChartInfoController) Refresh() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	chartInfoId, _ := c.GetInt("ChartInfoId")
+	uniqueCode := c.GetString("UniqueCode")
+	if chartInfoId <= 0 && uniqueCode == `` {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误:chartInfoId:" + strconv.Itoa(chartInfoId) + ",UniqueCode:" + uniqueCode
+		return
+	}
+
+	var chartInfo *data_manage.ChartInfo
+	var err error
+	if chartInfoId > 0 {
+		chartInfo, err = data_manage.GetChartInfoById(chartInfoId)
+	} else {
+		chartInfo, err = data_manage.GetChartInfoByUniqueCode(uniqueCode)
+	}
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除,无需刷新"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+		br.Msg = "刷新失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	var config request.ChartConfigReq
+	err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &config)
+	if err != nil {
+		br.Msg = "解析跨品种分析配置失败"
+		br.ErrMsg = "解析跨品种分析配置失败,Err:" + err.Error()
+		return
+	}
+
+	// 获取关联的指标信息
+	_, _, edbInfoIdList, err := cross_variety.GetXYEdbIdList(config.TagX, config.TagY, config.VarietyList)
+	if err != nil {
+		br.Msg = "刷新失败,获取指标信息失败"
+		br.ErrMsg = "刷新失败,获取指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	// 批量刷新
+	err, isAsync := data.EdbInfoRefreshAllFromBaseV3(edbInfoIdList, false, false, false)
+	if err != nil {
+		return
+	}
+
+	//清除图表缓存
+	{
+		key := utils.HZ_CHART_LIB_DETAIL + chartInfo.UniqueCode
+		_ = utils.Rc.Delete(key)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "刷新成功"
+	if isAsync {
+		br.Msg = "图表关联指标较多,请10分钟后刷新页面查看最新数据"
+	}
+}
+
+// EnInfoEdit
+// @Title 编辑图表英文信息接口
+// @Description 编辑图表英文信息接口
+// @Param	request	body data_manage.EditChartEnInfoReq true "type json string"
+// @Success Ret=200 编辑成功
+// @router /chart_info/en/edit [post]
+func (c *ChartInfoController) EnInfoEdit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EditChartEnInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	req.ChartNameEn = strings.Trim(req.ChartNameEn, " ")
+	if req.ChartInfoId <= 0 {
+		br.Msg = "请选择图表"
+		return
+	}
+	if req.ChartNameEn == "" {
+		br.Msg = "请输入英文图表名称"
+		return
+	}
+
+	//判断指标名称是否存在
+	chartItem, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已被删除,请刷新页面"
+			br.ErrMsg = "图表已被删除,请刷新页面"
+			return
+		}
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	// 校验名称是否有重复
+	//{
+	//	var condition string
+	//	var pars []interface{}
+	//	condition += " AND chart_info_id <> ?  AND chart_name_en = ? AND source = ?"
+	//	pars = append(pars, req.ChartInfoId, req.ChartNameEn, utils.CHART_SOURCE_CROSS_HEDGING)
+	//	existItem, err := data_manage.GetChartInfoByCondition(condition, pars)
+	//	if err != nil {
+	//		if err.Error() != utils.ErrNoRow() {
+	//			br.Msg = "判断英文图表名称是否存在失败"
+	//			br.ErrMsg = "判断英文图表名称是否存在失败,Err:" + err.Error()
+	//			return
+	//		}
+	//	}
+	//	if err == nil && existItem.ChartInfoId > 0 {
+	//		br.Msg = existItem.ChartName + ":" + req.ChartNameEn + "图表名称已存在"
+	//		return
+	//	}
+	//}
+
+	chartItem.ChartNameEn = req.ChartNameEn
+	chartItem.ModifyTime = time.Now().Local()
+	if e := chartItem.Update([]string{"ChartNameEn", "ModifyTime"}); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新图表信息失败, Err: " + e.Error()
+		return
+	}
+
+	err = cross_varietyModels.EditChartEn(chartItem, req)
+	if err != nil {
+		br.Msg = "修改失败"
+		br.ErrMsg = "更新图表英文信息失败, Err: " + err.Error()
+		return
+	}
+
+	//添加es数据
+	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
+	//修改my eta es数据
+	go data.EsAddOrEditMyChartInfoByChartInfoId(chartItem.ChartInfoId)
+
+	//指标 修改es信息
+	//go data.AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "编辑跨品种分析图表英文信息"
+		chartLog.Method = c.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+	// 清除缓存
+	if utils.Re == nil && utils.Rc != nil {
+		_ = utils.Rc.Delete(utils.HZ_CHART_LIB_DETAIL + chartItem.UniqueCode) //图表分享链接缓存
+		_ = utils.Rc.Delete(data.GetChartInfoDataKey(req.ChartInfoId))
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+	br.IsAddLog = true
+}
+
+// DeleteChart
+// @Title 删除跨品种分析分类/图表
+// @Description 删除跨品种分析分类/图表接口
+// @Param	request	body data_manage.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /chart_info/delete [post]
+func (c *ChartInfoController) DeleteChart() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.DeleteChartClassifyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId <= 0 {
+		br.Msg = "请选择图表"
+		br.IsSendEmail = false
+		return
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	//删除图表
+	chartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "图表已删除,请刷新页面"
+			br.ErrMsg = "指标不存在,Err:" + err.Error()
+			return
+		} else {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,获取指标信息失败,Err:" + err.Error()
+			return
+		}
+	}
+	if chartInfo == nil {
+		br.Msg = "图表已删除,请刷新页面"
+		return
+	}
+	//图表操作权限
+	ok := data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+	if !ok {
+		br.Msg = "没有该图表的操作权限"
+		br.ErrMsg = "没有该图表的操作权限"
+		return
+	}
+
+	myIds := make([]int, 0)
+	{
+		// 获取引用该图表的MyCharts, 用于ES删除
+		var myCond string
+		var myPars []interface{}
+		myCond += ` AND a.chart_info_id = ? `
+		myPars = append(myPars, req.ChartInfoId)
+		myCharts, e := data_manage.GetMyChartListGroupByCharyInfoIdAndAdminIdByCondition(myCond, myPars)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取引用图表的MyChats失败, Err: " + e.Error()
+			return
+		}
+		for _, m := range myCharts {
+			myIds = append(myIds, m.MyChartId)
+		}
+	}
+	//删除图表及关联指标
+	err = data_manage.DeleteChartInfoAndData(chartInfo.ChartInfoId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+	//删除ES
+	{
+		go data.EsDeleteChartInfo(chartInfo.ChartInfoId)
+		// 删除MY ETA 图表 es数据
+		go data.EsDeleteMyChartInfoByMyChartIds(myIds)
+	}
+
+	source := chartInfo.Source // 跨品种分析
+	var condition string
+	var pars []interface{}
+	condition += " AND chart_classify_id=? AND source = ? "
+	pars = append(pars, chartInfo.ChartClassifyId, source)
+
+	condition += " AND chart_info_id>? ORDER BY create_time ASC LIMIT 1 "
+	pars = append(pars, req.ChartInfoId)
+
+	nextItem, err := data_manage.GetChartInfoByCondition(condition, pars)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "删除失败"
+		br.ErrMsg = "获取下一级图库信息失败,Err:" + err.Error()
+		return
+	}
+
+	if nextItem != nil {
+		resp.UniqueCode = nextItem.UniqueCode
+		resp.ChartInfoId = nextItem.ChartInfoId
+	} else {
+		var tmpCondition string
+		var tmpPars []interface{}
+
+		tmpCondition += " AND level=1 "
+		//pars = append(pars, chartInfo.ChartClassifyId)
+
+		tmpCondition += " AND chart_classify_id>? ORDER BY chart_classify_id ASC LIMIT 1 "
+		tmpPars = append(tmpPars, chartInfo.ChartClassifyId)
+
+		classifyItem, err := data_manage.GetChartClassifyByCondition(tmpCondition, tmpPars)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取下一级图库分类信息失败,Err:" + err.Error()
+			return
+		}
+		if classifyItem != nil {
+			nextItem, err = data_manage.GetNextChartInfo(chartInfo.ChartClassifyId)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "删除失败"
+				br.ErrMsg = "获取下一级图库信息失败,Err:" + err.Error()
+				return
+			}
+			if nextItem != nil {
+				resp.UniqueCode = nextItem.UniqueCode
+				resp.ChartInfoId = nextItem.ChartInfoId
+			}
+		}
+	}
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartInfo.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "删除图表"
+		chartLog.Method = c.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// SearchByEs
+// @Title 图表模糊搜索(从es获取)
+// @Description  图表模糊搜索(从es获取)
+// @Param   Keyword   query   string  true       "图表名称"
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Param   Source   query   int  true       "来源,3:拟合方程,4:滚动拟合方程,默认0:全部"
+// @Success 200 {object} data_manage.ChartInfo
+// @router /chart_info/search_by_es [get]
+func (c *ChartInfoController) SearchByEs() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	keyword := c.GetString("Keyword")
+
+	//只看我的
+	isShowMe, _ := c.GetBool("IsShowMe")
+	showSysId := 0
+	if isShowMe {
+		showSysId = sysUser.AdminId
+	}
+
+	sourceList := []int{utils.CHART_SOURCE_CROSS_HEDGING}
+
+	var searchList []*data_manage.ChartInfo
+	var total int64
+	var err error
+
+	// 获取当前账号的不可见指标
+	noPermissionChartIdList := make([]int, 0)
+	{
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllChartListByAdminId(c.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range confList {
+			noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
+		}
+	}
+
+	if keyword != "" {
+		searchList, total, err = data.EsSearchChartInfo(keyword, showSysId, sourceList, noPermissionChartIdList, startSize, pageSize)
+	} else {
+		total, searchList, err = data_manage.ChartInfoSearchByEmptyKeyWord(showSysId, sourceList, noPermissionChartIdList, startSize, pageSize)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	finalList := make([]*data_manage.ChartInfoMore, 0)
+	if len(searchList) > 0 {
+		chartInfoIds := ""
+		chartEdbMap := make(map[int][]*data_manage.ChartEdbInfoMapping)
+		for _, v := range searchList {
+			chartInfoIds += strconv.Itoa(v.ChartInfoId) + ","
+		}
+		if chartInfoIds != "" {
+			chartInfoIds = strings.Trim(chartInfoIds, ",")
+			//判断是否需要展示英文标识
+			edbList, e := data_manage.GetChartEdbMappingListByChartInfoIds(chartInfoIds)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取图表,指标信息失败,Err:" + e.Error()
+				return
+			}
+			for _, v := range edbList {
+				chartEdbMap[v.ChartInfoId] = append(chartEdbMap[v.ChartInfoId], v)
+			}
+		}
+
+		for _, v := range searchList {
+			tmp := new(data_manage.ChartInfoMore)
+			tmp.ChartInfo = *v
+			//判断是否需要展示英文标识
+			if _, ok := chartEdbMap[v.ChartInfoId]; ok {
+				tmp.IsEnChart = data.CheckIsEnChart(v.ChartNameEn, []*data_manage.ChartEdbInfoMapping{}, v.Source, v.ChartType)
+			}
+			finalList = append(finalList, tmp)
+		}
+	}
+	//新增搜索词记录
+	{
+		searchKeyword := new(data_manage.SearchKeyword)
+		searchKeyword.KeyWord = keyword
+		searchKeyword.CreateTime = time.Now()
+		go data_manage.AddSearchKeyword(searchKeyword)
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, int(total))
+	resp := data_manage.ChartInfoListByEsResp{
+		Paging: page,
+		List:   finalList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// GetChartInfoDetailFromUniqueCode 根据编码获取图表详情
+func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	resp = new(data_manage.ChartInfoDetailFromUniqueCodeResp)
+
+	adminId := sysUser.AdminId
+
+	//判断是否存在缓存,如果存在缓存,那么直接从缓存中获取
+	key := data.GetChartInfoDataKey(chartInfo.ChartInfoId)
+	if utils.Re == nil && isCache {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if chartData, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err := json.Unmarshal(chartData, &resp)
+				if err == nil && resp != nil {
+					// 这里跟当前用户相关的信息重新查询写入resp, 不使用缓存中的
+					var myCond string
+					var myPars []interface{}
+					myCond += ` AND a.admin_id=? `
+					myPars = append(myPars, adminId)
+					myCond += ` AND a.chart_info_id=? `
+					myPars = append(myPars, chartInfo.ChartInfoId)
+					myList, err := data_manage.GetMyChartByCondition(myCond, myPars)
+					if err != nil && err.Error() != utils.ErrNoRow() {
+						msg = "获取失败"
+						errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+						return
+					}
+					resp.ChartInfo.IsAdd = false
+					resp.ChartInfo.MyChartId = 0
+					resp.ChartInfo.MyChartClassifyId = ""
+					if myList != nil && len(myList) > 0 {
+						resp.ChartInfo.IsAdd = true
+						resp.ChartInfo.MyChartId = myList[0].MyChartId
+						resp.ChartInfo.MyChartClassifyId = myList[0].MyChartClassifyId
+					}
+
+					isOk = true
+					fmt.Println("source redis")
+					return
+				}
+			}
+		}
+	}
+
+	chartInfoId := chartInfo.ChartInfoId
+
+	if chartInfo.ExtraConfig == `` {
+		msg = "图表配置信息异常"
+		errMsg = "图表配置信息异常"
+		return
+	}
+	var config request.ChartConfigReq
+	err := json.Unmarshal([]byte(chartInfo.ExtraConfig), &config)
+	if err != nil {
+		msg = "解析跨品种分析配置失败"
+		errMsg = "解析跨品种分析配置失败,Err:" + err.Error()
+		return
+	}
+	// 获取图表x轴y轴
+	edbList, dataResp, err, msg, _ := cross_variety.GetChartData(0, config)
+	if err != nil {
+		errMsg = "获取图表,指标信息失败,Err:" + err.Error()
+		return
+	}
+	if chartInfoId > 0 && chartInfo != nil {
+		//判断是否加入我的图库
+		{
+			var myChartCondition string
+			var myChartPars []interface{}
+			myChartCondition += ` AND a.admin_id=? `
+			myChartPars = append(myChartPars, sysUser.AdminId)
+			myChartCondition += ` AND a.chart_info_id=? `
+			myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+			myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				msg = "获取失败"
+				errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+				return
+			}
+			if myChartList != nil && len(myChartList) > 0 {
+				chartInfo.IsAdd = true
+				chartInfo.MyChartId = myChartList[0].MyChartId
+				chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+			}
+		}
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+	//判断是否需要展示英文标识
+	//chartInfo.IsEnChart = data.CheckIsEnChart(chartInfo.ChartNameEn, edbList[0:1], chartInfo.Source, chartInfo.ChartType)
+	//chartInfo.UnitEn = edbInfoMappingA.UnitEn
+
+	//isSaveAs := true
+	// 另存为
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp.ChartInfo = chartInfo
+	resp.DataResp = dataResp
+	resp.EdbInfoList = edbList
+	resp.Status = true
+
+	// 将数据加入缓存
+	if utils.Re == nil {
+		d, _ := json.Marshal(resp)
+		_ = utils.Rc.Put(key, d, 2*time.Hour)
+	}
+	isOk = true
+	return
+}

+ 554 - 0
controllers/data_manage/cross_variety/classify.go

@@ -0,0 +1,554 @@
+package cross_variety
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/services/data"
+	"eta/eta_api/utils"
+	"time"
+)
+
+// ClassifyController
+// @Description: 跨品种分析分类
+type ClassifyController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 跨品种分析分类列表
+// @Description 跨品种分析分类列表接口
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Param   Source   query   int  true       "图表类型,3:跨品种分析,4:滚动跨品种分析"
+// @Success 200 {object} data_manage.ChartClassifyListResp
+// @router /classify/list [get]
+func (c *ClassifyController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	resp := new(data_manage.ChartClassifyListResp)
+
+	// 获取当前账号的不可见指标
+	noPermissionChartIdMap := make(map[int]bool)
+	{
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllChartListByAdminId(c.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range confList {
+			noPermissionChartIdMap[v.ChartInfoId] = true
+		}
+	}
+
+	isShowMe, _ := c.GetBool("IsShowMe")
+
+	source, _ := c.GetInt("Source")
+	if source <= 0 {
+		source = utils.CHART_SOURCE_CROSS_HEDGING
+	}
+
+	rootList, err := data_manage.GetChartClassifyByParentId(0, utils.CHART_SOURCE_CROSS_HEDGING)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	allChartInfo, err := data_manage.GetChartInfoAll([]int{source})
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	chartInfoMap := make(map[int][]*data_manage.ChartClassifyItems)
+	for _, v := range allChartInfo {
+		if !isShowMe {
+			chartInfoMap[v.ChartClassifyId] = append(chartInfoMap[v.ChartClassifyId], v)
+			continue
+		}
+		if v.SysUserId != c.SysUser.AdminId {
+			continue
+		}
+		chartInfoMap[v.ChartClassifyId] = append(chartInfoMap[v.ChartClassifyId], v)
+	}
+	rootChildMap := make(map[int][]*data_manage.ChartClassifyItems)
+
+	// 移除没有图表的分类
+	allNodes := make([]*data_manage.ChartClassifyItems, 0)
+	for _, v := range rootList {
+		if v.SysUserId == c.SysUser.AdminId || c.SysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN {
+			v.Button.OpButton = true
+		}
+
+		rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
+		if existItems, ok := chartInfoMap[v.ChartClassifyId]; ok {
+			v.Children = existItems
+			allNodes = append(allNodes, v)
+		}
+	}
+
+	// 移除没有权限的图表
+	allNodes = data.HandleNoPermissionChart(allNodes, noPermissionChartIdMap)
+	resp.AllNodes = allNodes
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EditChartClassify
+// @Title 修改跨品种分析图表分类
+// @Description 修改跨品种分析图表分类接口
+// @Param	request	body data_manage.EditChartClassifyReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /classify/edit [post]
+func (c *ClassifyController) EditChartClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req data_manage.EditChartClassifyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ChartClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.ChartClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	item, err := data_manage.GetChartClassifyById(req.ChartClassifyId)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.Msg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+
+	source := utils.CHART_SOURCE_CROSS_HEDGING
+	if item.ChartClassifyName != req.ChartClassifyName {
+		//count, err := data_manage.GetChartClassifyCount(req.ChartClassifyName, item.ParentId, source)
+		//if err != nil {
+		//	br.Msg = "判断名称是否已存在失败"
+		//	br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+		//	return
+		//}
+		//if count > 0 {
+		//	br.Msg = "分类名称已存在,请重新输入"
+		//	br.IsSendEmail = false
+		//	return
+		//}
+
+		err = data_manage.EditChartClassify(req.ChartClassifyId, source, req.ChartClassifyName)
+		if err != nil {
+			br.Msg = "保存失败"
+			br.ErrMsg = "保存失败,Err:" + err.Error()
+			return
+		}
+	}
+	br.Ret = 200
+	br.Msg = "修改成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// DeleteChartClassifyCheck
+// @Title 删除图表检测接口
+// @Description 删除图表检测接口
+// @Param	request	body data_manage.ChartClassifyDeleteCheckResp true "type json string"
+// @Success 200 Ret=200 检测成功
+// @router /classify/delete/check [post]
+func (c *ClassifyController) DeleteChartClassifyCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req data_manage.ChartClassifyDeleteCheckReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartClassifyId < 0 && req.ChartInfoId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+	var deleteStatus int
+	var tipsMsg string
+	//删除分类
+	if req.ChartClassifyId > 0 && req.ChartInfoId == 0 {
+		//判断跨品种分析图表分类下,是否含有图表
+		count, err := data_manage.GetChartInfoCountByClassifyId(req.ChartClassifyId)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有图表失败,Err:" + err.Error()
+			return
+		}
+
+		if count > 0 {
+			deleteStatus = 1
+			tipsMsg = "该分类下关联图表不可删除"
+		}
+	}
+
+	if deleteStatus != 1 && req.ChartInfoId == 0 {
+		classifyCount, err := data_manage.GetChartClassifyCountByClassifyId(req.ChartClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有图表失败,Err:" + err.Error()
+			return
+		}
+		if classifyCount > 0 {
+			deleteStatus = 2
+			tipsMsg = "确认删除当前目录及包含的子目录吗"
+		}
+	}
+	if deleteStatus == 0 {
+		tipsMsg = "可删除,进行删除操作"
+	}
+
+	resp := new(data_manage.ChartClassifyDeleteCheckResp)
+	resp.DeleteStatus = deleteStatus
+	resp.TipsMsg = tipsMsg
+	br.Ret = 200
+	br.Msg = "检测成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// DeleteChartClassify
+// @Title 删除跨品种分析图表分类/图表
+// @Description 删除跨品种分析图表分类/图表接口
+// @Param	request	body data_manage.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /classify/delete [post]
+func (c *ClassifyController) DeleteChartClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.DeleteChartClassifyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartClassifyId < 0 && req.ChartInfoId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	//删除分类
+	if req.ChartClassifyId > 0 && req.ChartInfoId == 0 {
+		//判断是否含有指标
+		count, err := data_manage.GetChartInfoCountByClassifyId(req.ChartClassifyId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+			return
+		}
+
+		if count > 0 {
+			br.Msg = "该目录下存在关联指标,不可删除"
+			br.IsSendEmail = false
+			return
+		}
+
+		err = data_manage.DeleteChartClassify(req.ChartClassifyId)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,Err:" + err.Error()
+			return
+		}
+	}
+	resp := new(data_manage.AddChartInfoResp)
+	//删除图表
+	if req.ChartInfoId > 0 {
+		chartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "图表已删除,请刷新页面"
+				br.ErrMsg = "指标不存在,Err:" + err.Error()
+				return
+			} else {
+				br.Msg = "删除失败"
+				br.ErrMsg = "删除失败,获取指标信息失败,Err:" + err.Error()
+				return
+			}
+		}
+		if chartInfo == nil {
+			br.Msg = "图表已删除,请刷新页面"
+			return
+		}
+		//图表操作权限
+		ok := data.CheckOpChartPermission(sysUser, chartInfo.SysUserId)
+		if !ok {
+			br.Msg = "没有该图表的操作权限"
+			br.ErrMsg = "没有该图表的操作权限"
+			return
+		}
+
+		// 获取引用该图表的MyCharts, 用于ES删除
+		var myCond string
+		var myPars []interface{}
+		myCond += ` AND a.chart_info_id = ? `
+		myPars = append(myPars, chartInfo.ChartInfoId)
+		myCharts, e := data_manage.GetMyChartListGroupByCharyInfoIdAndAdminIdByCondition(myCond, myPars)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取引用图表的MyChats失败, Err: " + e.Error()
+			return
+		}
+		myIds := make([]int, 0)
+		for _, m := range myCharts {
+			myIds = append(myIds, m.MyChartId)
+		}
+
+		source := chartInfo.Source // 跨品种分析图表(滚动跨品种分析)
+		//删除图表及关联指标
+		err = data_manage.DeleteChartInfoAndData(chartInfo.ChartInfoId)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,Err:" + err.Error()
+			return
+		}
+		//删除ES
+		{
+			go data.EsDeleteChartInfo(chartInfo.ChartInfoId)
+			// 删除MY ETA 图表 es数据
+			//go data.EsDeleteMyChartInfoByChartInfoId(chartInfo.ChartInfoId)
+			go data.EsDeleteMyChartInfoByMyChartIds(myIds)
+		}
+
+		var condition string
+		var pars []interface{}
+		condition += " AND chart_classify_id=? AND source = ? "
+		pars = append(pars, chartInfo.ChartClassifyId, source)
+
+		condition += " AND chart_info_id>? ORDER BY create_time ASC LIMIT 1 "
+		pars = append(pars, req.ChartInfoId)
+
+		nextItem, err := data_manage.GetChartInfoByCondition(condition, pars)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取下一级图库信息失败,Err:" + err.Error()
+			return
+		}
+
+		if nextItem != nil {
+			resp.UniqueCode = nextItem.UniqueCode
+			resp.ChartInfoId = nextItem.ChartInfoId
+		} else {
+			var condition string
+			var pars []interface{}
+
+			condition += " AND level=1 "
+			//pars = append(pars, chartInfo.ChartClassifyId)
+
+			condition += " AND chart_classify_id>? ORDER BY chart_classify_id ASC LIMIT 1 "
+			pars = append(pars, chartInfo.ChartClassifyId)
+
+			classifyItem, err := data_manage.GetChartClassifyByCondition(condition, pars)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "删除失败"
+				br.ErrMsg = "获取下一级图库分类信息失败,Err:" + err.Error()
+				return
+			}
+			if classifyItem != nil {
+				nextItem, err = data_manage.GetNextChartInfo(chartInfo.ChartClassifyId)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "删除失败"
+					br.ErrMsg = "获取下一级图库信息失败,Err:" + err.Error()
+					return
+				}
+				if nextItem != nil {
+					resp.UniqueCode = nextItem.UniqueCode
+					resp.ChartInfoId = nextItem.ChartInfoId
+				}
+			}
+		}
+		//新增操作日志
+		{
+			chartLog := new(data_manage.ChartInfoLog)
+			chartLog.ChartName = chartInfo.ChartName
+			chartLog.ChartInfoId = req.ChartInfoId
+			chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+			chartLog.SysUserId = sysUser.AdminId
+			chartLog.SysUserRealName = sysUser.RealName
+			chartLog.UniqueCode = chartInfo.UniqueCode
+			chartLog.CreateTime = time.Now()
+			chartLog.Content = string(c.Ctx.Input.RequestBody)
+			chartLog.Status = "删除图表"
+			chartLog.Method = c.Ctx.Input.URI()
+			go data_manage.AddChartInfoLog(chartLog)
+		}
+	}
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// ChartClassifyMove
+// @Title 相关性图表分类移动接口
+// @Description 相关性图表分类移动接口
+// @Success 200 {object} data_manage.MoveChartClassifyReq
+// @router /classify/move [post]
+func (c *ClassifyController) ChartClassifyMove() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.MoveChartClassifyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "分类id小于等于0"
+		return
+	}
+	//判断分类是否存在
+	chartClassifyInfo, err := data_manage.GetChartClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "移动失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	if chartClassifyInfo.Source != utils.CHART_SOURCE_CROSS_HEDGING {
+		br.Msg = "分类异常"
+		br.ErrMsg = "分类异常,不是跨品种分析图表的分类"
+		return
+	}
+	updateCol := make([]string, 0)
+
+	//如果有传入 上一个兄弟节点分类id
+	if req.PrevClassifyId > 0 {
+		//上一个兄弟节点
+		prevClassify, err := data_manage.GetChartClassifyById(req.PrevClassifyId)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+			return
+		}
+		if prevClassify.Source != utils.CHART_SOURCE_CROSS_HEDGING {
+			br.Msg = "上级节点分类异常"
+			br.ErrMsg = "上级节点分类异常,不是跨品种分析图表的分类"
+			return
+		}
+
+		//如果是移动在两个兄弟节点之间
+		if req.NextClassifyId > 0 {
+			//下一个兄弟节点
+			nextClassify, err := data_manage.GetChartClassifyById(req.NextClassifyId)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+				return
+			}
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == chartClassifyInfo.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+				_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, prevClassify.ChartClassifyId, prevClassify.Sort, updateSortStr)
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextClassify.Sort-prevClassify.Sort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+					_ = data_manage.UpdateChartClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
+				}
+			}
+		}
+
+		chartClassifyInfo.Sort = prevClassify.Sort + 1
+		chartClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+
+	} else {
+		firstClassify, err := data_manage.GetFirstChartClassifyByParentIdAndSource(chartClassifyInfo.ParentId, chartClassifyInfo.Source)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取跨品种分析图表分类排序第一条的分类信息失败,Err:" + err.Error()
+			return
+		}
+		if firstClassify != nil && firstClassify.Source != utils.CHART_SOURCE_CROSS_HEDGING {
+			br.Msg = "上级节点分类异常"
+			br.ErrMsg = "上级节点分类异常,不是跨品种分析图表的分类"
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstClassify != nil && firstClassify.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = data_manage.UpdateChartClassifySortByParentId(firstClassify.ParentId, firstClassify.ChartClassifyId-1, 0, updateSortStr)
+		}
+
+		chartClassifyInfo.Sort = 0 //那就是排在第一位
+		chartClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = chartClassifyInfo.Update(updateCol)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "修改失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "移动成功"
+}

+ 408 - 0
controllers/data_manage/cross_variety/tag.go

@@ -0,0 +1,408 @@
+package cross_variety
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage/cross_variety"
+	"eta/eta_api/models/data_manage/cross_variety/request"
+	"eta/eta_api/models/data_manage/cross_variety/response"
+	cross_varietyService "eta/eta_api/services/data/cross_variety"
+	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+// TagController
+// @Description: 标签列表
+type TagController struct {
+	controllers.BaseAuthController
+}
+
+// Add
+// @Title 新增标签
+// @Description 新增标签接口
+// @Param	request	body request.AddTagReq true "type json string"
+// @Success 200 Ret=200 添加成功
+// @router /tag/add [post]
+func (c *TagController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.AddTagReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.TagName == "" {
+		br.Msg = "请输入标签名称"
+		br.IsSendEmail = false
+		return
+	}
+	TagName := utils.TrimStr(req.TagName)
+	item, err := cross_variety.GetTagByName(TagName)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		return
+	}
+	if item != nil {
+		br.Msg = "添加失败,标签名称不能重复"
+		br.IsSendEmail = false
+		return
+	}
+
+	tag := &cross_variety.ChartTag{
+		ChartTagId:      0,
+		ChartTagName:    TagName,
+		SysUserId:       c.SysUser.AdminId,
+		SysUserRealName: c.SysUser.RealName,
+		ModifyTime:      time.Now(),
+		CreateTime:      time.Now(),
+	}
+	err = cross_variety.AddTag(tag)
+	if err != nil {
+		br.Msg = "添加标签失败"
+		br.ErrMsg = "添加标签失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "添加成功"
+	br.IsAddLog = true
+	br.Success = true
+}
+
+// Edit
+// @Title 编辑标签接口
+// @Description 编辑标签接口
+// @Param	request	body request.EditTagReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /tag/edit [post]
+func (c *TagController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.EditTagReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ChartTagId <= 0 {
+		br.Msg = "请选择标签"
+		br.IsSendEmail = false
+		return
+	}
+	if req.TagName == "" {
+		br.Msg = "请输入标签名称"
+		br.IsSendEmail = false
+		return
+	}
+	TagName := utils.TrimStr(req.TagName)
+
+	item, err := cross_variety.GetTagByName(TagName)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		return
+	}
+	if item != nil && item.ChartTagId != req.ChartTagId {
+		br.Msg = "添加失败,标签名称不能重复"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取标签详情
+	varietyInfo, err := cross_variety.GetTagById(req.ChartTagId)
+	if err != nil {
+		br.Msg = "查询标签失败"
+		br.ErrMsg = "查询标签失败;ERR:" + err.Error()
+		return
+	}
+
+	// 编辑
+	varietyInfo.ChartTagName = TagName
+	varietyInfo.ModifyTime = time.Now()
+	err = varietyInfo.Update([]string{"ChartTagName", "ModifyTime"})
+	if err != nil {
+		br.Msg = "修改标签失败"
+		br.ErrMsg = "修改标签失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "修改成功"
+	br.IsAddLog = true
+	br.Success = true
+}
+
+// DeleteCheck
+// @Title 删除标签检测接口
+// @Description 删除标签检测接口
+// @Param	request	body request.DelTagReq true "type json string"
+// @Success 200 Ret=200 检测成功
+// @router /tag/delete/check [post]
+func (c *TagController) DeleteCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelTagReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartTagId <= 0 {
+		br.Msg = "请选择标签"
+		br.IsSendEmail = false
+		return
+	}
+	var deleteStatus int
+	var tipsMsg string
+
+	// 获取该标签关联的图表数
+	count, err := cross_variety.GetCountChartByTagId(req.ChartTagId)
+	if err != nil {
+		br.Msg = "检测异常"
+		br.ErrMsg = "检测异常,err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	if count > 0 {
+		deleteStatus = 1
+		tipsMsg = "已关联图表的品种,不允许删除!"
+	}
+
+	if deleteStatus == 0 {
+		tipsMsg = "可删除,进行删除操作"
+	}
+
+	resp := response.TagDeleteCheckResp{
+		DeleteStatus: deleteStatus,
+		TipsMsg:      tipsMsg,
+	}
+	br.Ret = 200
+	br.Msg = "检测成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// Delete
+// @Title 删除标签
+// @Description 删除标签接口
+// @Param	request	body request.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /tag/delete [post]
+func (c *TagController) Delete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelTagReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartTagId <= 0 {
+		br.Msg = "请选择标签"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取该标签关联的图表数
+	count, err := cross_variety.GetCountChartByTagId(req.ChartTagId)
+	if err != nil {
+		br.Msg = "检测异常"
+		br.ErrMsg = "检测异常,err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	if count > 0 {
+		br.Msg = "已关联图表的品种,不允许删除!"
+		br.ErrMsg = "已关联图表的品种,不允许删除!"
+		br.IsSendEmail = false
+		return
+	}
+
+	varietyInfo, err := cross_variety.GetTagById(req.ChartTagId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "该标签不存在或已删除"
+			br.IsSendEmail = false
+		} else {
+			br.Msg = "删除失败"
+			br.ErrMsg = "查找标签失败,ERR:" + err.Error()
+		}
+		return
+	}
+	err = varietyInfo.Delete()
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除标签失败,ERR:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// List
+// @Title 获取标签中的指标与品种的映射关系
+// @Description 获取标签中的指标与品种的映射关系
+// @Param   ChartTagId   query   int  true       "标签id"
+// @Success 200 Ret=200 保存成功
+// @router /tag/list [get]
+func (c *TagController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	// 获取数据
+	list, err := cross_variety.GetTagItemList()
+	if err != nil {
+		br.Msg = "获取标签失败"
+		br.ErrMsg = "获取标签失败,ERR:" + err.Error()
+		return
+	}
+	dataCount := len(list)
+	page := paging.GetPaging(1, dataCount, dataCount)
+
+	// 获取标签绑定的品种数量
+	tagTotalList, err := cross_variety.GetCountChartTagVarietyItemListByTag()
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取标签绑定的品种数量失败,ERR:" + err.Error()
+		return
+	}
+
+	tagTotalMap := make(map[int]int)
+	for _, v := range tagTotalList {
+		tagTotalMap[v.ChartTagId] = v.Total
+	}
+
+	for k, v := range list {
+		list[k].VarietyTotal = tagTotalMap[v.ChartTagId]
+	}
+
+	resp := response.TagListResp{
+		List:   list,
+		Paging: page,
+	}
+
+	br.Ret = 200
+	br.Msg = "获取成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// VarietyEdbList
+// @Title 获取标签中的指标与品种的映射关系
+// @Description 获取标签中的指标与品种的映射关系
+// @Param   ChartTagId   query   int  true       "标签id"
+// @Success 200 Ret=200 保存成功
+// @router /tag/variety_edb/list [get]
+func (c *TagController) VarietyEdbList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	chartTagId, _ := c.GetInt("ChartTagId")
+	if chartTagId <= 0 {
+		br.Msg = "请选择标签"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取数据
+	list, err := cross_variety.GetChartTagVarietyItemListByTag(chartTagId)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,ERR:" + err.Error()
+		return
+	}
+	dataCount := len(list)
+	page := paging.GetPaging(1, dataCount, dataCount)
+
+	resp := response.VarietyEdbListResp{
+		List:   list,
+		Paging: page,
+	}
+
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// SaveVarietyEdb
+// @Title 配置标签中的指标与品种的映射关系
+// @Description 配置标签中的指标与品种的映射关系
+// @Param	request	body request.SaveTagVarietyEdbReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /tag/variety_edb/save [post]
+func (c *TagController) SaveVarietyEdb() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.SaveTagVarietyEdbReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartTagId <= 0 {
+		br.Msg = "请选择标签"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 过滤未配置的品种
+	varietyEdbList := make([]request.VarietyEdbReq, 0)
+	for _, v := range req.VarietyEdb {
+		if v.EdbInfoId <= 0 {
+			continue
+		}
+		varietyEdbList = append(varietyEdbList, v)
+	}
+
+	// 保存配置
+	err = cross_variety.SaveVarietyEdb(req.ChartTagId, varietyEdbList, c.SysUser.AdminId, c.SysUser.RealName)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,ERR:" + err.Error()
+		return
+	}
+
+	// 修改跨品种分析图表的关联指标
+	go cross_varietyService.ModifyChartEdbMapping(req.ChartTagId)
+
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+	br.IsAddLog = true
+}

+ 295 - 0
controllers/data_manage/cross_variety/variety.go

@@ -0,0 +1,295 @@
+package cross_variety
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage/cross_variety"
+	"eta/eta_api/models/data_manage/cross_variety/request"
+	"eta/eta_api/models/data_manage/cross_variety/response"
+	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+// VarietyController
+// @Description: 品种列表
+type VarietyController struct {
+	controllers.BaseAuthController
+}
+
+// Add
+// @Title 新增品种
+// @Description 新增品种接口
+// @Param	request	body request.AddVarietyReq true "type json string"
+// @Success 200 Ret=200 添加成功
+// @router /variety/add [post]
+func (c *VarietyController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.AddVarietyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.VarietyName == "" {
+		br.Msg = "请输入品种名称"
+		br.IsSendEmail = false
+		return
+	}
+	varietyName := utils.TrimStr(req.VarietyName)
+	item, err := cross_variety.GetVarietyByName(varietyName)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		return
+	}
+	if item != nil {
+		br.Msg = "添加失败,品种名称不能重复"
+		br.IsSendEmail = false
+		return
+	}
+
+	variety := &cross_variety.ChartVariety{
+		ChartVarietyId:   0,
+		ChartVarietyName: varietyName,
+		SysUserId:        c.SysUser.AdminId,
+		SysUserRealName:  c.SysUser.RealName,
+		ModifyTime:       time.Now(),
+		CreateTime:       time.Now(),
+	}
+	err = cross_variety.AddVariety(variety)
+	if err != nil {
+		br.Msg = "添加品种失败"
+		br.ErrMsg = "添加品种失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "添加成功"
+	br.IsAddLog = true
+	br.Success = true
+}
+
+// Edit
+// @Title 编辑品种接口
+// @Description 编辑品种接口
+// @Param	request	body request.EditVarietyReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /variety/edit [post]
+func (c *VarietyController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.EditVarietyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ChartVarietyId <= 0 {
+		br.Msg = "请选择品种"
+		br.IsSendEmail = false
+		return
+	}
+	if req.VarietyName == "" {
+		br.Msg = "请输入品种名称"
+		br.IsSendEmail = false
+		return
+	}
+	varietyName := utils.TrimStr(req.VarietyName)
+
+	item, err := cross_variety.GetVarietyByName(varietyName)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		return
+	}
+	if item != nil && item.ChartVarietyId != req.ChartVarietyId {
+		br.Msg = "添加失败,品种名称不能重复"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取品种详情
+	varietyInfo, err := cross_variety.GetVarietyById(req.ChartVarietyId)
+	if err != nil {
+		br.Msg = "查询品种失败"
+		br.ErrMsg = "查询品种失败;ERR:" + err.Error()
+		return
+	}
+
+	// 编辑
+	varietyInfo.ChartVarietyName = varietyName
+	varietyInfo.ModifyTime = time.Now()
+	err = varietyInfo.Update([]string{"ChartVarietyName", "ModifyTime"})
+	if err != nil {
+		br.Msg = "修改品种失败"
+		br.ErrMsg = "修改品种失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "修改成功"
+	br.IsAddLog = true
+	br.Success = true
+}
+
+// DeleteCheck
+// @Title 删除品种检测接口
+// @Description 删除品种检测接口
+// @Param	request	body request.DelVarietyReq true "type json string"
+// @Success 200 Ret=200 检测成功
+// @router /variety/delete/check [post]
+func (c *VarietyController) DeleteCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelVarietyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartVarietyId <= 0 {
+		br.Msg = "请选择品种"
+		br.IsSendEmail = false
+		return
+	}
+	var deleteStatus int
+	var tipsMsg string
+
+	// 获取该品种关联的图表数
+	count, err := cross_variety.GetCountChartByVarietyId(req.ChartVarietyId)
+	if err != nil {
+		br.Msg = "检测异常"
+		br.ErrMsg = "检测异常,err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	if count > 0 {
+		deleteStatus = 1
+		tipsMsg = "已关联图表的品种,不允许删除!"
+	}
+
+	if deleteStatus == 0 {
+		tipsMsg = "可删除,进行删除操作"
+	}
+	resp := response.VarietyDeleteCheckResp{
+		DeleteStatus: deleteStatus,
+		TipsMsg:      tipsMsg,
+	}
+	br.Ret = 200
+	br.Msg = "检测成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// Delete
+// @Title 删除品种
+// @Description 删除品种接口
+// @Param	request	body request.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /variety/delete [post]
+func (c *VarietyController) Delete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	var req request.DelVarietyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartVarietyId <= 0 {
+		br.Msg = "请选择品种"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取该品种关联的图表数
+	count, err := cross_variety.GetCountChartByVarietyId(req.ChartVarietyId)
+	if err != nil {
+		br.Msg = "检测异常"
+		br.ErrMsg = "检测异常,err:" + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	if count > 0 {
+		br.Msg = "已关联图表的品种,不允许删除!"
+		br.ErrMsg = "已关联图表的品种,不允许删除!"
+		br.IsSendEmail = false
+		return
+	}
+
+	varietyInfo, err := cross_variety.GetVarietyById(req.ChartVarietyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "该品种不存在或已删除"
+			br.IsSendEmail = false
+		} else {
+			br.Msg = "删除失败"
+			br.ErrMsg = "查找品种失败,ERR:" + err.Error()
+		}
+		return
+	}
+	err = varietyInfo.Delete()
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除品种失败,ERR:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// List
+// @Title 获取标签中的指标与品种的映射关系
+// @Description 获取标签中的指标与品种的映射关系
+// @Success 200 Ret=200 保存成功
+// @router /variety/list [get]
+func (c *VarietyController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	// 获取数据
+	list, err := cross_variety.GetVarietyList()
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,ERR:" + err.Error()
+		return
+	}
+	dataCount := len(list)
+	page := paging.GetPaging(1, dataCount, dataCount)
+
+	resp := response.VarietyListResp{
+		List:   list,
+		Paging: page,
+	}
+
+	br.Ret = 200
+	br.Msg = "获取成功"
+	br.Success = true
+	br.Data = resp
+}

+ 1271 - 162
controllers/data_manage/edb_info.go

@@ -11,6 +11,7 @@ import (
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
+	"eta/eta_api/services/data_stat"
 	"eta/eta_api/services/elastic"
 	etaTrialService "eta/eta_api/services/eta_trial"
 	"eta/eta_api/utils"
@@ -31,7 +32,9 @@ type EdbInfoController struct {
 // @Title 新增指标-查询指标信息接口
 // @Description 新增指标-查询指标信息接口
 // @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
-// @Param   EdbCode   query   string  false       "指标编码"
+// @Param   SubSource   query   int  true       "子数据来源:0:经济数据库,1:日期序列"
+// @Param   EdbCode   query   string  false       "指标编码/指标代码"
+// @Param   StockCode   query   string  false       "证券代码"
 // @Success 200 {object} data_manage.EdbInfoSearchResp
 // @router /edb_info/search [get]
 func (this *EdbInfoController) EdbInfoSearch() {
@@ -45,11 +48,14 @@ func (this *EdbInfoController) EdbInfoSearch() {
 	edbCode = strings.Trim(edbCode, "\t")
 	edbCode = strings.Trim(edbCode, " ")
 	edbCode = strings.Replace(edbCode, "\t", "", -1)
+	subSource, _ := this.GetInt("SubSource")
+	stockCode := this.GetString("StockCode")
 
 	if source <= 0 {
 		br.Msg = "无效的数据来源"
 		return
 	}
+
 	if edbCode == "" {
 		br.Msg = "请输入指标ID"
 		return
@@ -155,76 +161,138 @@ func (this *EdbInfoController) EdbInfoSearch() {
 
 		searchItem := new(data_manage.EdbInfoSearch)
 		if source == utils.DATA_SOURCE_THS {
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_THS, utils.EDB_DATA_LIMIT)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				br.Msg = "获取失败"
-				br.ErrMsg = "获取Ths已存在信息失败,Err:" + err.Error()
-				return
-			}
-
-			fmt.Println("ths len:", len(dataItems))
-			if len(dataItems) > 0 {
-				fmt.Println("ths data exist")
-				searchItem.EdbCode = edbCode
-				minDate, maxDate, err := data_manage.GetEdbDataThsMaxOrMinDate(edbCode)
-				if err != nil {
+			fmt.Println("subSource:", subSource)
+			if subSource == utils.DATA_SUB_SOURCE_EDB {
+				dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_THS, subSource, utils.EDB_DATA_LIMIT)
+				if err != nil && err.Error() != utils.ErrNoRow() {
 					br.Msg = "获取失败"
-					br.ErrMsg = "获取Ths日期信息失败,Err:" + err.Error()
+					br.ErrMsg = "获取Ths已存在信息失败,Err:" + err.Error()
 					return
 				}
-				searchItem.DataList = dataItems
-				searchItem.StartDate = minDate
-				searchItem.EndDate = maxDate
-			} else {
-				//endDate := dateNow.AddDate(utils.DATA_END_DATE_LIMIT, 0, 0).Format(utils.FormatDate)
-				//searchItem, err = data.GetEdbDataByThs(edbCode, startDate, endDate)
-				//if err != nil {
-				//	br.Msg = "获取失败"
-				//	br.ErrMsg = "获取失败,Err:" + err.Error()
-				//	return
-				//}
-				respItem, err := data.AddEdbData(source, edbCode)
+
+				fmt.Println("ths len:", len(dataItems))
+				if len(dataItems) > 0 {
+					fmt.Println("ths data exist")
+					searchItem.EdbCode = edbCode
+					minDate, maxDate, err := data_manage.GetEdbDataThsMaxOrMinDate(edbCode)
+					if err != nil {
+						br.Msg = "获取失败"
+						br.ErrMsg = "获取Ths日期信息失败,Err:" + err.Error()
+						return
+					}
+					searchItem.DataList = dataItems
+					searchItem.StartDate = minDate
+					searchItem.EndDate = maxDate
+				} else {
+					//endDate := dateNow.AddDate(utils.DATA_END_DATE_LIMIT, 0, 0).Format(utils.FormatDate)
+					//searchItem, err = data.GetEdbDataByThs(edbCode, startDate, endDate)
+					//if err != nil {
+					//	br.Msg = "获取失败"
+					//	br.ErrMsg = "获取失败,Err:" + err.Error()
+					//	return
+					//}
+					respItem, err := data.AddEdbData(source, edbCode)
+					if err != nil {
+						br.Msg = "获取失败"
+						br.ErrMsg = "获取失败,Err:" + err.Error()
+						return
+					}
+					if respItem.Ret != 200 {
+						br.Msg = "未搜索到该指标"
+						br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
+						return
+					}
+					isAdd = true
+				}
+			} else if subSource == utils.DATA_SUB_SOURCE_DATE {
+				if stockCode == "" {
+					br.Msg = "请输入证券代码"
+					return
+				}
+				if edbCode == "" {
+					br.Msg = "请输入指标代码"
+					return
+				}
+				respItem, err := data.AddEdbDataThsDs(source, stockCode, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取失败,Err:" + err.Error()
 					return
 				}
 				if respItem.Ret != 200 {
-					br.Msg = "未搜索到该指标"
+					if respItem.Ret == 421 {
+						br.Msg = "该渠道已超过添加上限"
+					} else if respItem.Ret == 4052 {
+						br.Msg = "该指标已下架"
+					} else {
+						br.Msg = "未搜索到该指标"
+					}
 					br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
 					return
 				}
 				isAdd = true
-			}
-		} else if source == utils.DATA_SOURCE_WIND {
-			fmt.Println("wind data exist")
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_WIND, utils.EDB_DATA_LIMIT)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				br.Msg = "获取失败"
-				br.ErrMsg = "获取Wind已存在信息失败,Err:" + err.Error()
+			} else {
+				br.Msg = "无效的渠道来源"
 				return
 			}
-			fmt.Println("wind dataItems:", len(dataItems))
-			if len(dataItems) > 0 {
-				searchItem.EdbCode = edbCode
-				minDate, maxDate, err := data_manage.GetEdbDataWindMaxOrMinDate(edbCode)
-				if err != nil {
+		} else if source == utils.DATA_SOURCE_WIND {
+			fmt.Println("subSource:", subSource)
+			if subSource == utils.DATA_SUB_SOURCE_EDB {
+				dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_WIND, subSource, utils.EDB_DATA_LIMIT)
+				if err != nil && err.Error() != utils.ErrNoRow() {
 					br.Msg = "获取失败"
-					br.ErrMsg = "获取wind日期信息失败,Err:" + err.Error()
+					br.ErrMsg = "获取Wind已存在信息失败,Err:" + err.Error()
 					return
 				}
-				searchItem.DataList = dataItems
-				searchItem.StartDate = minDate
-				searchItem.EndDate = maxDate
-			} else {
-				//endDate := dateNow.Format(utils.FormatDate)
-				//searchItem, err = data.GetEdbDataByWind(edbCode, startDate, endDate)
-				//if err != nil {
-				//	br.Msg = "获取失败"
-				//	br.ErrMsg = "wind 获取失败,Err:" + err.Error()
-				//	return
-				//}
-				respItem, err := data.AddEdbData(source, edbCode)
+				fmt.Println("wind dataItems:", len(dataItems))
+				if len(dataItems) > 0 {
+					searchItem.EdbCode = edbCode
+					minDate, maxDate, err := data_manage.GetEdbDataWindMaxOrMinDate(edbCode)
+					if err != nil {
+						br.Msg = "获取失败"
+						br.ErrMsg = "获取wind日期信息失败,Err:" + err.Error()
+						return
+					}
+					searchItem.DataList = dataItems
+					searchItem.StartDate = minDate
+					searchItem.EndDate = maxDate
+				} else {
+					//endDate := dateNow.Format(utils.FormatDate)
+					//searchItem, err = data.GetEdbDataByWind(edbCode, startDate, endDate)
+					//if err != nil {
+					//	br.Msg = "获取失败"
+					//	br.ErrMsg = "wind 获取失败,Err:" + err.Error()
+					//	return
+					//}
+					respItem, err := data.AddEdbData(source, edbCode)
+					if err != nil {
+						br.Msg = "获取失败"
+						br.ErrMsg = "获取失败,Err:" + err.Error()
+						return
+					}
+					if respItem.Ret != 200 {
+						if respItem.Ret == 421 {
+							br.Msg = "该渠道已超过添加上限"
+						} else if respItem.Ret == 4052 {
+							br.Msg = "该指标已下架"
+						} else {
+							br.Msg = "未搜索到该指标"
+						}
+						br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
+						return
+					}
+					isAdd = true
+				}
+			} else if subSource == utils.DATA_SUB_SOURCE_DATE {
+				if stockCode == "" {
+					br.Msg = "请输入证券代码"
+					return
+				}
+				if edbCode == "" {
+					br.Msg = "请输入指标代码"
+					return
+				}
+				respItem, err := data.AddEdbDataWindWsd(source, stockCode, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取失败,Err:" + err.Error()
@@ -242,10 +310,13 @@ func (this *EdbInfoController) EdbInfoSearch() {
 					return
 				}
 				isAdd = true
+			} else {
+				br.Msg = "无效的渠道来源"
+				return
 			}
 		} else if source == utils.DATA_SOURCE_PB || source == utils.DATA_SOURCE_PB_FINANCE {
 			fmt.Println("pb data exist")
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取Pb已存在信息失败,Err:" + err.Error()
@@ -286,7 +357,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				isAdd = true
 			}
 		} else if source == utils.DATA_SOURCE_MANUAL { //手工数据指标
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_MANUAL, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_MANUAL, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取Ths已存在信息失败,Err:" + err.Error()
@@ -340,7 +411,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 
 		} else if source == utils.DATA_SOURCE_LZ {
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_LZ, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_LZ, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取隆众已存在信息失败,Err:" + err.Error()
@@ -409,7 +480,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = lzInfo.SampleName + lzInfo.BreedName + lzInfo.QuotaName
 			}
 		} else if source == utils.DATA_SOURCE_YS { //有色网
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_YS, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_YS, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取Ys已存在信息失败,Err:" + err.Error()
@@ -469,7 +540,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 
 		} else if source == utils.DATA_SOURCE_GL { //钢联
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取钢联已存在信息失败,Err:" + err.Error()
@@ -533,7 +604,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取郑商所已存在信息失败,Err:" + err.Error()
@@ -611,7 +682,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取大商所已存在信息失败,Err:" + err.Error()
@@ -690,7 +761,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取上期所已存在信息失败,Err:" + err.Error()
@@ -769,7 +840,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取中金所已存在信息失败,Err:" + err.Error()
@@ -848,7 +919,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取上期能源已存在信息失败,Err:" + err.Error()
@@ -942,7 +1013,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取欧洲天然气已存在信息失败,Err:" + err.Error()
@@ -1050,7 +1121,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "暂不支持编码中含有=的指标"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_LT, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_LT, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取 lt 已存在信息失败,Err:" + err.Error()
@@ -1059,7 +1130,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			fmt.Println("lt dataItems:", len(dataItems))
 			if len(dataItems) > 0 {
 				searchItem.EdbCode = edbCode
-				edbInfoMaxAndMinInfo, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				edbInfoMaxAndMinInfo, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取lt日期信息失败,Err:" + err.Error()
@@ -1106,7 +1177,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				br.ErrMsg = "指标code异常"
 				return
 			}
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取煤炭网已存在信息失败,Err:" + err.Error()
@@ -1167,7 +1238,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = coalInfo.IndexName
 			}
 		} else if source == utils.DATA_SOURCE_GOOGLE_TRAVEL { //谷歌出行数据
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取煤炭网已存在信息失败,Err:" + err.Error()
@@ -1176,7 +1247,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 
 			if len(dataItems) > 0 {
 				searchItem.EdbCode = edbCode
-				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取煤炭网日期信息失败,Err:" + err.Error()
@@ -1202,7 +1273,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				isAdd = true
 			}
 		} else if source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL { //钢联化工
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取钢联已存在信息失败,Err:" + err.Error()
@@ -1254,7 +1325,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = glInfo.IndexName
 			}
 		} else if source == utils.DATA_SOURCE_EIA_STEO { //eia steo报告
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取钢联已存在信息失败,Err:" + err.Error()
@@ -1263,7 +1334,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 
 			if len(dataItems) > 0 {
 				searchItem.EdbCode = edbCode
-				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取eia steo日期信息失败,Err:" + err.Error()
@@ -1299,7 +1370,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = eiasteoInfo.IndexName
 			}
 		} else if source == utils.DATA_SOURCE_COM_TRADE { // un数据源
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取联合国商品贸易数据已存在信息失败,Err:" + err.Error()
@@ -1308,7 +1379,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 
 			if len(dataItems) > 0 {
 				searchItem.EdbCode = edbCode
-				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取联合国商品贸易数据日期信息失败,Err:" + err.Error()
@@ -1353,7 +1424,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = eiasteoInfo.Name
 			}
 		} else if source == utils.DATA_SOURCE_SCI { //卓创数据(红桃三)
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取SCI已存在信息失败,Err:" + err.Error()
@@ -1413,7 +1484,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 
 		} else if source == utils.DATA_SOURCE_BAIINFO { //百川盈孚
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取BAIINFO已存在信息失败,Err:" + err.Error()
@@ -1473,7 +1544,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 
 		} else if source == utils.DATA_SOURCE_NATIONAL_STATISTICS { // 国家统计局
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取国家统计局已存在信息失败,Err:" + err.Error()
@@ -1482,7 +1553,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 
 			if len(dataItems) > 0 {
 				searchItem.EdbCode = edbCode
-				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				item, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if err != nil {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取国家统计局日期信息失败,Err:" + err.Error()
@@ -1518,7 +1589,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbName = fmt.Sprintf("%s%s", nationalInfo.Reg, nationalInfo.IndexName)
 			}
 		} else if source == utils.DATA_SOURCE_FUBAO { //数宝
-			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_FUBAO, utils.EDB_DATA_LIMIT)
+			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_FUBAO, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取Fubao已存在信息失败,Err:" + err.Error()
@@ -1561,7 +1632,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 
 			// 获取指标数据
-			dataList, e := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
+			dataList, e := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if e != nil {
 				br.Msg = "获取失败"
 				br.ErrMsg = "获取指标数据失败, Err: " + e.Error()
@@ -1571,7 +1642,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.EdbCode = edbCode
 				searchItem.DataList = dataList
 				// 获取最大最小值
-				edbInfoMaxAndMinInfo, e := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
+				edbInfoMaxAndMinInfo, e := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
 				if e != nil && e.Error() != utils.ErrNoRow() {
 					br.Msg = "获取失败"
 					br.ErrMsg = "获取数据失败, GetEdbInfoMaxAndMinInfo Err:" + e.Error()
@@ -1602,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)
@@ -1625,31 +1702,141 @@ func (this *EdbInfoController) EdbInfoSearch() {
 			}
 		}
 		if isAdd {
-			dataList, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, utils.EDB_DATA_LIMIT)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				br.Msg = "获取失败"
-				br.ErrMsg = "获取数据失败,GetEdbDataAllByEdbCode Err:" + err.Error()
-				return
-			}
-			searchItem.DataList = dataList
+			if subSource == utils.DATA_SUB_SOURCE_DATE {
+				if source == utils.DATA_SOURCE_WIND {
+					//wsdData := windWsdRespItem.Data
+					//var buf bytes.Buffer
+					//// 创建一个encoder并指定目标为buf
+					//enc := gob.NewEncoder(&buf)
+					//
+					//// 将data编码到buf中
+					//err = enc.Encode(wsdData)
+					//if err != nil {
+					//	br.Msg = "获取失败"
+					//	br.ErrMsg = "获取数据失败,wind wsd encoding GOB Err:" + err.Error()
+					//	return
+					//}
+					//
+					//wsdDataMap := make(map[string]map[string]interface{})
+					//err = json.Unmarshal(buf.Bytes(), &wsdDataMap)
+					//if err != nil {
+					//	br.Msg = "获取失败"
+					//	br.ErrMsg = "获取数据失败,wind wsd json.Unmarshal Err:" + err.Error()
+					//	return
+					//}
+					//
+					//stockList := make([]*data_manage.StockInfo, 0)
+					//
+					//dataList := make([]*data_manage.EdbInfoSearchData, 0)
+					//for wk, wv := range wsdDataMap {
+					//	for vk, vv := range wv {
+					//		wkInt, err := strconv.ParseInt(wk, 10, 64)
+					//		if err != nil {
+					//			br.Msg = "获取失败"
+					//			br.ErrMsg = "获取数据失败,转换日期类型失败 Err:" + err.Error()
+					//			return
+					//		}
+					//
+					//		vk = strings.ToLower(vk)
+					//		wkInt = wkInt / 1000
+					//		t := time.Unix(wkInt, 0)
+					//		dateTime := t.Format(utils.FormatDate)
+					//		//saveVal := utils.SubFloatToString(val, 20)
+					//		if vv == nil {
+					//			continue
+					//		}
+					//		var saveVal string
+					//		switch vt := vv.(type) {
+					//		case int:
+					//			saveVal = strconv.Itoa(vt)
+					//		case float64:
+					//			saveVal = utils.SubFloatToFloatStr(vt, 20)
+					//		case string:
+					//			saveVal = vt
+					//		}
+					//
+					//		dataItem := new(data_manage.EdbInfoSearchData)
+					//		dataItem.Value = saveVal
+					//		dataItem.DataTime = dateTime
+					//		dataList = append(dataList, dataItem)
+					//		if len(dataList) >= 10 {
+					//			break
+					//		}
+					//	}
+					//}
+					//searchItem.StockList = stockList
+
+					stockList := make([]*data_manage.StockInfo, 0)
+					edbCodeArr := strings.Split(edbCode, ",")
+					for _, v := range edbCodeArr {
+						indexCode := utils.WindDbWsd + stockCode + v
+
+						dataList, err := data_manage.GetEdbDataAllByEdbCodeAndSubSource(indexCode, source, utils.DATA_SUB_SOURCE_DATE, utils.EDB_DATA_LIMIT)
+						if err != nil && err.Error() != utils.ErrNoRow() {
+							br.Msg = "获取失败"
+							br.ErrMsg = "获取数据失败,GetEdbDataAllByEdbCode Err:" + err.Error()
+							return
+						}
+
+						stockInfo := new(data_manage.StockInfo)
+						stockInfo.StockCode = stockCode
+						stockInfo.EdbCode = v
+						stockInfo.DataList = dataList
+						stockList = append(stockList, stockInfo)
+					}
+					searchItem.StockList = stockList
+				} else if source == utils.DATA_SOURCE_THS {
+					stockList := make([]*data_manage.StockInfo, 0)
+					edbCodeArr := strings.Split(edbCode, ",")
+					for _, v := range edbCodeArr {
+						indexCode := utils.ThsDs + stockCode + v
+
+						dataList, err := data_manage.GetEdbDataAllByEdbCodeAndSubSource(indexCode, source, utils.DATA_SUB_SOURCE_DATE, utils.EDB_DATA_LIMIT)
+						if err != nil && err.Error() != utils.ErrNoRow() {
+							br.Msg = "获取失败"
+							br.ErrMsg = "获取数据失败,GetEdbDataAllByEdbCode Err:" + err.Error()
+							return
+						}
+
+						stockInfo := new(data_manage.StockInfo)
+						stockInfo.StockCode = stockCode
+						stockInfo.EdbCode = v
+						stockInfo.DataList = dataList
+						stockList = append(stockList, stockInfo)
+					}
+					searchItem.StockList = stockList
+				} else {
+					br.Msg = "来源错误"
+					br.ErrMsg = "来源错误"
+					return
+				}
+			} else {
+				dataList, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取数据失败,GetEdbDataAllByEdbCode Err:" + err.Error()
+					return
+				}
+				searchItem.DataList = dataList
 
-			edbInfoMaxAndMinInfo, err := data_manage.GetEdbInfoMaxAndMinInfo(source, edbCode)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				br.Msg = "获取失败"
-				br.ErrMsg = "获取数据失败,GetEdbInfoMaxAndMinInfo Err:" + err.Error()
-				return
-			}
-			searchItem.EdbCode = edbCode
-			searchItem.DataList = dataList
-			if edbInfoMaxAndMinInfo != nil {
-				searchItem.StartDate = edbInfoMaxAndMinInfo.MinDate
-				searchItem.EndDate = edbInfoMaxAndMinInfo.MaxDate
-			}
+				edbInfoMaxAndMinInfo, err := data_manage.GetEdbInfoMaxAndMinInfo(source, subSource, edbCode)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取数据失败,GetEdbInfoMaxAndMinInfo Err:" + err.Error()
+					return
+				}
+				searchItem.EdbCode = edbCode
+				searchItem.DataList = dataList
+				if edbInfoMaxAndMinInfo != nil {
+					searchItem.StartDate = edbInfoMaxAndMinInfo.MinDate
+					searchItem.EndDate = edbInfoMaxAndMinInfo.MaxDate
+				}
 
-			//edb指标信息
-			edbInfoItem, err := data_manage.GetEdbInfoByEdbCode(source, edbCode)
-			if edbInfoItem != nil {
-				searchItem.EdbName = edbInfoItem.EdbName
+				//edb指标信息
+				edbInfoItem, err := data_manage.GetEdbInfoByEdbCode(source, edbCode)
+				if edbInfoItem != nil {
+					searchItem.EdbName = edbInfoItem.EdbName
+				}
 			}
 		}
 		resp.Status = 2
@@ -1778,20 +1965,58 @@ func (this *EdbInfoController) EdbInfoList() {
 	dataCondition += ` AND edb_info_id=? `
 	dataPars = append(dataPars, edbInfoItem.EdbInfoId)
 
-	dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source)
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		br.Msg = "获取指标信息失败"
-		br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
-		return
-	}
-	page = paging.GetPaging(currentIndex, pageSize, dataCount)
-	dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, pageSize, startSize)
-	if err != nil {
-		br.Msg = "获取指标信息失败"
-		br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
-		return
+	if edbInfoItem.SubSource == utils.DATA_SUB_SOURCE_DATE {
+		if edbInfoItem.Source == utils.DATA_SOURCE_WIND {
+			dataCount, err := data_manage.GetEdbWsdDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取指标信息失败"
+				br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
+				return
+			}
+			page = paging.GetPaging(currentIndex, pageSize, dataCount)
+			dataList, err := data_manage.GetEdbWsdDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, pageSize, startSize)
+			if err != nil {
+				br.Msg = "获取指标信息失败"
+				br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+				return
+			}
+			edbInfoItem.DataList = dataList
+		} else if edbInfoItem.Source == utils.DATA_SOURCE_THS {
+			dataCount, err := data_manage.GetTHsDsDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source)
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取指标信息失败"
+				br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
+				return
+			}
+			page = paging.GetPaging(currentIndex, pageSize, dataCount)
+			dataList, err := data_manage.GetThsDsDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, pageSize, startSize)
+			if err != nil {
+				br.Msg = "获取指标信息失败"
+				br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+				return
+			}
+			edbInfoItem.DataList = dataList
+		} else {
+			br.Msg = "指标数据源id错误"
+			br.ErrMsg = "指标数据源id错误"
+			return
+		}
+	} else {
+		dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source, edbInfoItem.SubSource)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取指标信息失败"
+			br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
+			return
+		}
+		page = paging.GetPaging(currentIndex, pageSize, dataCount)
+		dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, edbInfoItem.SubSource, pageSize, startSize)
+		if err != nil {
+			br.Msg = "获取指标信息失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		edbInfoItem.DataList = dataList
 	}
-	edbInfoItem.DataList = dataList
 
 	// 获取指标插入配置
 	{
@@ -1930,7 +2155,7 @@ func (this *EdbInfoController) EdbInfoAdd() {
 	}
 
 	// 指标入库
-	edbInfo, err, errMsg, isSendEmail := data.EdbInfoAdd(source, req.ClassifyId, req.EdbCode, req.EdbName, req.Frequency, req.Unit, req.StartDate, req.EndDate, sysUser.AdminId, sysUser.RealName)
+	edbInfo, err, errMsg, isSendEmail := data.EdbInfoAdd(source, utils.DATA_SUB_SOURCE_EDB, req.ClassifyId, req.EdbCode, req.EdbName, req.Frequency, req.Unit, req.StartDate, req.EndDate, sysUser.AdminId, sysUser.RealName)
 	if err != nil {
 		br.Msg = "保存失败"
 		if errMsg != `` {
@@ -1974,6 +2199,9 @@ func (this *EdbInfoController) EdbInfoAdd() {
 		go data_manage.AddEdbInfoLog(edbLog)
 	}
 
+	// 更新es
+	go data.AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+
 	resp := new(data_manage.AddEdbInfoResp)
 	resp.EdbInfoId = edbInfo.EdbInfoId
 	resp.UniqueCode = edbInfo.UniqueCode
@@ -2132,6 +2360,11 @@ func (this *EdbInfoController) EdbInfoEdit() {
 	// 修改关联的预测指标基础信息
 	go data.ModifyPredictEdbBaseInfoBySourceEdb(edbInfo)
 
+	// 添加钢联指标更新日志
+	if edbInfo.Source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+		go data_stat.AddEdbInfoUpdateLog(req.EdbInfoId, 1, "", sysUser)
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "保存成功"
@@ -2308,7 +2541,7 @@ func (this *EdbInfoController) EdbInfoRefresh() {
 		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
 		return
 	}
-	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, false)
+	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, false, false)
 	if err != nil {
 		br.Msg = "刷新失败"
 		br.ErrMsg = "刷新指标失败,EdbInfoRefresh Err:" + err.Error()
@@ -2991,7 +3224,7 @@ func (this *EdbInfoController) EdbInfoAllRefresh() {
 		br.ErrMsg = "数据已被删除,请刷新页面,edbInfoId:" + strconv.Itoa(edbInfoId)
 		return
 	}
-	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, true)
+	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, true, false)
 	if err != nil {
 		br.Msg = "刷新失败"
 		br.ErrMsg = "刷新指标失败,EdbInfoRefreshAllFromBase Err:" + err.Error()
@@ -3061,9 +3294,9 @@ func (this *ChartInfoController) EdbInfoData() {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
 		maxYear = latestDateT.Year()
 	}
-
+	dataList := make([]*data_manage.EdbDataList, 0)
 	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
-	dataList, err := data_manage.GetEdbDataList(edbInfo.Source, edbInfoId, startDate, endDate)
+	dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDate, endDate)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败,Err:" + err.Error()
@@ -3192,7 +3425,7 @@ func (this *ChartInfoController) EdbInfoReplace() {
 
 	sysAdminId := sysUser.AdminId
 	//replaceChartTotal, replaceCalculateTotal, err := data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
-	_, _, err = data_manage.EdbInfoReplaceV2(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
+	_, _, err = data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
 	//msgContent := ``
 	isFail := false
 	var errmsg string
@@ -3522,7 +3755,7 @@ func (this *EdbInfoController) RelationEdbList() {
 
 		dataList := make([]*data_manage.EdbDataList, 0)
 		if v.EdbInfoType == 0 {
-			dataList, err = data_manage.GetEdbDataList(v.Source, v.EdbInfoId, "", "")
+			dataList, err = data_manage.GetEdbDataList(v.Source, v.SubSource, v.EdbInfoId, "", "")
 		} else {
 			_, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(v.EdbInfoId, "", "", false)
 		}
@@ -3797,7 +4030,7 @@ func (this *ChartInfoController) EdbInfoDataTb() {
 		//同比值的计算方式,是需要与去年同期对比,所以如果用户需要某个时间段的数据的话,获取基础数据时,需要往前面推(1年+兼容的日期频度(目前是35天))
 		startDate = startDateTime.AddDate(-1, 0, -35).Format(utils.FormatDate)
 	}
-	tmpDataList, err := data_manage.GetEdbDataList(edbInfo.Source, edbInfoId, startDate, endDate)
+	tmpDataList, err := data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDate, endDate)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.Msg = "获取失败,Err:" + err.Error()
@@ -4065,6 +4298,10 @@ func (this *EdbInfoController) AllEdbInfoByEs() {
 	//指标来源
 	source, _ := this.GetInt("Source")
 
+	frequency := this.GetString("Frequency") //频度
+
+	isAddPredictEdb, _ := this.GetBool("IsAddPredictEdb") //是否查询添加预测指标
+
 	var edbInfoList []*data_manage.EdbInfoList
 	var err error
 
@@ -4092,6 +4329,46 @@ func (this *EdbInfoController) AllEdbInfoByEs() {
 
 		// 普通的搜索
 		total, edbInfoList, err = elastic.SearchEdbInfoData(utils.DATA_INDEX_NAME, keyWord, startSize, pageSize, filterSource, source, -1, ``, noPermissionEdbInfoIdList)
+	} else {
+		var condition string
+		var pars []interface{}
+		// 普通指标
+		condition += ` AND edb_info_type = ? `
+		pars = append(pars, 0)
+
+		// 无权限指标id
+		lenNoPermissionEdbInfoIdList := len(noPermissionEdbInfoIdList)
+		if lenNoPermissionEdbInfoIdList > 0 {
+			condition += ` AND edb_info_id  not in (` + utils.GetOrmInReplace(lenNoPermissionEdbInfoIdList) + `) `
+			pars = append(pars, noPermissionEdbInfoIdList)
+		}
+
+		switch filterSource {
+		case 2:
+			condition += ` AND frequency='月度' `
+		case 3:
+			condition += ` AND frequency <> '日度' `
+		case 4:
+			condition += ` AND edb_type = 1 `
+		case 5:
+			condition += ` AND source = 6 ` //来源(同比值)
+		case 6:
+			condition += ` AND frequency != ? `
+			pars = append(pars, "年度")
+		}
+
+		//频度
+		if frequency != "" {
+			condition += ` AND frequency = ? `
+			pars = append(pars, frequency)
+		}
+
+		// 查询只允许添加预测指标的搜索
+		if isAddPredictEdb {
+			condition += ` AND frequency in ("日度","周度","月度") `
+		}
+
+		total, edbInfoList, err = data_manage.GetEdbInfoFilterList(condition, pars, startSize, pageSize)
 	}
 	if err != nil {
 		edbInfoList = make([]*data_manage.EdbInfoList, 0)
@@ -4228,17 +4505,25 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		br.IsSendEmail = false
 		return
 	}
-	if date == `` {
-		br.Msg = "请选择日期"
-		br.IsSendEmail = false
-		return
-	}
 	edbInfo, err := data_manage.GetEdbInfoById(edbInfoId)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = fmt.Sprint("获取指标信息失败,Err:", err.Error())
 		return
 	}
+
+	// 当前日期
+	var currDate string
+	// 是否查找之后的数据
+	isFindAfter := true
+	if date == `` {
+		currDate = edbInfo.EndDate
+		isFindAfter = false
+		if num <= 0 {
+			num = 4 //默认获取前面的几期数据
+		}
+	}
+
 	dataList := make([]*data_manage.EdbDataList, 0)
 
 	startDate := date
@@ -4250,40 +4535,45 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		dateType = "month"
 	}
 
-	// 后面的数据
-	afterList, err := data.GetEdbBeforeAndAfterDateData(edbInfo, startDate, "", 2, num)
-	if err != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
-		return
+	resp := data_manage.BeforeAndAfterDateDataResp{
+		List: dataList,
+		Date: "",
 	}
-
-	// 当前日期
-	var currDate string
-	lenBeforeList := len(afterList)
-	if lenBeforeList <= 0 {
-		br.Ret = 200
-		br.Success = true
-		br.Msg = "所选指标所选日期无值"
-		br.Data = dataList
-		return
-	} else {
-		var dateTimeStr string
-		switch dateType {
-		case "month":
-			dateTime, _ := time.ParseInLocation(utils.FormatDate, afterList[0].DataTime, time.Local)
-			dateTimeStr = dateTime.Format(utils.FormatYearMonthDate)
-		case "day":
-			dateTimeStr = afterList[0].DataTime
+	// 后面的数据
+	afterList := make([]*data_manage.EdbDataList, 0)
+	if isFindAfter {
+		afterList, err = data.GetEdbBeforeAndAfterDateData(edbInfo, startDate, "", 2, num)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = fmt.Sprint("获取后面的指数据失败,Err:", err.Error())
+			return
 		}
-		currDate = afterList[0].DataTime
-		// 如果对应日期找不到,那么就直接返回吧
-		if dateTimeStr != date {
+
+		lenBeforeList := len(afterList)
+		if lenBeforeList <= 0 {
 			br.Ret = 200
 			br.Success = true
 			br.Msg = "所选指标所选日期无值"
-			br.Data = dataList
+			br.Data = resp
 			return
+		} else {
+			var dateTimeStr string
+			switch dateType {
+			case "month":
+				dateTime, _ := time.ParseInLocation(utils.FormatDate, afterList[0].DataTime, time.Local)
+				dateTimeStr = dateTime.Format(utils.FormatYearMonthDate)
+			case "day":
+				dateTimeStr = afterList[0].DataTime
+			}
+			currDate = afterList[0].DataTime
+			// 如果对应日期找不到,那么就直接返回吧
+			if dateTimeStr != date {
+				br.Ret = 200
+				br.Success = true
+				br.Msg = "所选指标所选日期无值"
+				br.Data = resp
+				return
+			}
 		}
 	}
 
@@ -4310,9 +4600,10 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 		dataList[i], dataList[j] = dataList[j], dataList[i]
 	}
 
-	resp := data_manage.BeforeAndAfterDateDataResp{
-		List: dataList,
-		Date: currDate,
+	resp.List = dataList
+	// 前端不传入日期的时候,这个J皮不让返回这个字段,要不然他会颜色标记
+	if date != `` {
+		resp.Date = currDate
 	}
 
 	br.Ret = 200
@@ -4791,3 +5082,821 @@ func (this *EdbInfoController) ChartImageSet() {
 	br.Success = true
 	br.Msg = "保存成功"
 }
+
+// EdbInfoExistCheck
+// @Title 新增指标-检验指标是否存在接口
+// @Description 新增指标-检验指标是否存在接口
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind"
+// @Param   SubSource   query   int  true       "子数据来源:0:经济数据库,1:日期序列"
+// @Param   EdbCode   query   string  false       "指标编码/指标代码"
+// @Param   StockCode   query   string  false       "证券代码"
+// @Success 200 {object} data_manage.EdbInfoExistCheckResp
+// @router /edb_info/exist/check [get]
+func (this *EdbInfoController) EdbInfoExistCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	source, _ := this.GetInt("Source")
+	edbCode := this.GetString("EdbCode")
+	edbCode = strings.Trim(edbCode, "\t")
+	edbCode = strings.Trim(edbCode, " ")
+	edbCode = strings.Replace(edbCode, "\t", "", -1)
+	subSource, _ := this.GetInt("SubSource")
+	stockCode := this.GetString("StockCode")
+
+	if source <= 0 {
+		br.Msg = "无效的数据来源"
+		return
+	}
+
+	if edbCode == "" {
+		br.Msg = "请输入指标ID"
+		return
+	}
+
+	if source != utils.DATA_SOURCE_WIND && source != utils.DATA_SOURCE_THS {
+		br.Msg = "无效的数据来源"
+		return
+	}
+	if subSource != utils.DATA_SUB_SOURCE_DATE {
+		br.Msg = "无效的数据库来源"
+		return
+	}
+
+	var indexCodeArr []string
+	edbCodeArr := strings.Split(edbCode, ",")
+	stockCodeArr := strings.Split(stockCode, ",")
+
+	var prefix string
+	if source == utils.DATA_SOURCE_WIND {
+		prefix = utils.WindDbWsd
+	} else if source == utils.DATA_SOURCE_THS {
+		prefix = utils.ThsDs
+	} else {
+		br.Msg = "来源错误"
+		br.ErrMsg = "来源错误"
+		return
+	}
+	for _, sv := range stockCodeArr {
+		for _, ev := range edbCodeArr {
+			indexCode := prefix + sv + ev
+			indexCodeArr = append(indexCodeArr, indexCode)
+		}
+	}
+	indexList, err := data_manage.GetEdbInfoByEdbCodeList(source, indexCodeArr)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "校验指标是否存在失败"
+		br.ErrMsg = "校验指标是否存在失败,Err:" + err.Error()
+		return
+	}
+	var existStockCodeArr []string
+	var existEdbCodeArr []string
+	var existClassifyId []int
+	var existIndexId []int
+
+	for _, indexItem := range indexList {
+		for _, sv := range stockCodeArr {
+			for _, ev := range edbCodeArr {
+				if strings.Contains(indexItem.EdbCode, sv) {
+					existStockCodeArr = append(existStockCodeArr, sv)
+				}
+				if strings.Contains(indexItem.EdbCode, ev) {
+					existEdbCodeArr = append(existEdbCodeArr, ev)
+					existClassifyId = append(existClassifyId, indexItem.ClassifyId)
+					existIndexId = append(existIndexId, indexItem.EdbInfoId)
+				}
+			}
+		}
+	}
+
+	resp := new(data_manage.EdbInfoExistCheckResp)
+	if len(indexList) > 0 {
+		resp.IndexExist = true
+	}
+	resp.ExistEdbCodeArr = existEdbCodeArr
+	resp.ExistStockCodeArr = existStockCodeArr
+	resp.ExistClassifyId = existClassifyId
+	resp.ExistIndexId = existIndexId
+	resp.ExistEdbInfo = indexList
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbInfoAdd
+// @Title 指标批量保存接口
+// @Description 指标批量保存接口
+// @Param	request	body data_manage.BatchAddEdbInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /edb_info/batch/add [post]
+func (this *EdbInfoController) EdbInfoBatchAdd() {
+	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
+	}
+	deleteCache := true
+	cacheKey := "CACHE_EDB_INFO_BATCH_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(this.Ctx.Input.RequestBody)
+		return
+	}
+	var req data_manage.BatchAddEdbInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	resp := new(data_manage.AddEdbInfoResp)
+
+	var edbNames string
+	for _, v := range req.BatchList {
+		edbNames += "'" + v.EdbName + "',"
+	}
+	edbNames = strings.Trim(edbNames, ",")
+	infoList, err := data_manage.GetEdbInfoByNames(edbNames)
+	if err != nil {
+		br.Msg = "查询指标名称重复错误!"
+		br.ErrMsg = "GetEdbInfoByNames,Err:" + err.Error()
+		return
+	}
+	if len(infoList) > 0 {
+		for _, v := range infoList {
+			resp.ExistEdbName = append(resp.ExistEdbName, v.EdbName)
+		}
+		br.Data = resp
+		br.Msg = "指标名称重复!"
+		br.ErrMsg = "指标名称重复"
+		return
+	}
+
+	for k, v := range req.BatchList {
+		v.EdbName = strings.Trim(v.EdbName, " ")
+		v.EdbCode = strings.Trim(v.EdbCode, " ")
+		v.StockCode = strings.Trim(v.StockCode, " ")
+
+		if v.Source <= 0 {
+			br.Msg = "无效的数据来源"
+			return
+		}
+
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不能为空"
+			return
+		}
+
+		if v.StockCode == "" {
+			br.Msg = "证券代码不能为空"
+			return
+		}
+
+		if v.EdbName == "" {
+			br.Msg = "指标名称不能为空"
+			return
+		}
+
+		if v.Frequency == "" {
+			br.Msg = "频率不能为空"
+			return
+		}
+
+		if v.ClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			return
+		}
+
+		edbInfoItem := new(data_manage.EdbInfo)
+		edbInfoItem.Source = v.Source
+		switch v.Source {
+		case utils.DATA_SOURCE_WIND:
+			edbInfoItem.SourceName = "wind"
+			edbInfoItem.EdbCode = utils.WindDbWsd + v.StockCode + v.EdbCode
+		case utils.DATA_SOURCE_THS:
+			edbInfoItem.SourceName = "ths"
+			edbInfoItem.EdbCode = utils.ThsDs + v.StockCode + v.EdbCode
+		}
+		edbInfoItem.SubSource = 1
+		edbInfoItem.SubSourceName = "日期序列"
+		edbInfoItem.EdbName = v.EdbName
+		edbInfoItem.Frequency = v.Frequency
+		edbInfoItem.Unit = v.Unit
+		edbInfoItem.ClassifyId = v.ClassifyId
+		edbInfoItem.SysUserId = sysUser.AdminId
+		edbInfoItem.SysUserRealName = sysUser.RealName
+		edbInfoItem.IndicatorCode = v.EdbCode
+		edbInfoItem.StockCode = v.StockCode
+
+		// 指标入库
+		edbInfo, err, errMsg, isSendEmail := data.EdbInfoWsdAdd(edbInfoItem)
+		if err != nil {
+			br.Msg = "保存失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
+			br.ErrMsg = err.Error()
+			br.IsSendEmail = isSendEmail
+			return
+		}
+		//新增操作日志
+		{
+			edbLog := new(data_manage.EdbInfoLog)
+			edbLog.EdbInfoId = edbInfo.EdbInfoId
+			edbLog.SourceName = edbInfo.SourceName
+			edbLog.Source = edbInfo.Source
+			edbLog.EdbCode = edbInfo.EdbCode
+			edbLog.EdbName = edbInfo.EdbName
+			edbLog.ClassifyId = edbInfo.ClassifyId
+			edbLog.SysUserId = sysUser.AdminId
+			edbLog.SysUserRealName = sysUser.RealName
+			edbLog.CreateTime = time.Now()
+			edbLog.Content = string(this.Ctx.Input.RequestBody)
+			edbLog.Status = "新增指标"
+			edbLog.Method = this.Ctx.Input.URI()
+			go data_manage.AddEdbInfoLog(edbLog)
+		}
+
+		if k <= 0 {
+			resp.EdbInfoId = edbInfo.EdbInfoId
+			resp.UniqueCode = edbInfo.UniqueCode
+		}
+	}
+
+	// 试用平台更新用户累计新增指标数
+	adminItem, e := system.GetSysAdminById(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error()
+		return
+	}
+	if utils.BusinessCode == utils.BusinessCodeSandbox && adminItem.DepartmentName == "ETA试用客户" {
+		go func() {
+			var r etaTrialService.EtaTrialUserReq
+			r.Mobile = adminItem.Mobile
+			_, _ = etaTrialService.UpdateUserIndexNum(r)
+		}()
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// SmmExistCheck
+// @Title 新增指标-检验指标是否存在接口-smm
+// @Description 新增指标-检验指标是否存在接口-smm
+// @Param   SubSource   query   int  true       "子数据来源:0:经济数据库,1:日期序列"
+// @Param   EdbCode   query   string  false       "指标编码/指标代码"
+// @Param   StockCode   query   string  false       "证券代码"
+// @Success 200 {object} data_manage.EdbInfoExistCheckResp
+// @router /edb_info/smm/exist/check [get]
+func (this *EdbInfoController) SmmExistCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	selectAll, err := this.GetBool("SelectAll", false)
+	if err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	types := this.GetString("Types")
+	frequency := this.GetString("Frequency")
+	dataState := this.GetString("DataState")
+	edbCode := this.GetString("EdbCode")
+	edbCode = strings.Trim(edbCode, "\t")
+	edbCode = strings.Trim(edbCode, " ")
+	edbCode = strings.Replace(edbCode, "\t", "", -1)
+
+	selectCode := this.GetString("SelectCode")
+	selectCode = strings.Trim(selectCode, "\t")
+	selectCode = strings.Trim(selectCode, " ")
+	selectCode = strings.Replace(selectCode, "\t", "", -1)
+
+	var edbCodeArr []string
+	var codeArr []string
+
+	if selectAll {
+		// 如果勾了列表全选,那么EdbCode传的就是排除的code
+		if selectCode == "" {
+			// 无勾选code,走查询
+			var condition string
+			var pars []interface{}
+
+			if types != "" {
+				typeArr := strings.Split(types, ",")
+				for i, v := range typeArr {
+					typeStr := "type_"
+					typeStr += fmt.Sprintf("%d", i+1)
+					condition += " AND " + typeStr + " =? "
+					pars = append(pars, v)
+				}
+			}
+
+			if dataState != "" {
+				if dataState == "normal" {
+					condition += " AND (data_state = 'normal' OR data_state = '') "
+					pars = append(pars)
+				} else {
+					condition += " AND data_state = ? "
+					pars = append(pars, dataState)
+				}
+			}
+
+			if frequency != "" {
+				condition += " AND frequency = ? "
+				pars = append(pars, frequency)
+			}
+
+			indexList, err := data_manage.GetSmmIndexDataListNoPage(condition, pars)
+			if err != nil {
+				br.Msg = "获取指标列表失败"
+				br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+				return
+			}
+
+			for _, v := range indexList {
+				codeArr = append(codeArr, v.IndexCode)
+			}
+
+			noUseCodeArr := strings.Split(edbCode, ",")
+
+			for _, code := range codeArr {
+				// 检查code是否在noUseCodeArr数组中
+				if !utils.ArrContainsStr(noUseCodeArr, code) {
+					// 如果不在,将其添加到结果数组中
+					edbCodeArr = append(edbCodeArr, code)
+				}
+			}
+		} else {
+			// 有勾选,不查询
+			codeArr = strings.Split(selectCode, ",")
+
+			noUseCodeArr := strings.Split(edbCode, ",")
+
+			for _, code := range codeArr {
+				// 检查code是否在noUseCodeArr数组中
+				if !utils.ArrContainsStr(noUseCodeArr, code) {
+					// 如果不在,将其添加到结果数组中
+					edbCodeArr = append(edbCodeArr, code)
+				}
+			}
+		}
+	} else {
+		//未勾选全选EdbCode就是需要的code
+		edbCodeArr = strings.Split(edbCode, ",")
+	}
+
+	if len(edbCodeArr) > 30 {
+		br.Msg = "最多只能选择30个指标"
+		return
+	}
+
+	if len(edbCodeArr) <= 0 {
+		br.Msg = "无符合指标或指标代码错误"
+		return
+	}
+
+	indexList, err := data_manage.GetEdbInfoByEdbCodeList(utils.DATA_SOURCE_YS, edbCodeArr)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "校验指标是否存在失败"
+		br.ErrMsg = "校验指标是否存在失败,Err:" + err.Error()
+		return
+	}
+	var existEdbCodeArr []string
+	var existClassifyId []int
+	var existIndexId []int
+
+	for _, indexItem := range indexList {
+		for _, ev := range edbCodeArr {
+			if strings.Contains(indexItem.EdbCode, ev) {
+				existEdbCodeArr = append(existEdbCodeArr, ev)
+				existClassifyId = append(existClassifyId, indexItem.ClassifyId)
+				existIndexId = append(existIndexId, indexItem.EdbInfoId)
+			}
+		}
+	}
+
+	resp := new(data_manage.EdbInfoSmmExistCheckResp)
+	if len(indexList) > 0 {
+		resp.IndexExist = true
+	}
+	if len(existEdbCodeArr) == len(edbCodeArr) {
+		resp.ExistAll = true
+	}
+	resp.ExistEdbCodeArr = existEdbCodeArr
+	resp.ExistClassifyId = existClassifyId
+	resp.ExistIndexId = existIndexId
+	resp.ExistEdbInfo = indexList
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbInfoSearch
+// @Title 新增指标-查询指标信息接口-smm
+// @Description 新增指标-查询指标信息接口-smm
+// @Param   Source   query   int  true       "来源:1:同花顺,2:wind,3:彭博"
+// @Param   SubSource   query   int  true       "子数据来源:0:经济数据库,1:日期序列"
+// @Param   EdbCode   query   string  false       "指标编码/指标代码"
+// @Param   StockCode   query   string  false       "证券代码"
+// @Success 200 {object} data_manage.EdbInfoSearchResp
+// @router /edb_info/smm/search [get]
+func (this *EdbInfoController) EdbInfoSmmSearch() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	selectAll, err := this.GetBool("SelectAll", false)
+	if err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	types := this.GetString("Types")
+	frequency := this.GetString("Frequency")
+	dataState := this.GetString("DataState")
+	edbCode := this.GetString("EdbCode")
+	edbCode = strings.Trim(edbCode, "\t")
+	edbCode = strings.Trim(edbCode, " ")
+	edbCode = strings.Replace(edbCode, "\t", "", -1)
+
+	selectCode := this.GetString("SelectCode")
+	selectCode = strings.Trim(selectCode, "\t")
+	selectCode = strings.Trim(selectCode, " ")
+	selectCode = strings.Replace(selectCode, "\t", "", -1)
+
+	var edbCodeArr []string
+	var codeArr []string
+
+	if selectAll {
+		// 如果勾了列表全选,那么EdbCode传的就是排除的code
+		if selectCode == "" {
+			// 无勾选code,走查询
+			var condition string
+			var pars []interface{}
+
+			if types != "" {
+				typeArr := strings.Split(types, ",")
+				for i, v := range typeArr {
+					typeStr := "type_"
+					typeStr += fmt.Sprintf("%d", i+1)
+					condition += " AND " + typeStr + " =? "
+					pars = append(pars, v)
+				}
+			}
+
+			if dataState != "" {
+				if dataState == "normal" {
+					condition += " AND (data_state = 'normal' OR data_state = '') "
+					pars = append(pars)
+				} else {
+					condition += " AND data_state = ? "
+					pars = append(pars, dataState)
+				}
+			}
+
+			if frequency != "" {
+				condition += " AND frequency = ? "
+				pars = append(pars, frequency)
+			}
+
+			indexList, err := data_manage.GetSmmIndexDataListNoPage(condition, pars)
+			if err != nil {
+				br.Msg = "获取指标列表失败"
+				br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+				return
+			}
+
+			for _, v := range indexList {
+				codeArr = append(codeArr, v.IndexCode)
+			}
+
+			noUseCodeArr := strings.Split(edbCode, ",")
+
+			for _, code := range codeArr {
+				// 检查code是否在noUseCodeArr数组中
+				if !utils.ArrContainsStr(noUseCodeArr, code) {
+					// 如果不在,将其添加到结果数组中
+					edbCodeArr = append(edbCodeArr, code)
+				}
+			}
+		} else {
+			// 有勾选,不查询
+			codeArr = strings.Split(selectCode, ",")
+
+			noUseCodeArr := strings.Split(edbCode, ",")
+
+			for _, code := range codeArr {
+				// 检查code是否在noUseCodeArr数组中
+				if !utils.ArrContainsStr(noUseCodeArr, code) {
+					// 如果不在,将其添加到结果数组中
+					edbCodeArr = append(edbCodeArr, code)
+				}
+			}
+		}
+	} else {
+		//未勾选全选EdbCode就是需要的code
+		edbCodeArr = strings.Split(edbCode, ",")
+	}
+
+	if len(edbCodeArr) > 30 {
+		br.Msg = "最多只能选择30个指标"
+		return
+	}
+
+	if len(edbCodeArr) <= 0 {
+		br.Msg = "无符合指标或指标代码错误"
+		return
+	}
+
+	edbCodeStr := ""
+	for i, _ := range edbCodeArr {
+		edbCodeStr += "'" + edbCodeArr[i] + "'" + ","
+	}
+	edbCodeStr = strings.Trim(edbCodeStr, ",")
+	smmInfoList, err := data_manage.GetBaseFromSmmIndexByIndexCodes(edbCodeStr)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取有色指标详情失败,Err:" + err.Error()
+		return
+	}
+
+	smmInfoMap := make(map[string]*data_manage.BaseFromSmmIndex)
+	for _, v := range smmInfoList {
+		smmInfoMap[v.IndexCode] = v
+	}
+
+	searchItemList := make([]*data_manage.EdbInfoSearch, 0)
+
+	resp := new(data_manage.EdbInfoSearchResp)
+	needAddCodeArr := make([]string, 0)
+	noNeedAddCodeMap := make(map[string]string, 0)
+
+	for _, edbCode := range edbCodeArr {
+		dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_YS, utils.DATA_SUB_SOURCE_EDB, utils.EDB_DATA_LIMIT)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取Ys已存在信息失败,Err:" + err.Error()
+			return
+		}
+
+		fmt.Println("dataItems:", len(dataItems))
+		if len(dataItems) > 0 {
+			searchItem := new(data_manage.EdbInfoSearch)
+			searchItem.EdbCode = edbCode
+			minDate, maxDate, err := data_manage.GetEdbDataYsMaxAndMinDate(edbCode)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取YS日期信息失败,Err:" + err.Error()
+				return
+			}
+			searchItem.DataList = dataItems
+			searchItem.StartDate = minDate
+			searchItem.EndDate = maxDate
+			searchItem.Frequency = smmInfoMap[edbCode].Frequency
+			searchItem.Unit = smmInfoMap[edbCode].Unit
+			searchItem.EdbName = smmInfoMap[edbCode].IndexName
+			searchItem.EdbCode = smmInfoMap[edbCode].IndexCode
+
+			searchItemList = append(searchItemList, searchItem)
+
+			noNeedAddCodeMap[edbCode] = edbCode
+		} else {
+			// 把需要新加的code添加到needAddCodeArr数组中,一起批量请求
+			needAddCodeArr = append(needAddCodeArr, edbCode)
+		}
+	}
+	if len(needAddCodeArr) > 0 {
+		edbCode = strings.Join(needAddCodeArr, ",")
+		respItem, err := data.AddEdbData(utils.DATA_SOURCE_YS, edbCode)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+		if respItem.Ret != 200 {
+			if respItem.Ret == 421 {
+				br.Msg = "该渠道已超过添加上限"
+			} else if respItem.Ret == 4052 {
+				br.Msg = "该指标已下架"
+			} else {
+				br.Msg = "未搜索到该指标"
+			}
+			br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + edbCode
+			return
+		}
+	}
+
+	for _, smmInfo := range smmInfoList {
+		if smmInfo != nil {
+			if _, ok := noNeedAddCodeMap[smmInfo.IndexCode]; !ok {
+				searchItem := new(data_manage.EdbInfoSearch)
+				minDate, maxDate, err := data_manage.GetEdbDataYsMaxAndMinDate(smmInfo.IndexCode)
+				if err != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取YS日期信息失败,Err:" + err.Error()
+					return
+				}
+				searchItem.StartDate = minDate
+				searchItem.EndDate = maxDate
+				searchItem.Frequency = smmInfo.Frequency
+				searchItem.Unit = smmInfo.Unit
+				searchItem.EdbName = smmInfo.IndexName
+				searchItem.EdbCode = smmInfo.IndexCode
+				dataList, err := data_manage.GetEdbDataAllByEdbCode(smmInfo.IndexCode, utils.DATA_SOURCE_YS, utils.DATA_SUB_SOURCE_EDB, utils.EDB_DATA_LIMIT)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取数据失败,GetEdbDataAllByEdbCode Err:" + err.Error()
+					return
+				}
+				searchItem.DataList = dataList
+
+				searchItemList = append(searchItemList, searchItem)
+			}
+		}
+	}
+
+	resp.Status = 2
+	resp.StockSearchList = searchItemList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// SmmEdbInfoBatchAdd
+// @Title 指标批量保存接口-smm
+// @Description 指标批量保存接口-smm
+// @Param	request	body data_manage.BatchAddEdbInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /edb_info/smm/batch/add [post]
+func (this *EdbInfoController) SmmEdbInfoBatchAdd() {
+	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
+	}
+	deleteCache := true
+	cacheKey := "CACHE_EDB_INFO_BATCH_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(this.Ctx.Input.RequestBody)
+		return
+	}
+	var req data_manage.BatchAddEdbInfoReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	resp := new(data_manage.AddEdbInfoResp)
+
+	var edbNames string
+	for _, v := range req.BatchList {
+		edbNames += "'" + v.EdbName + "',"
+	}
+	edbNames = strings.Trim(edbNames, ",")
+	infoList, err := data_manage.GetEdbInfoByNames(edbNames)
+	if err != nil {
+		br.Msg = "查询指标名称重复错误!"
+		br.ErrMsg = "GetEdbInfoByNames,Err:" + err.Error()
+		return
+	}
+	if len(infoList) > 0 {
+		for _, v := range infoList {
+			resp.ExistEdbName = append(resp.ExistEdbName, v.EdbName)
+		}
+		br.Data = resp
+		br.Msg = "指标名称重复!"
+		br.ErrMsg = "指标名称重复"
+		return
+	}
+
+	for k, v := range req.BatchList {
+		v.EdbName = strings.Trim(v.EdbName, " ")
+		v.EdbCode = strings.Trim(v.EdbCode, " ")
+
+		if v.Source <= 0 {
+			br.Msg = "无效的数据来源"
+			return
+		}
+
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不能为空"
+			return
+		}
+
+		if v.EdbName == "" {
+			br.Msg = "指标名称不能为空"
+			return
+		}
+
+		if v.Frequency == "" {
+			br.Msg = "频率不能为空"
+			return
+		}
+
+		if v.ClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			return
+		}
+
+		edbInfoItem := new(data_manage.EdbInfo)
+		edbInfoItem.Source = v.Source
+		edbInfoItem.SourceName = "SMM"
+		edbInfoItem.EdbCode = v.EdbCode
+		edbInfoItem.SubSource = 0
+		edbInfoItem.SubSourceName = ""
+		edbInfoItem.EdbName = v.EdbName
+		edbInfoItem.Frequency = v.Frequency
+		edbInfoItem.Unit = v.Unit
+		edbInfoItem.ClassifyId = v.ClassifyId
+		edbInfoItem.SysUserId = sysUser.AdminId
+		edbInfoItem.SysUserRealName = sysUser.RealName
+		edbInfoItem.IndicatorCode = ""
+		edbInfoItem.StockCode = ""
+
+		// 指标入库
+		edbInfo, err, errMsg, isSendEmail := data.EdbInfoWsdAdd(edbInfoItem)
+		if err != nil {
+			br.Msg = "保存失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
+			br.ErrMsg = err.Error()
+			br.IsSendEmail = isSendEmail
+			return
+		}
+		//新增操作日志
+		{
+			edbLog := new(data_manage.EdbInfoLog)
+			edbLog.EdbInfoId = edbInfo.EdbInfoId
+			edbLog.SourceName = edbInfo.SourceName
+			edbLog.Source = edbInfo.Source
+			edbLog.EdbCode = edbInfo.EdbCode
+			edbLog.EdbName = edbInfo.EdbName
+			edbLog.ClassifyId = edbInfo.ClassifyId
+			edbLog.SysUserId = sysUser.AdminId
+			edbLog.SysUserRealName = sysUser.RealName
+			edbLog.CreateTime = time.Now()
+			edbLog.Content = string(this.Ctx.Input.RequestBody)
+			edbLog.Status = "新增指标"
+			edbLog.Method = this.Ctx.Input.URI()
+			go data_manage.AddEdbInfoLog(edbLog)
+		}
+
+		if k <= 0 {
+			resp.EdbInfoId = edbInfo.EdbInfoId
+			resp.UniqueCode = edbInfo.UniqueCode
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}

+ 19 - 7
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 {
@@ -996,7 +1008,7 @@ func (this *ChartInfoController) CalculateBatchReset() {
 	//}
 
 	// 重新计算
-	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, true)
+	err, isAsync := data.EdbInfoRefreshAllFromBaseV2(edbInfoId, true, false)
 	if err != nil {
 		fmt.Println(edbInfoId, "RefreshEdbCalculateData err", time.Now())
 		br.Msg = "重新计算失败"
@@ -1418,7 +1430,7 @@ func (this *EdbInfoController) QueryEdbDataTable() {
 		return
 	}
 
-	tableName := data_manage.GetEdbDataTableName(edbInfo.Source)
+	tableName := data_manage.GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
 
 	columnList := []map[string]string{
 		{

+ 195 - 24
controllers/data_manage/excel/excel_info.go

@@ -60,7 +60,7 @@ func (c *ExcelInfoController) Add() {
 	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
 		deleteCache = false
 		br.Msg = "系统处理中,请稍后重试!"
-		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		br.ErrMsg = "系统处理中,请稍后重试!"
 		return
 	}
 	var req request.AddExcelInfoReq
@@ -181,9 +181,12 @@ func (c *ExcelInfoController) Add() {
 			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
 			return
 		}
-		newResult, tmpErr := excel2.GetMixedTableCellData(result.Data)
-		if tmpErr != nil {
+		newResult, err, errMsg := excel2.GetMixedTableCellData(result)
+		if err != nil {
 			br.Msg = "获取失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
 			br.ErrMsg = "获取最新的数据失败,Err:" + err.Error()
 			return
 		}
@@ -348,7 +351,7 @@ func (c *ExcelInfoController) List() {
 	}
 	if keyword != "" {
 		condition += ` AND  ( excel_name LIKE ? )`
-		pars = append(pars, `%`+keyword+`%`)
+		pars = utils.GetLikeKeywordPars(pars, keyword, 1)
 	}
 	if adminId > 0 {
 		condition += " AND sys_user_id = ? "
@@ -491,7 +494,7 @@ func (c *ExcelInfoController) Edit() {
 	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
 		deleteCache = false
 		br.Msg = "系统处理中,请稍后重试!"
-		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		br.ErrMsg = "系统处理中,请稍后重试!"
 		return
 	}
 	req.ExcelName = strings.Trim(req.ExcelName, " ")
@@ -581,7 +584,7 @@ func (c *ExcelInfoController) Edit() {
 	edbInfoIdList := make([]int, 0)
 	content := req.Content
 	switch excelInfo.Source {
-	case 2: // 自定义表格
+	case utils.TIME_TABLE: // 自定义表格
 		jsonStrByte, err := json.Marshal(req.TableData)
 		if err != nil {
 			br.Msg = "自定义表格数据获取失败"
@@ -609,7 +612,7 @@ func (c *ExcelInfoController) Edit() {
 			return
 		}
 		content = string(contentByte)
-	case 3: // 混合表格
+	case utils.MIXED_TABLE: // 混合表格
 		contentByte, err := json.Marshal(req.TableData)
 		if err != nil {
 			br.Msg = "混合表格数据获取失败"
@@ -625,9 +628,12 @@ func (c *ExcelInfoController) Edit() {
 			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
 			return
 		}
-		newResult, tmpErr := excel2.GetMixedTableCellData(result.Data)
-		if tmpErr != nil {
+		newResult, err, errMsg := excel2.GetMixedTableCellData(result)
+		if err != nil {
 			br.Msg = "获取失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
 			br.ErrMsg = "获取最新的数据失败,Err:" + err.Error()
 			return
 		}
@@ -856,7 +862,7 @@ func (c *ExcelInfoController) Move() {
 		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
 		if firstClassify != nil && firstClassify.Sort == 0 {
 			updateSortStr := ` sort + 1 `
-			_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId-1, updateSortStr)
+			_ = excel3.UpdateExcelInfoSortByClassifyId(firstClassify.ExcelClassifyId, 0, firstClassify.ExcelInfoId+1, updateSortStr)
 		}
 
 		// 变更表格在当前分类下的排序
@@ -1185,7 +1191,7 @@ func (c *ExcelInfoController) GetExcelTableData() {
 
 	var tableData excel.TableData
 	switch excelInfo.Source {
-	case 1:
+	case utils.EXCEL_DEFAULT:
 		luckySheetData, err := excel.GetLuckySheetData(excelInfo.Content)
 		if err != nil {
 			br.Msg = "获取失败"
@@ -1198,7 +1204,7 @@ func (c *ExcelInfoController) GetExcelTableData() {
 			br.ErrMsg = "转换成table失败,Err:" + err.Error()
 			return
 		}
-	case 2:
+	case utils.TIME_TABLE:
 		var tableDataConfig excel2.TableDataConfig
 		err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig)
 		if err != nil {
@@ -1218,7 +1224,7 @@ func (c *ExcelInfoController) GetExcelTableData() {
 			br.ErrMsg = "转换成table失败,Err:" + err.Error()
 			return
 		}
-	case 3:
+	case utils.MIXED_TABLE:
 		var result request.MixedTableReq
 		err = json.Unmarshal([]byte(excelInfo.Content), &result)
 		if err != nil {
@@ -1226,9 +1232,12 @@ func (c *ExcelInfoController) GetExcelTableData() {
 			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
 			return
 		}
-		newResult, tmpErr := excel2.GetMixedTableCellData(result.Data)
-		if tmpErr != nil {
+		newResult, err, errMsg := excel2.GetMixedTableCellData(result)
+		if err != nil {
 			br.Msg = "获取失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
 			br.ErrMsg = "获取最新的数据失败,Err:" + err.Error()
 			return
 		}
@@ -1561,7 +1570,7 @@ func (c *ExcelInfoController) GetFutureDateData() {
 	{
 		switch baseEdbInfo.EdbInfoType {
 		case 0:
-			firstEdbDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.EdbInfoId, req.StartDate, ``)
+			firstEdbDataList, err = data_manage.GetEdbDataList(baseEdbInfo.Source, baseEdbInfo.SubSource, baseEdbInfo.EdbInfoId, req.StartDate, ``)
 		case 1:
 			_, firstEdbDataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(baseEdbInfo.EdbInfoId, req.StartDate, ``, false)
 		default:
@@ -1795,6 +1804,9 @@ func (c *ExcelInfoController) GetHistoryDateData() {
 func (c *ExcelInfoController) Refresh() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
 		c.Data["json"] = br
 		c.ServeJSON()
 	}()
@@ -1835,7 +1847,7 @@ func (c *ExcelInfoController) Refresh() {
 	}
 
 	// 数据刷新(只有自定义表格有刷新)
-	if excelDetail.Source == 2 {
+	if excelDetail.Source == utils.TIME_TABLE {
 		jsonStrByte, err := json.Marshal(excelDetail.TableData)
 		if err != nil {
 			br.Msg = "自定义表格数据获取失败"
@@ -1851,7 +1863,7 @@ func (c *ExcelInfoController) Refresh() {
 		}
 
 		if len(tableData.EdbInfoIdList) > 0 {
-			err, _ = data.EdbInfoRefreshAllFromBaseV3(tableData.EdbInfoIdList, false, true)
+			err, _ = data.EdbInfoRefreshAllFromBaseV3(tableData.EdbInfoIdList, false, true, false)
 			if err != nil {
 				br.Msg = "刷新失败"
 				br.ErrMsg = "刷新失败,Err:" + err.Error()
@@ -1860,6 +1872,48 @@ func (c *ExcelInfoController) Refresh() {
 		}
 	}
 
+	// 数据刷新-混合表格
+	if excelDetail.Source == utils.MIXED_TABLE {
+		jsonByte, e := json.Marshal(excelDetail.TableData)
+		if e != nil {
+			br.Msg = "刷新失败"
+			br.ErrMsg = "JSON格式化混合表格数据失败, Err: " + e.Error()
+			return
+		}
+		var tableData request.MixedTableReq
+		if e = json.Unmarshal(jsonByte, &tableData); e != nil {
+			br.Msg = "刷新失败"
+			br.ErrMsg = "解析混合表格数据失败, Err: " + e.Error()
+			return
+		}
+		edbInfoIds := make([]int, 0)
+		edbInfoIdExist := make(map[int]bool)
+		if len(tableData.Data) > 0 {
+			for _, t := range tableData.Data {
+				for _, v := range t {
+					if v.EdbInfoId > 0 && !edbInfoIdExist[v.EdbInfoId] {
+						edbInfoIdExist[v.EdbInfoId] = true
+						edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+					}
+				}
+			}
+		}
+		if len(edbInfoIds) > 0 {
+			e, _ = data.EdbInfoRefreshAllFromBaseV3(edbInfoIds, false, true, false)
+			if e != nil {
+				br.Msg = "刷新失败"
+				br.ErrMsg = "刷新混合表格数据失败, Err: " + err.Error()
+				return
+			}
+		}
+	}
+
+	// 清除缓存
+	key := utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + excelDetail.UniqueCode
+	if utils.Re == nil {
+		_ = utils.Rc.Delete(key)
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "刷新成功"
@@ -1921,9 +1975,9 @@ func (c *ExcelInfoController) Download() {
 
 	var tableData excel.TableData
 	switch excelInfo.Source {
-	case 1:
+	case utils.EXCEL_DEFAULT:
 		br.Msg = "表格类型异常"
-	case 2: // 自定义表格
+	case utils.TIME_TABLE: // 自定义表格
 		var tableDataConfig excel2.TableDataConfig
 		err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig)
 		if err != nil {
@@ -1943,7 +1997,7 @@ func (c *ExcelInfoController) Download() {
 			br.ErrMsg = "转换成table失败,Err:" + err.Error()
 			return
 		}
-	case 3: // 混合表格
+	case utils.MIXED_TABLE: // 混合表格
 		var result request.MixedTableReq
 		err = json.Unmarshal([]byte(excelInfo.Content), &result)
 		if err != nil {
@@ -1951,9 +2005,12 @@ func (c *ExcelInfoController) Download() {
 			br.ErrMsg = "表格json转结构体失败,Err:" + err.Error()
 			return
 		}
-		newResult, tmpErr := excel2.GetMixedTableCellData(result.Data)
-		if tmpErr != nil {
+		newResult, err, errMsg := excel2.GetMixedTableCellData(result)
+		if err != nil {
 			br.Msg = "获取失败"
+			if errMsg != `` {
+				br.Msg = errMsg
+			}
 			br.ErrMsg = "获取最新的数据失败,Err:" + err.Error()
 			return
 		}
@@ -2018,7 +2075,7 @@ func (c *ExcelInfoController) Copy() {
 	cacheKey := "CACHE_TABLE_INFO_EDIT_" + strconv.Itoa(req.ExcelInfoId)
 	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
 		br.Msg = "系统处理中,请稍后重试!"
-		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		br.ErrMsg = "系统处理中,请稍后重试!"
 		return
 	}
 	defer func() {
@@ -2232,3 +2289,117 @@ func (this *ExcelInfoController) MarkEditStatus() {
 	br.Msg = msg
 	br.Data = data
 }
+
+// BatchRefresh
+// @Title 批量刷新表格接口
+// @Description 批量刷新图表接口
+// @Param	request	body excel3.BatchRefreshExcelReq true "type json string"
+// @Success Ret=200 刷新成功
+// @router /excel_info/table/batch_refresh [post]
+func (this *ExcelInfoController) BatchRefresh() {
+	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 excel3.BatchRefreshExcelReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if len(req.ExcelCodes) == 0 {
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "刷新成功"
+		return
+	}
+
+	// 获取表格关联的指标IDs
+	edbIds, e := excel2.GetEdbIdsFromExcelCodes(req.ExcelCodes)
+	if e != nil {
+		br.Msg = "刷新失败"
+		br.ErrMsg = "获取表格关联的指标IDs失败, Err: " + e.Error()
+		return
+	}
+
+	redisKey := data.GetBatchChartRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+	refreshKeys := make([]string, 0)
+	for _, v := range req.ExcelCodes {
+		refreshKeys = append(refreshKeys, fmt.Sprint(utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL, v))
+	}
+
+	// 刷新相关指标
+	syncing, e := data.BatchRefreshEdbByEdbIds(edbIds, redisKey, refreshKeys)
+	if e != nil {
+		br.Msg = "刷新失败"
+		br.ErrMsg = "刷新表格关联指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "刷新成功"
+	if syncing {
+		br.Msg = "表格关联指标较多,请10分钟后刷新页面查看最新数据"
+	}
+	br.Ret = 200
+	br.Success = true
+}
+
+// GetBatchChartRefreshResult
+// @Title 获取批量刷新表格结果
+// @Description 获取批量刷新表格结果
+// @Param	request	body excel3.BatchRefreshExcelReq true "type json string"
+// @Success Ret=200 刷新成功
+// @router /excel_info/table/batch_refresh/result [post]
+func (this *ExcelInfoController) GetBatchChartRefreshResult() {
+	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
+	}
+	var req excel3.BatchRefreshExcelReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	// 校验缓存是否存在, 存在说明还在刷新中
+	result := true
+	redisKey := excel2.GetExcelEdbBatchRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+	if redisKey != `` {
+		// 如果找到了key,那么就是还在更新中
+		ok := utils.Rc.IsExist(redisKey)
+		if ok {
+			result = false
+		}
+	}
+
+	resp := struct {
+		RefreshResult bool `description:"刷新结果"`
+	}{
+		RefreshResult: result,
+	}
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+}

+ 237 - 0
controllers/data_manage/excel/mixed_table.go

@@ -0,0 +1,237 @@
+package excel
+
+import (
+	"encoding/json"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/services/data"
+	excel2 "eta/eta_api/services/data/excel"
+	"strconv"
+)
+
+// GetSystemDate
+// @Title 获取系统日期(包含计算日期)
+// @Description 获取系统日期(包含计算日期)
+// @Param	request	body request.MixedTableCellDataReq true "type json string"
+// @router /excel_info/get_system_date [post]
+func (c *ExcelInfoController) GetSystemDate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.MixedTableCellDataReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	date, err, errMsg := excel2.HandleDate(req.DataTimeType, req.Value)
+	if err != nil {
+		br.Msg = "获取系统日期失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "获取系统日期失败,Err:" + err.Error()
+		return
+	}
+
+	type resp struct {
+		Date string
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取系统日期成功"
+	br.Data = resp{
+		Date: date,
+	}
+}
+
+// CalculateData
+// @Title 公式计算(混合表格)
+// @Description 公式计算(混合表格)
+// @Param	request	body request.CalculateConf true "type json string"
+// @router /excel_info/mixed/calculate [post]
+func (c *ExcelInfoController) CalculateData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.CalculateConf
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	edbInfo, err := data_manage.GetEdbInfoById(req.EdbInfoId)
+	if err != nil {
+		br.Msg = "获取指标信息失败!"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	dataList := make([]*data_manage.EdbDataList, 0)
+	switch edbInfo.EdbInfoType {
+	case 0:
+		dataList, _ = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``)
+	case 1:
+		_, dataList, _, _, _, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false)
+	default:
+		br.Msg = "指标类型异常!"
+		br.ErrMsg = "指标类型异常,Err:" + strconv.Itoa(edbInfo.EdbInfoType)
+		return
+	}
+
+	//获取所有数据,计算所有数据
+	//获取部分数据,计算部分数据
+	// BaseCalculate 数据计算的结构体
+	type BaseCalculate struct {
+		DataList      []*data_manage.EdbDataList
+		Frequency     string `description:"需要转换的频度"`
+		Formula       interface{}
+		Calendar      string `description:"公历/农历"`
+		MoveType      int    `description:"移动方式:1:领先(默认),2:滞后"`
+		MoveFrequency string `description:"移动频度"`
+		FromFrequency string `description:"来源的频度"`
+		Source        int    `description:"1:累计值转月;2:累计值转季;3:同比值;4:同差值;5:N数值移动平均数计算;6:环比值;7:环差值;8:升频;9:降频;10:时间移位;11:超季节性;12:年化;13:累计值;14:累计值年初至今;15:指数修匀;16:日均值"`
+	}
+
+	req2 := &BaseCalculate{
+		DataList:      dataList,
+		Frequency:     req.Frequency,
+		Formula:       req.Formula,
+		Calendar:      req.Calendar,
+		MoveType:      req.MoveType,
+		MoveFrequency: req.MoveFrequency,
+		FromFrequency: edbInfo.Frequency,
+		Source:        req.Source,
+	}
+
+	// 调用指标库去更新
+	reqJson, tmpErr := json.Marshal(req2)
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	respItem, tmpErr := data.BaseCalculate(string(reqJson))
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	if respItem.Ret != 200 {
+		br.Msg = respItem.Msg
+		br.ErrMsg = respItem.ErrMsg
+		return
+	}
+
+	// 数据处理成需要返回的样式
+	num := 5
+	lenDate := len(respItem.Data.DateList)
+	if lenDate < 5 {
+		num = lenDate
+	}
+
+	var currDate string // 当前日期
+	dataListResp := make([]*data_manage.EdbDataList, 0)
+
+	if req.DataTime == `` {
+		for i := 1; i <= num; i++ {
+			date := respItem.Data.DateList[lenDate-i]
+			val, ok := respItem.Data.DataMap[date]
+			if !ok {
+				continue
+			}
+
+			dataListResp = append(dataListResp, &data_manage.EdbDataList{
+				Value:    val,
+				DataTime: date,
+			})
+		}
+	} else {
+		if val, ok := respItem.Data.DataMap[req.DataTime]; ok {
+			for i, tmpDate := range respItem.Data.DateList {
+				if tmpDate == req.DataTime {
+					if i+3 <= lenDate {
+						t1Date := respItem.Data.DateList[i+2]
+						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
+							// 当前日期
+							dataListResp = append(dataListResp, &data_manage.EdbDataList{
+								Value:    tmpVal,
+								DataTime: t1Date,
+							})
+						}
+					}
+
+					if i+2 <= lenDate {
+						t1Date := respItem.Data.DateList[i+1]
+						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
+							// 当前日期
+							dataListResp = append(dataListResp, &data_manage.EdbDataList{
+								Value:    tmpVal,
+								DataTime: t1Date,
+							})
+						}
+					}
+
+					// 当前日期
+					dataListResp = append(dataListResp, &data_manage.EdbDataList{
+						Value:    val,
+						DataTime: req.DataTime,
+					})
+					if i >= 1 {
+						t1Date := respItem.Data.DateList[i-1]
+						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
+							// 当前日期
+							dataListResp = append(dataListResp, &data_manage.EdbDataList{
+								Value:    tmpVal,
+								DataTime: t1Date,
+							})
+						}
+					}
+					if i >= 2 {
+						t1Date := respItem.Data.DateList[i-2]
+						if tmpVal, ok2 := respItem.Data.DataMap[t1Date]; ok2 {
+							// 当前日期
+							dataListResp = append(dataListResp, &data_manage.EdbDataList{
+								Value:    tmpVal,
+								DataTime: t1Date,
+							})
+						}
+					}
+				}
+			}
+		}
+	}
+	resp := data_manage.BeforeAndAfterDateDataResp{
+		List: dataListResp,
+		Date: currDate,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "计算成功"
+	br.Data = resp
+}

+ 2 - 28
controllers/data_manage/future_good/future_good_chart_classify.go

@@ -56,7 +56,7 @@ func (this *FutureGoodChartClassifyController) ChartClassifyList() {
 			return
 		}
 		// 移除没有权限的图表
-		allNodes := handleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
+		allNodes := data.HandleNoPermissionChart(resp.AllNodes, noPermissionChartIdMap)
 		resp.AllNodes = allNodes
 
 		br.Ret = 200
@@ -97,7 +97,7 @@ func (this *FutureGoodChartClassifyController) ChartClassifyList() {
 	}
 
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(rootList, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(rootList, noPermissionChartIdMap)
 	resp.AllNodes = allNodes
 
 	br.Ret = 200
@@ -139,32 +139,6 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	return
 }
 
-// handleNoPermissionChart 图表列表返回,将没有权限的图表移除
-func handleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermissionChartIdMap map[int]bool) (newAllNodes []*data_manage.ChartClassifyItems) {
-	// 移除没有权限的图表
-	newAllNodes = make([]*data_manage.ChartClassifyItems, 0)
-	for _, node := range allNodes {
-		// 二级分类
-		tmpNodeInfo := *node
-		tmpNodeList := make([]*data_manage.ChartClassifyItems, 0)
-
-		if node.Children != nil {
-			for _, chartInfo := range node.Children {
-				// 如果指标不可见,那么就不返回该指标
-				if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-					continue
-				}
-				tmpNodeList = append(tmpNodeList, chartInfo)
-			}
-		}
-
-		tmpNodeInfo.Children = tmpNodeList
-		newAllNodes = append(newAllNodes, &tmpNodeInfo)
-	}
-
-	return
-}
-
 // ChartClassifyItems
 // @Title 获取所有商品价格图表分类接口-不包含图表
 // @Description 获取所有商品价格图表分类接口-不包含图表

+ 3 - 3
controllers/data_manage/future_good/future_good_chart_info.go

@@ -1818,14 +1818,14 @@ func (this *FutureGoodChartInfoController) ChartInfoEdbInfoDetail() {
 
 	switch edbInfo.EdbInfoType {
 	case 0: //普通源指标
-		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfoId, startDateReal, endDate)
+		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDateReal, endDate)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.Msg = "获取失败,Err:" + err.Error()
 			return
 		}
 		//查询区间内最大最小值
-		minData, maxData, err = data_manage.GetEdbDataListMinAndMax(edbInfo.Source, edbInfoId, startDateReal, endDate)
+		minData, maxData, err = data_manage.GetEdbDataListMinAndMax(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDateReal, endDate)
 		if err != nil {
 			br.Msg = "获取失败"
 			br.Msg = "获取指标最新的最大最小值失败,Err:" + err.Error()
@@ -1842,7 +1842,7 @@ func (this *FutureGoodChartInfoController) ChartInfoEdbInfoDetail() {
 		// 有预测数据,且为普通的预测指标
 		if len(dataList) > 0 && edbInfo.EdbInfoType == 0 {
 			//查询区间内最大最小值
-			minData, maxData, err = data_manage.GetEdbDataListMinAndMax(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, startDateReal, endDate)
+			minData, maxData, err = data_manage.GetEdbDataListMinAndMax(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, sourceEdbInfoItem.EdbInfoId, startDateReal, endDate)
 			if err != nil {
 				br.Msg = "获取失败"
 				br.Msg = "获取指标最新的最大最小值失败,Err:" + err.Error()

+ 1 - 1
controllers/data_manage/future_good/future_good_edb_info.go

@@ -42,7 +42,7 @@ func (this *FutureGoodEdbInfoController) FutureGoodEdbInfoList() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += ` AND ( future_good_edb_name like ? or future_good_edb_code like ? ) `
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	// @Param   RegionType   query   string  false       "交易所来源,海外还是国内"

+ 1 - 27
controllers/data_manage/line_equation/line_chart_classify.go

@@ -101,7 +101,7 @@ func (this *LineEquationChartClassifyController) ChartClassifyList() {
 	}
 
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(rootList, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(rootList, noPermissionChartIdMap)
 	resp.AllNodes = allNodes
 
 	br.Ret = 200
@@ -144,32 +144,6 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	return
 }
 
-// handleNoPermissionChart 图表列表返回,将没有权限的图表移除
-func handleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermissionChartIdMap map[int]bool) (newAllNodes []*data_manage.ChartClassifyItems) {
-	// 移除没有权限的图表
-	newAllNodes = make([]*data_manage.ChartClassifyItems, 0)
-	for _, node := range allNodes {
-		// 二级分类
-		tmpNodeInfo := *node
-		tmpNodeList := make([]*data_manage.ChartClassifyItems, 0)
-
-		if node.Children != nil {
-			for _, chartInfo := range node.Children {
-				// 如果指标不可见,那么就不返回该指标
-				if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-					continue
-				}
-				tmpNodeList = append(tmpNodeList, chartInfo)
-			}
-		}
-
-		tmpNodeInfo.Children = tmpNodeList
-		newAllNodes = append(newAllNodes, &tmpNodeInfo)
-	}
-
-	return
-}
-
 // ChartClassifyItems
 // @Title 获取所有拟合方程图表分类接口-不包含图表
 // @Description 获取所有拟合方程图表分类接口-不包含图表

+ 1 - 27
controllers/data_manage/line_feature/classify.go

@@ -101,7 +101,7 @@ func (this *LineFeaturesChartClassifyController) ChartClassifyList() {
 	}
 
 	// 移除没有权限的图表
-	allNodes := handleNoPermissionChart(rootList, noPermissionChartIdMap)
+	allNodes := data.HandleNoPermissionChart(rootList, noPermissionChartIdMap)
 	resp.AllNodes = allNodes
 
 	br.Ret = 200
@@ -144,32 +144,6 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	return
 }
 
-// handleNoPermissionChart 图表列表返回,将没有权限的图表移除
-func handleNoPermissionChart(allNodes []*data_manage.ChartClassifyItems, noPermissionChartIdMap map[int]bool) (newAllNodes []*data_manage.ChartClassifyItems) {
-	// 移除没有权限的图表
-	newAllNodes = make([]*data_manage.ChartClassifyItems, 0)
-	for _, node := range allNodes {
-		// 二级分类
-		tmpNodeInfo := *node
-		tmpNodeList := make([]*data_manage.ChartClassifyItems, 0)
-
-		if node.Children != nil {
-			for _, chartInfo := range node.Children {
-				// 如果指标不可见,那么就不返回该指标
-				if _, ok := noPermissionChartIdMap[chartInfo.ChartInfoId]; ok {
-					continue
-				}
-				tmpNodeList = append(tmpNodeList, chartInfo)
-			}
-		}
-
-		tmpNodeInfo.Children = tmpNodeList
-		newAllNodes = append(newAllNodes, &tmpNodeInfo)
-	}
-
-	return
-}
-
 // ChartClassifyItems
 // @Title 获取所有统计特征图表分类接口-不包含图表
 // @Description 获取所有统计特征图表分类接口-不包含图表

+ 75 - 17
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`
 	// 指标显示的语言
@@ -1141,6 +1156,7 @@ func (this *MyChartController) MyChartEdit() {
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
 // @Param   MyChartClassifyId   query   int  true       "我的图表分类id"
 // @Param   MyChartId   query   int  true       "我的图表id"
+// @Param   IsShared   query   bool  false       "是否可分享(如从图库框架请求的属于可分享的)"
 // @Success 200 {object} data_manage.MyChartListResp
 // @router /list [get]
 func (this *MyChartController) MyChartList() {
@@ -1164,6 +1180,7 @@ func (this *MyChartController) MyChartList() {
 	currentIndex, _ := this.GetInt("CurrentIndex")
 
 	myChartId, _ := this.GetInt("MyChartId")
+	isShared, _ := this.GetBool("IsShared")
 
 	var total int
 	page := paging.GetPaging(currentIndex, pageSize, total)
@@ -1180,14 +1197,30 @@ func (this *MyChartController) MyChartList() {
 	var condition string
 	var pars []interface{}
 
-	condition += " AND (a.admin_id=?  or  d.is_public=1)"
-	pars = append(pars, sysUser.AdminId)
-
+	chartAdminId := sysUser.AdminId
 	if myChartClassifyId > 0 {
 		condition += " AND c.my_chart_classify_id=? "
 		pars = append(pars, myChartClassifyId)
+
+		// 可共享
+		if isShared {
+			myClassify, e := data_manage.GetMyChartClassifyByClassifyId(myChartClassifyId)
+			if e != nil {
+				if e.Error() == utils.ErrNoRow() {
+					br.Msg = "分类已被删除, 请刷新页面"
+					return
+				}
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类失败, Err: " + e.Error()
+				return
+			}
+			chartAdminId = myClassify.AdminId
+		}
 	}
 
+	condition += " AND (a.admin_id = ? OR d.is_public = 1)"
+	pars = append(pars, chartAdminId)
+
 	if myChartId > 0 {
 		condition += " AND a.my_chart_id=? "
 		pars = append(pars, myChartId)
@@ -1652,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))
@@ -1673,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
+		}
+
+		if itemsMap[v.AdminId] == nil {
+			itemsMap[v.AdminId] = make([]data_manage.PublicChartClassifyItem, 0)
 		}
-		publicChartClassifyItem := data_manage.PublicChartClassifyItem{
+		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`
 	// 指标显示的语言
@@ -1977,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
@@ -1985,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 = "获取成功"
@@ -2048,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

+ 108 - 56
controllers/data_manage/mysteel_chemical_data.go

@@ -52,23 +52,6 @@ func (this *EdbInfoController) MysteelChemicalClassify() {
 		return
 	}
 
-	baseFromMysteelChemicalIndexMap := make(map[int][]*data_manage.BaseFromMysteelChemicalClassifyItems)
-
-	allBaseFromMysteelChemicalIndex, err := data_manage.GetMysteelChemicalIndexAll()
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
-		return
-	}
-	for _, v := range allBaseFromMysteelChemicalIndex {
-		v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId, "_", v.BaseFromMysteelChemicalIndexId)
-		button := data.GetMysteelChemicalOpButton(sysUser, v.SysUserId)
-		button.AddButton = false //不管有没有权限,指标都是没有添加按钮的
-		v.Button = button
-
-		baseFromMysteelChemicalIndexMap[v.BaseFromMysteelChemicalClassifyId] = append(baseFromMysteelChemicalIndexMap[v.BaseFromMysteelChemicalClassifyId], v)
-	}
-
 	rootChildMap := make(map[int][]*data_manage.BaseFromMysteelChemicalClassifyItems)
 	for _, v := range classifyAll {
 		v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId)
@@ -78,12 +61,6 @@ func (this *EdbInfoController) MysteelChemicalClassify() {
 		v.Button = button
 
 		rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
-		if existItems, ok := baseFromMysteelChemicalIndexMap[v.BaseFromMysteelChemicalClassifyId]; ok {
-			v.Children = existItems
-		} else {
-			items := make([]*data_manage.BaseFromMysteelChemicalClassifyItems, 0)
-			v.Children = items
-		}
 	}
 
 	nodeAll := make([]*data_manage.BaseFromMysteelChemicalClassifyItems, 0)
@@ -107,6 +84,52 @@ func (this *EdbInfoController) MysteelChemicalClassify() {
 	br.Data = nodeAll
 }
 
+// MysteelChemicalIndexList
+// @Title 钢联化工数据指标列表
+// @Description 钢联化工数据指标列表接口
+// @Success 200 {object} data_manage.BaseFromMysteelChemicalIndexResp
+// @router /mysteel_chemical/index/list [get]
+func (this *EdbInfoController) MysteelChemicalIndexList() {
+	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
+	}
+	classifyId, _ := this.GetInt("BaseFromMysteelChemicalClassifyId")
+	if classifyId <= 0 {
+		br.Msg = "请选择正确的分类"
+		return
+	}
+	allBaseFromMysteelChemicalIndex, err := data_manage.GetMysteelChemicalIndexByClassifyId(classifyId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	nodeAll := make([]*data_manage.BaseFromMysteelChemicalClassifyItems, 0)
+	for _, v := range allBaseFromMysteelChemicalIndex {
+		v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId, "_", v.BaseFromMysteelChemicalIndexId)
+		button := data.GetMysteelChemicalOpButton(sysUser, v.SysUserId)
+		button.AddButton = false //不管有没有权限,指标都是没有添加按钮的
+		v.Button = button
+		nodeAll = append(nodeAll, v)
+	}
+	ret := &data_manage.BaseFromMysteelChemicalIndexResp{
+		List: nodeAll,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
 // AddMysteelChemicalClassify
 // @Title 新增分类
 // @Description 新增分类接口
@@ -345,7 +368,7 @@ func (this *EdbInfoController) MysteelChemicalSearch() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += " AND (index_name like ? OR index_code like ?) "
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	list, err := data_manage.GetMysteelChemicalIndex(condition, pars)
@@ -354,9 +377,33 @@ func (this *EdbInfoController) MysteelChemicalSearch() {
 		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
+	classifyIds := make([]int, 0)
 	for _, v := range list {
 		v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId, "_", v.Id)
+		if v.BaseFromMysteelChemicalClassifyId > 0 {
+			classifyIds = append(classifyIds, v.BaseFromMysteelChemicalClassifyId)
+		}
+	}
+	if len(classifyIds) > 0 {
+		// 查询父级分类信息
+		classifyList, e := data_manage.GetBaseFromMysteelChemicalClassifyByIds(classifyIds)
+		if e != nil {
+			br.Msg = "获取目录信息失败"
+			br.ErrMsg = "获取失获取目录信息失败,Err:" + err.Error()
+			return
+		}
+		classifyListMap := make(map[int]int, 0)
+		for _, v := range classifyList {
+			classifyListMap[v.BaseFromMysteelChemicalClassifyId] = v.ParentId
+		}
+		for _, v := range list {
+			v.UniqueCode = fmt.Sprint(v.BaseFromMysteelChemicalClassifyId, "_", v.Id)
+			if p, ok := classifyListMap[v.BaseFromMysteelChemicalClassifyId]; ok {
+				v.ParentClassifyId = p
+			}
+		}
 	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
@@ -417,7 +464,7 @@ func (this *EdbInfoController) MysteelChemicalFrequency() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += " AND (index_name like ? OR index_code like ?) "
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	edbFrequencyList := make([]string, 0)
@@ -518,7 +565,7 @@ func (this *EdbInfoController) MysteelChemicalData() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += " AND (index_name like ? OR index_code like ?) "
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	//获取指标
@@ -599,7 +646,7 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 	keyword := this.GetString("Keyword")
 	if keyword != `` {
 		condition += " AND (index_name like ? OR index_code like ?) "
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	var frequencies []string
@@ -640,7 +687,7 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 		keyword := this.GetString("Keyword")
 		if keyword != `` {
 			tmpCondition += " AND (index_name like ? OR index_code like ?) "
-			tmpPars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+			pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 		}
 		//获取指标
 		secNameList, err := data_manage.GetMysteelChemicalIndex(tmpCondition, tmpPars)
@@ -797,38 +844,43 @@ func (this *EdbClassifyController) AddMysteelChemical() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
-	if req.IndexCode == "" {
-		br.Msg = "请输入指标ID"
-		br.IsSendEmail = false
-		return
-	}
-	if req.BaseFromMysteelChemicalClassifyId <= 0 {
-		br.Msg = "请选择分类"
-		br.IsSendEmail = false
-		return
-	}
+	resp := new(response.AddMysteelChemicalIndexInfoResp)
+	for i, v := range req.List {
+		if v.IndexCode == "" {
+			br.Msg = "请输入指标ID"
+			br.IsSendEmail = false
+			return
+		}
+		if v.BaseFromMysteelChemicalClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			br.IsSendEmail = false
+			return
+		}
 
-	req.IndexCode = utils.TrimStr(req.IndexCode)
-	req.IndexCode = strings.Replace(req.IndexCode, "\t", "", -1)
+		v.IndexCode = utils.TrimStr(v.IndexCode)
+		v.IndexCode = strings.Replace(v.IndexCode, "\t", "", -1)
 
-	//添加指标
-	mysteelChemicalIndexInfo, err, errMsg := data.AddMysteelChemicalIndex(req.BaseFromMysteelChemicalClassifyId, strings.ToUpper(req.IndexCode), req.UpdateWeek, req.UpdateTime, this.SysUser.AdminId, this.SysUser.RealName)
-	if errMsg != `` {
-		br.Msg = errMsg
-		br.ErrMsg = errMsg
-		if err != nil {
-			br.ErrMsg = errMsg + ";Err:" + err.Error()
-		} else {
-			br.IsSendEmail = false
+		//添加指标
+		mysteelChemicalIndexInfo, err, errMsg := data.AddMysteelChemicalIndex(v.BaseFromMysteelChemicalClassifyId, strings.ToUpper(v.IndexCode), v.UpdateWeek, v.UpdateTime, this.SysUser.AdminId, this.SysUser.RealName)
+		if errMsg != `` {
+			br.Msg = errMsg
+			br.ErrMsg = errMsg
+			if err != nil {
+				br.ErrMsg = errMsg + ";Err:" + err.Error()
+			} else {
+				br.IsSendEmail = false
+			}
+			return
+		}
+		if i == 0 {
+			resp.BaseFromMysteelChemicalIndexId = mysteelChemicalIndexInfo.BaseFromMysteelChemicalIndexId
+			resp.IndexCode = mysteelChemicalIndexInfo.IndexCode
+			resp.UniqueCode = fmt.Sprint(mysteelChemicalIndexInfo.BaseFromMysteelChemicalClassifyId, "_", mysteelChemicalIndexInfo.BaseFromMysteelChemicalIndexId)
 		}
-		return
 	}
 
-	resp := response.AddMysteelChemicalIndexInfoResp{
-		BaseFromMysteelChemicalIndexId: mysteelChemicalIndexInfo.BaseFromMysteelChemicalIndexId,
-		IndexCode:                      mysteelChemicalIndexInfo.IndexCode,
-		UniqueCode:                     fmt.Sprint(mysteelChemicalIndexInfo.BaseFromMysteelChemicalClassifyId, "_", mysteelChemicalIndexInfo.BaseFromMysteelChemicalIndexId),
-	}
+
+
 	br.Data = resp
 	br.Ret = 200
 	br.Msg = "保存成功"
@@ -881,7 +933,7 @@ func (this *EdbClassifyController) EditMysteelChemical() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
-	var req request.AddBaseFromMysteelChemicalReq
+	var req request.AddBaseFromMysteelChemicalReqItem
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"

+ 42 - 46
controllers/data_manage/predict_edb_info.go

@@ -285,14 +285,14 @@ func (this *PredictEdbInfoController) List() {
 			dataCondition += ` AND edb_info_id=? `
 			dataPars = append(dataPars, sourceEdbInfoItem.EdbInfoId)
 
-			dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, sourceEdbInfoItem.Source)
+			dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取指标信息失败"
 				br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
 				return
 			}
 			page = paging.GetPaging(currentIndex, pageSize, dataCount)
-			dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, sourceEdbInfoItem.Source, pageSize, startSize)
+			dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, pageSize, startSize)
 			if err != nil {
 				br.Msg = "获取指标信息失败"
 				br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
@@ -303,7 +303,7 @@ func (this *PredictEdbInfoController) List() {
 
 		// 第一页才需要 获取预测指标未来的数据
 		if currentIndex == 1 {
-			allDataList, err := data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, "", "")
+			allDataList, err := data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, sourceEdbInfoItem.EdbInfoId, "", "")
 			if err != nil {
 				br.Msg = "获取失败"
 				br.Msg = "获取失败,Err:" + err.Error()
@@ -352,14 +352,14 @@ func (this *PredictEdbInfoController) List() {
 			dataCondition += ` AND edb_info_id=? AND data_time <= ? `
 			dataPars = append(dataPars, edbInfoItem.EdbInfoId, edbInfoItem.LatestDate)
 
-			dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source)
+			dataCount, err := data_manage.GetEdbDataCountByCondition(dataCondition, dataPars, edbInfoItem.Source, edbInfoItem.SubSource)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取指标信息失败"
 				br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
 				return
 			}
 			page = paging.GetPaging(currentIndex, pageSize, dataCount)
-			dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, pageSize, startSize)
+			dataList, err := data_manage.GetEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, edbInfoItem.SubSource, pageSize, startSize)
 			if err != nil {
 				br.Msg = "获取指标信息失败"
 				br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
@@ -376,7 +376,7 @@ func (this *PredictEdbInfoController) List() {
 			dataCondition += ` AND edb_info_id=? AND data_time > ? `
 			dataPars = append(dataPars, edbInfoItem.EdbInfoId, edbInfoItem.LatestDate)
 
-			predictDataList, err = data_manage.GetAllEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source)
+			predictDataList, err = data_manage.GetAllEdbDataListByCondition(dataCondition, dataPars, edbInfoItem.Source, edbInfoItem.SubSource)
 			if err != nil {
 				br.Msg = "获取指标信息失败"
 				br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
@@ -733,7 +733,7 @@ func (this *PredictEdbInfoController) Edit() {
 	data.AddOrEditEdbInfoToEs(resp.EdbInfoId)
 
 	// 刷新关联指标
-	go data.EdbInfoRefreshAllFromBaseV2(resp.EdbInfoId, true)
+	go data.EdbInfoRefreshAllFromBaseV2(resp.EdbInfoId, true, false)
 
 	br.Ret = 200
 	br.Success = true
@@ -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,
@@ -1551,7 +1566,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 	maxValue := sourceEdbInfoItem.MaxValue
 	allDataList := make([]*data_manage.EdbDataList, 0)
 	//获取指标数据(实际已生成)
-	dataList, err := data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, startDate, endDate)
+	dataList, err := data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, sourceEdbInfoItem.EdbInfoId, startDate, endDate)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.Msg = "获取失败,Err:" + err.Error()
@@ -1560,7 +1575,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 
 	// 如果选择了日期,那么需要筛选所有的数据,用于未来指标的生成
 	if startDate != `` {
-		allDataList, err = data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, "", "")
+		allDataList, err = data_manage.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.SubSource, sourceEdbInfoItem.EdbInfoId, "", "")
 		if err != nil {
 			br.Msg = "获取失败"
 			br.Msg = "获取失败,Err:" + err.Error()
@@ -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

+ 197 - 0
controllers/data_manage/smm_api.go

@@ -0,0 +1,197 @@
+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"
+	"strings"
+)
+
+// SmmIndexList
+// @Title 有色api数据指标列表
+// @Description 有色api数据指标列表
+// @Success 200 {object} data_manage.SmmClassify
+// @router /smm/api/list [get]
+func (this *EdbInfoController) SmmApiList() {
+	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
+	}
+	types := this.GetString("Types")
+	frequency := this.GetString("Frequency")
+	dataState := this.GetString("DataState")
+	keyword := this.GetString("Keyword")
+	indexCodes := this.GetString("IndexCodes")
+	sortType := this.GetString("SortType", "desc")
+	sortParam := this.GetString("SortParam")
+	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)
+
+	var condition string
+	var pars []interface{}
+
+	if types != "" {
+		typeArr := strings.Split(types,",")
+		for i, v := range typeArr {
+			typeStr := "type_"
+			typeStr += fmt.Sprintf("%d", i+1)
+			condition += " AND "+typeStr+" =? "
+			pars = append(pars, v)
+		}
+	}
+
+	if frequency != "" {
+		condition += " AND frequency = ? "
+		pars = append(pars, frequency)
+	}
+
+	if dataState != "" {
+		if dataState == "normal" {
+			condition += " AND (data_state = 'normal' OR data_state = '') "
+			pars = append(pars)
+		} else {
+			condition += " AND data_state = ? "
+			pars = append(pars, dataState)
+		}
+	}
+
+	if keyword != "" {
+		condition += " AND (index_name LIKE ? OR index_code LIKE ?) "
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+	}
+
+	if indexCodes != "" {
+		indexCodeArr := strings.Split(indexCodes,",")
+		indexCodeStr := ""
+		for _, v := range indexCodeArr {
+			indexCodeStr += "'" + v + "',"
+		}
+		indexCodeStr = strings.TrimRight(indexCodeStr, ",")
+		condition += " AND index_code IN (" + indexCodeStr + ") "
+	}
+
+	sortStr := ``
+	if sortParam != `` {
+		sortStr = fmt.Sprintf("%s %s,modify_time desc ", utils.PascalToSnake(sortParam), sortType)
+	} else {
+		sortStr = " modify_time desc "
+	}
+
+	total, err := data_manage.GetSmmIndexDataListCount(condition, pars)
+	if err!= nil {
+		br.Msg = "获取指标总数失败"
+		br.ErrMsg = "获取指标总数失败,Err:" + err.Error()
+		return
+	}
+
+	indexList, err := data_manage.GetSmmIndexDataList(condition, sortStr, pars, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取指标列表失败"
+		br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range indexList {
+		v.TypeAll = v.Type1 + "/" + v.Type2 + "/" + v.Type3
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	var ret data_manage.BaseFromSmmIndexListResp
+	ret.List = indexList
+	ret.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
+// SmmApiTypeList
+// @Title 有色api数据分类列表
+// @Description 有色api数据分类列表
+// @Success 200 {object} data_manage.SmmClassify
+// @router /smm/api/type/list [get]
+func (this *EdbInfoController) SmmApiTypeList() {
+	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
+	}
+
+	typeList, err := data_manage.GetBaseFromSmmIndexTypeList()
+	if err != nil {
+		br.Msg = "获取指标列表失败"
+		br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+		return
+	}
+
+	resp := make([]data_manage.TypeListRespItem, 0)
+
+	typeMap := make(map[string]map[string][]string)
+	//type2Map := make(map[string][]string)
+
+	//type2Map := make(map[string]data_manage.TypeListRespItem)
+
+	// 初始化
+	for _, v := range typeList {
+		if v.Type1 != ""{
+			if _, ok := typeMap[v.Type1];!ok {
+				typeMap[v.Type1] = make(map[string][]string)
+			} else {
+				if _, ok := typeMap[v.Type1][v.Type2];!ok {
+					typeMap[v.Type1][v.Type2] = make([]string, 0)
+				}
+			}
+		}
+	}
+
+	for _, v := range typeList {
+		if v.Type1 != ""{
+			typeMap[v.Type1][v.Type2] = append(typeMap[v.Type1][v.Type2], v.Type3)
+		}
+	}
+
+	for type1, type2Map := range typeMap {
+		var item data_manage.TypeListRespItem
+		item.Type = type1
+		for type2, type3List := range type2Map {
+			var child data_manage.TypeListRespItem
+			child.Type = type2
+			for _, type3 := range type3List {
+				child.Child = append(child.Child, data_manage.TypeListRespItem{type3,nil})
+			}
+			item.Child = append(item.Child, child)
+		}
+		resp = append(resp, item)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 82 - 9
controllers/data_manage/smm_data.go

@@ -2,15 +2,15 @@ package data_manage
 
 import (
 	"encoding/json"
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"github.com/tealeg/xlsx"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/data_manage/request"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/tealeg/xlsx"
 	"os"
 	"path/filepath"
 	"strings"
@@ -49,7 +49,7 @@ func (this *EdbInfoController) SmmClassify() {
 		return
 	}
 
-	baseFromSmmIndexMap := make(map[int][]*data_manage.BaseFromSmmClassifyItems)
+	/*baseFromSmmIndexMap := make(map[int][]*data_manage.BaseFromSmmClassifyItems)
 
 	allBaseFromSmmIndex, err := data_manage.GetSmmIndexAll()
 	if err != nil && err.Error() != utils.ErrNoRow() {
@@ -59,17 +59,17 @@ func (this *EdbInfoController) SmmClassify() {
 	}
 	for _, v := range allBaseFromSmmIndex {
 		baseFromSmmIndexMap[v.ClassifyId] = append(baseFromSmmIndexMap[v.ClassifyId], v)
-	}
+	}*/
 
 	rootChildMap := make(map[int][]*data_manage.BaseFromSmmClassifyItems)
 	for _, v := range classifyAll {
 		rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
-		if existItems, ok := baseFromSmmIndexMap[v.ClassifyId]; ok {
+		/*if existItems, ok := baseFromSmmIndexMap[v.ClassifyId]; ok {
 			v.Children = existItems
 		} else {
 			items := make([]*data_manage.BaseFromSmmClassifyItems, 0)
 			v.Children = items
-		}
+		}*/
 	}
 	var ret data_manage.BaseFromSmmClassifyResp
 	nodeAll := make([]*data_manage.BaseFromSmmClassifyItems, 0)
@@ -93,7 +93,7 @@ func (this *EdbInfoController) SmmClassify() {
 		Sort:               0,
 		Children:           nil,
 	}
-	initIndexList, err := data_manage.GetBaseFromSmmIndexByClassifyId(initClassify.ClassifyId)
+	/*initIndexList, err := data_manage.GetBaseFromSmmIndexByClassifyId(initClassify.ClassifyId)
 	if err != nil {
 		br.Msg = "获取未分类指标失败"
 		br.ErrMsg = "获取未分类指标失败,Err:" + err.Error()
@@ -112,7 +112,7 @@ func (this *EdbInfoController) SmmClassify() {
 			Children:             nil,
 		}
 		initClassify.Children = append(initClassify.Children, tmp)
-	}
+	}*/
 	finalList := make([]*data_manage.BaseFromSmmClassifyItems, 0)
 	finalList = append(finalList, initClassify)
 	finalList = append(finalList, nodeAll...)
@@ -123,6 +123,55 @@ func (this *EdbInfoController) SmmClassify() {
 	br.Data = ret
 }
 
+// SmmIndexList
+// @Title 有色数据指标
+// @Description 有色数据指标列表接口
+// @Success 200 {object} data_manage.SmmClassify
+// @router /smm/index/list [get]
+func (this *EdbInfoController) SmmIndexList() {
+	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
+	}
+	classifyId, _ := this.GetInt("ClassifyId", 0)
+
+	list := make([]*data_manage.BaseFromSmmClassifyItems, 0)
+	indexList, err := data_manage.GetBaseFromSmmIndexByClassifyId(classifyId)
+	if err != nil {
+		br.Msg = "获取未分类指标失败"
+		br.ErrMsg = "获取未分类指标失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range indexList {
+		tmp := &data_manage.BaseFromSmmClassifyItems{
+			ClassifyId:           v.ClassifyId,
+			BaseFromSmmIndexId:   v.BaseFromSmmIndexId,
+			BaseFromSmmIndexCode: v.IndexCode,
+			ClassifyName:         v.IndexName,
+			ParentId:             0,
+			Level:                0,
+			Sort:                 0,
+			Children:             nil,
+		}
+		list = append(list, tmp)
+	}
+	var ret data_manage.BaseFromSmmClassifyResp
+	ret.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
 // SmmClassifyName
 // @Title 有色数据分类名称查询
 // @Description 有色数据分类名称查询接口
@@ -674,6 +723,30 @@ func (this *EdbInfoController) SmmSearchList() {
 		br.Msg = "获取失败"
 		return
 	}
+	classifyIds := make([]int, 0)
+	for _, v := range list {
+		if v.ClassifyId > 0 {
+			classifyIds = append(classifyIds, v.ClassifyId)
+		}
+	}
+	if len(classifyIds) > 0 {
+		// 查询父级分类信息
+		classifyList, e := data_manage.GetBaseFromSmmClassifyByIds(classifyIds)
+		if e != nil {
+			br.Msg = "获取目录信息失败"
+			br.ErrMsg = "获取失获取目录信息失败,Err:" + err.Error()
+			return
+		}
+		classifyListMap := make(map[int]int, 0)
+		for _, v := range classifyList {
+			classifyListMap[v.ClassifyId] = v.ParentId
+		}
+		for _, v := range list {
+			if p, ok := classifyListMap[v.ClassifyId]; ok {
+				v.ParentClassifyId = p
+			}
+		}
+	}
 
 	br.Ret = 200
 	br.Success = true

+ 2 - 2
controllers/data_manage/supply_analysis/variety.go

@@ -57,7 +57,7 @@ func (this *VarietyController) List() {
 
 	if keyword != `` {
 		condition += ` AND (a.variety_name like ? OR c.edb_code like ? ) `
-		pars = append(pars, "%"+keyword+"%", "%"+keyword+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	// 是否超管
@@ -584,7 +584,7 @@ func (this *VarietyController) Analysis() {
 						continue
 					}
 					// 刷新指标数据
-					go data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.StartDate)
+					go data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.StartDate)
 				}
 			}
 		}

+ 2 - 2
controllers/data_manage/supply_analysis/variety_edb.go

@@ -232,7 +232,7 @@ func (this *VarietyController) AddToEdb() {
 	prefixCode := "HZ_V"
 	suffixCode := time.Now().Format("060102") + randStr
 	edbCode := fmt.Sprint(prefixCode, varietyEdbInfo.Source, suffixCode)
-	edbInfo, err, errMsg, isSendEmail := data.EdbInfoAdd(utils.DATA_SOURCE_STOCK_PLANT, req.ClassifyId, edbCode, req.EdbName, req.Frequency, req.Unit, varietyEdbInfo.StartDate.Format(utils.FormatDate), varietyEdbInfo.EndDate.Format(utils.FormatDate), sysUser.AdminId, sysUser.RealName)
+	edbInfo, err, errMsg, isSendEmail := data.EdbInfoAdd(utils.DATA_SOURCE_STOCK_PLANT, utils.DATA_SUB_SOURCE_EDB, req.ClassifyId, edbCode, req.EdbName, req.Frequency, req.Unit, varietyEdbInfo.StartDate.Format(utils.FormatDate), varietyEdbInfo.EndDate.Format(utils.FormatDate), sysUser.AdminId, sysUser.RealName)
 	if err != nil {
 		br.Msg = "保存失败"
 		if errMsg != `` {
@@ -259,7 +259,7 @@ func (this *VarietyController) AddToEdb() {
 
 	// 更新ETA指标库信息
 	{
-		data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.StartDate)
+		data.RefreshEdbData(edbInfo.EdbInfoId, edbInfo.Source, edbInfo.SubSource, edbInfo.EdbCode, edbInfo.StartDate)
 	}
 
 	//新增操作日志

+ 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"
+
+}

+ 842 - 0
controllers/data_stat/edb_source_stat.go

@@ -0,0 +1,842 @@
+package data_stat
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_stat"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strings"
+	"time"
+)
+
+// EdbSourceStatController 数据源统计表管理模块
+type EdbSourceStatController struct {
+	controllers.BaseAuthController
+}
+
+// Column
+// @Title 数据源统计表自定义列列表
+// @Description 查询 数据源统计表自定义列列表
+// @Success 200 {object} data_stat.StatColumnList
+// @router /source_column [get]
+func (this *EdbSourceStatController) Column() {
+	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
+	}
+	columnType, _ := this.GetInt("ColumnType")
+	if columnType <= 0 {
+		br.Msg = "请选择表类型"
+		return
+	}
+	tmpList, err := data_stat.GetStatColumn(columnType)
+	if err != nil {
+		br.Msg = "获取自定义列失败"
+		br.ErrMsg = "获取自定义列失败,Err:" + err.Error()
+		return
+	}
+	var list []*data_stat.EdbInfoStatColumnListItem
+	for _, v := range tmpList {
+		tmp := new(data_stat.EdbInfoStatColumnListItem)
+		tmp.ColumnKey = v.ColumnKey
+		tmp.IsShow = v.IsShow
+		tmp.ColumnName = v.ColumnName
+		tmp.Id = v.Id
+		tmp.IsMust = v.IsMust
+		tmp.IsSort = v.IsSort
+		tmp.Type = v.Type
+		list = append(list, tmp)
+	}
+	var statColumnList data_stat.StatColumnList
+	statColumnList.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = statColumnList
+}
+
+// EditColumn
+// @Title 编辑数据源统计表自定义列
+// @Description 编辑 数据源统计表自定义列列表
+// @Success 200 {object} data_stat.StatColumnList
+// @router /source_column/edit [post]
+func (this *EdbSourceStatController) EditColumn() {
+	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
+	}
+	var req data_stat.EditStatColumnReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if len(req.List) <= 0 {
+		br.Msg = "请选择要修改的列"
+		br.IsSendEmail = false
+		return
+	}
+
+	tmpList, err := data_stat.GetAllStatColumn()
+	if err != nil {
+		br.Msg = "获取自定义列失败"
+		br.ErrMsg = "获取自定义列失败,Err:" + err.Error()
+		return
+	}
+	isMustMap := make(map[int]data_stat.EdbInfoStatColumn)
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.IsMust == 1 {
+				isMustMap[v.Id] = v
+			}
+		}
+	}
+
+	var list []*data_stat.EdbInfoStatColumn
+	for k, v := range req.List {
+		if v.Id == 0 {
+			br.Msg = "列序号不能为空"
+			return
+		}
+
+		if v.IsShow == 0 {
+			if exist, ok := isMustMap[v.Id]; ok {
+				br.Msg = exist.ColumnName + "为必选列!"
+				return
+			}
+		}
+		tmp := new(data_stat.EdbInfoStatColumn)
+		tmp.Id = v.Id
+		tmp.Sort = k + 1
+		tmp.IsShow = v.IsShow
+		list = append(list, tmp)
+	}
+
+	err = data_stat.UpdateStatColumn(list)
+	if err != nil {
+		br.Msg = "更新自定义列操作失败!"
+		br.ErrMsg = "更新自定义列操作失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	return
+}
+
+// EdbDeleteLog
+// @Title 查询删除指标列表
+// @Description 查询删除指标列表接口
+// @Success 200 {object} data_stat.GetEdbDeleteLogResp
+// @router /edb_delete_log [get]
+func (this *EdbSourceStatController) EdbDeleteLog() {
+	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
+	}
+
+	sortParamReq := this.GetString("SortParam", "")
+	sortType := this.GetString("SortType", "desc")
+	createTime := this.GetString("CreateTime", "")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	condition := " and source = ?"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+
+	if createTime != "" {
+		startT, err := time.ParseInLocation(utils.FormatDate, createTime, time.Local)
+		if err != nil {
+			br.Msg = "请求时间格式错误"
+			return
+		}
+		endT := startT.AddDate(0, 0, 1)
+		condition += " AND create_time >= ? AND create_time < ?"
+		pars = append(pars, createTime, endT.Format(utils.FormatDate))
+	}
+
+	sortStr := ``
+	sortParam := ``
+	if sortParamReq != `` {
+		switch sortParamReq {
+		case "CreateTime":
+			sortParam = "create_time"
+		case "DataUpdateTime":
+			sortParam = "data_update_time"
+		case "ErDataUpdateDate":
+			sortParam = "er_data_update_date"
+		case "LatestDate":
+			sortParam = "latest_date"
+		case "StartDate":
+			sortParam = "start_date"
+		}
+		if sortParam == "" {
+			br.Msg = "请输入正确的排序字段"
+			return
+		}
+		if strings.ToLower(sortType) != "asc" && strings.ToLower(sortType) != "desc" {
+			br.Msg = "请输入正确的排序类型"
+			return
+		}
+		sortStr = fmt.Sprintf(" order by %s %s, id desc ", sortParam, sortType)
+	}
+	total, err := data_stat.GetEdbDeleteLogCount(condition, pars)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取指标删除列表总数失败"
+			br.ErrMsg = "获取指标删除列表总数失败,Err:" + err.Error()
+			return
+		} else {
+			err = nil
+		}
+	}
+	list := make([]*data_stat.EdbInfoDeleteLogItem, 0)
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	if total == 0 {
+		resp := data_stat.GetEdbDeleteLogResp{
+			Paging: page,
+			List:   list,
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+	tmpList, err := data_stat.GetEdbDeleteLogByCondition(condition, pars, sortStr, pageSize, startSize)
+	if err != nil {
+		br.Msg = "获取指标删除列表失败"
+		br.ErrMsg = "获取指标删除列表失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range tmpList {
+		tmp := new(data_stat.EdbInfoDeleteLogItem)
+		tmp.EdbCode = v.EdbCode
+		tmp.EdbInfoId = v.EdbInfoId
+		tmp.Id = v.Id
+		tmp.StartDate = v.StartDate
+		tmp.EndDate = v.EndDate
+		tmp.Unit = v.Unit
+		tmp.TerminalCode = v.TerminalCode
+		tmp.CreateTime = v.CreateTime
+		tmp.EdbCreateTime = v.EdbCreateTime
+		tmp.Frequency = v.Frequency
+		tmp.Source = v.Source
+		tmp.SourceName = v.SourceName
+		tmp.EdbName = v.EdbName
+		tmp.EdbNameEn = v.EdbNameEn
+		tmp.EdbNameSource = v.EdbNameSource
+		tmp.LatestDate = v.LatestDate
+
+		tmp.DelSysUserId = v.DelSysUserId
+		tmp.DelSysUserRealName = v.DelSysUserRealName
+		tmp.SysUserId = v.SysUserId
+		tmp.SysUserRealName = v.SysUserRealName
+		tmp.LatestValue = v.LatestValue
+		if v.DataUpdateTime != utils.EmptyDateTimeStr {
+			tmp.DataUpdateTime = v.DataUpdateTime
+		}
+		if v.ErDataUpdateDate != utils.EmptyDateStr {
+			tmp.ErDataUpdateDate = v.ErDataUpdateDate
+		}
+		list = append(list, tmp)
+	}
+
+	resp := data_stat.GetEdbDeleteLogResp{
+		Paging: page,
+		List:   list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbUpdateLog
+// @Title 查询指标信息变更列表
+// @Description 查询指标信息变更列表接口
+// @Success 200 {object} data_stat.GetEdbUpdateLogResp
+// @router /edb_update_log [get]
+func (this *EdbSourceStatController) EdbUpdateLog() {
+	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
+	}
+
+	sortParamReq := this.GetString("SortParam", "")
+	sortType := this.GetString("SortType", "desc")
+	createTime := this.GetString("CreateTime", "")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	condition := " and source = ? and (data_update_result=1 or data_update_result=0)"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+
+	if createTime != "" {
+		startT, err := time.ParseInLocation(utils.FormatDate, createTime, time.Local)
+		if err != nil {
+			br.Msg = "请求时间格式错误"
+			return
+		}
+		endT := startT.AddDate(0, 0, 1)
+		condition += " AND create_time >= ? AND create_time < ?"
+		pars = append(pars, createTime, endT.Format(utils.FormatDate))
+	}
+
+	sortStr := ``
+	sortParam := ``
+	if sortParamReq != `` {
+		switch sortParamReq {
+		case "CreateTime":
+			sortParam = "create_time"
+		case "DataUpdateTime":
+			sortParam = "data_update_time"
+		case "ErDataUpdateDate":
+			sortParam = "er_data_update_date"
+		case "LatestDate":
+			sortParam = "latest_date"
+		case "StartDate":
+			sortParam = "start_date"
+		}
+		if sortParam == "" {
+			br.Msg = "请输入正确的排序字段"
+			return
+		}
+		if strings.ToLower(sortType) != "asc" && strings.ToLower(sortType) != "desc" {
+			br.Msg = "请输入正确的排序类型"
+			return
+		}
+		sortStr = fmt.Sprintf(" order by %s %s, id desc ", sortParam, sortType)
+	}
+	total, err := data_stat.GetEdbUpdateLogCount(condition, pars)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取指标删除列表总数失败"
+			br.ErrMsg = "获取指标删除列表总数失败,Err:" + err.Error()
+			return
+		} else {
+			err = nil
+		}
+	}
+	list := make([]*data_stat.EdbInfoUpdateLogItem, 0)
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	if total == 0 {
+		resp := data_stat.GetEdbUpdateLogResp{
+			Paging: page,
+			List:   list,
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+	tmpList, err := data_stat.GetEdbUpdateLogByCondition(condition, pars, sortStr, pageSize, startSize)
+	if err != nil {
+		br.Msg = "获取指标更新列表失败"
+		br.ErrMsg = "获取指标更新列表失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range tmpList {
+		tmp := new(data_stat.EdbInfoUpdateLogItem)
+		tmp.Id = v.Id
+		tmp.EdbInfoId = v.EdbInfoId
+		tmp.SourceName = v.SourceName
+		tmp.Source = v.Source
+		tmp.EdbCode = v.EdbCode
+		tmp.EdbName = v.EdbName
+		tmp.EdbNameSource = v.EdbNameSource
+		tmp.Frequency = v.Frequency
+		tmp.Unit = v.Unit
+		tmp.StartDate = v.StartDate
+		tmp.EndDate = v.EndDate
+		tmp.SysUserId = v.SysUserId
+		tmp.SysUserRealName = v.SysUserRealName
+		tmp.UpdateSysUserRealName = v.UpdateSysUserRealName
+		tmp.UpdateSysUserId = v.UpdateSysUserId
+		tmp.UniqueCode = v.UniqueCode
+		tmp.CreateTime = v.CreateTime.Format(utils.FormatDateTime)
+		tmp.LatestDate = v.LatestDate
+		tmp.LatestValue = v.LatestValue
+		tmp.TerminalCode = v.TerminalCode
+		if v.DataUpdateTime != utils.EmptyDateTimeStr {
+			tmp.DataUpdateTime = v.DataUpdateTime
+		}
+		if v.ErDataUpdateDate != utils.EmptyDateStr {
+			tmp.ErDataUpdateDate = v.ErDataUpdateDate
+		}
+		list = append(list, tmp)
+	}
+
+	resp := data_stat.GetEdbUpdateLogResp{
+		Paging: page,
+		List:   list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbUpdateStat
+// @Title 查询数据源明细列表
+// @Description 查询数据源明细列表接口
+// @Success 200 {object} data_stat.GetEdbUpdateStatResp
+// @router /edb_update_stat [get]
+func (this *EdbSourceStatController) EdbUpdateStat() {
+	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
+	}
+
+	sortParamReq := this.GetString("SortParam", "")
+	sortType := this.GetString("SortType", "desc")
+	terminalCode := this.GetString("TerminalCode", "")
+	sysUserId := this.GetString("SysUserId", "")
+	frequency := this.GetString("Frequency", "")
+	keyWord := this.GetString("KeyWord", "") //指标编码/指标名称
+
+	createTime := this.GetString("CreateTime", "")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	condition := " and source = ?"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+	if createTime != "" {
+		startT, err := time.ParseInLocation(utils.FormatDate, createTime, time.Local)
+		if err != nil {
+			br.Msg = "请求时间格式错误"
+			return
+		}
+		endT := startT.AddDate(0, 0, 1)
+		condition += " AND create_time >= ? AND create_time < ?"
+		pars = append(pars, createTime, endT.Format(utils.FormatDate))
+	}
+
+	if terminalCode != "" {
+		codeSlice := strings.Split(terminalCode, ",")
+		condition += ` AND terminal_code IN (` + utils.GetOrmInReplace(len(codeSlice)) + `)`
+		pars = append(pars, codeSlice)
+	}
+
+	if sysUserId != "" {
+		sysUserIdSlice := strings.Split(sysUserId, ",")
+		condition += ` AND sys_user_id IN (` + utils.GetOrmInReplace(len(sysUserIdSlice)) + `)`
+		pars = append(pars, sysUserIdSlice)
+	}
+
+	if frequency != "" {
+		frequencySlice := strings.Split(frequency, ",")
+		condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencySlice)) + `)`
+		pars = append(pars, frequencySlice)
+	}
+
+	if keyWord != "" {
+		condition += ` AND (edb_name LIKE ? OR edb_code LIKE ? ) `
+		pars = append(pars, "%"+keyWord+"%", "%"+keyWord+"%")
+	}
+
+	sortStr := ``
+	sortParam := ``
+	if sortParamReq != `` {
+		switch sortParamReq {
+		case "CreateTime":
+			sortParam = "create_time"
+		case "UpdateTime":
+			sortParam = "update_time"
+		case "DataUpdateTime":
+			sortParam = "data_update_time"
+		case "ErDataUpdateDate":
+			sortParam = "er_data_update_date"
+		case "LatestDate":
+			sortParam = "latest_date"
+		case "StartDate":
+			sortParam = "start_date"
+		}
+		if sortParam == "" {
+			br.Msg = "请输入正确的排序字段"
+			return
+		}
+		if strings.ToLower(sortType) != "asc" && strings.ToLower(sortType) != "desc" {
+			br.Msg = "请输入正确的排序类型"
+			return
+		}
+		sortStr = fmt.Sprintf(" order by %s %s, id desc ", sortParam, sortType)
+	}
+	total, err := data_stat.GetEdbUpdateStatCount(condition, pars)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取指标删除列表总数失败"
+			br.ErrMsg = "获取指标删除列表总数失败,Err:" + err.Error()
+			return
+		} else {
+			err = nil
+		}
+	}
+	list := make([]*data_stat.EdbInfoUpdateStatItem, 0)
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	if total == 0 {
+		resp := data_stat.GetEdbUpdateStatResp{
+			Paging: page,
+			List:   list,
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+	tmpList, err := data_stat.GetEdbUpdateStatByCondition(condition, pars, sortStr, pageSize, startSize)
+	if err != nil {
+		br.Msg = "获取指标更新列表失败"
+		br.ErrMsg = "获取指标更新列表失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range tmpList {
+		tmp := new(data_stat.EdbInfoUpdateStatItem)
+		tmp.Id = v.Id
+		tmp.EdbInfoId = v.EdbInfoId
+		tmp.SourceName = v.SourceName
+		tmp.Source = v.Source
+		tmp.EdbCode = v.EdbCode
+		tmp.EdbName = v.EdbName
+		tmp.EdbNameSource = v.EdbNameSource
+		tmp.Frequency = v.Frequency
+		tmp.Unit = v.Unit
+		tmp.StartDate = v.StartDate
+		tmp.SysUserId = v.SysUserId
+		tmp.SysUserRealName = v.SysUserRealName
+		tmp.LatestDate = v.LatestDate
+		tmp.LatestValue = v.LatestValue
+		tmp.TerminalCode = v.TerminalCode
+		if v.DataUpdateTime != utils.EmptyDateTimeStr {
+			tmp.DataUpdateTime = v.DataUpdateTime
+		}
+		if v.ErDataUpdateDate != utils.EmptyDateStr {
+			tmp.ErDataUpdateDate = v.ErDataUpdateDate
+		}
+		tmp.DataUpdateResult = v.DataUpdateResult
+		tmp.DataUpdateFailedReason = v.DataUpdateFailedReason
+		if v.UpdateTime != utils.EmptyDateTimeStr {
+			tmp.UpdateTime = v.UpdateTime
+		}
+		tmp.IsAdd = v.IsAdd
+		tmp.NeedRefresh = v.NeedRefresh
+		tmp.HasRefresh = v.HasRefresh
+		list = append(list, tmp)
+	}
+
+	resp := data_stat.GetEdbUpdateStatResp{
+		Paging: page,
+		List:   list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbSourceStat
+// @Title 查询数据源统计列表
+// @Description 查询数据源统计列表接口
+// @Success 200 {object} data_stat.GetEdbUpdateLogResp
+// @router /source_stat [get]
+func (this *EdbSourceStatController) EdbSourceStat() {
+	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
+	}
+
+	sortParamReq := this.GetString("SortParam", "")
+	sortType := this.GetString("SortType", "desc")
+	createTime := this.GetString("CreateTime", "")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+
+	startSize = paging.StartIndex(currentIndex, pageSize)
+
+	condition := " and source = ?"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+
+	if createTime != "" {
+		startT, err := time.ParseInLocation(utils.FormatDate, createTime, time.Local)
+		if err != nil {
+			br.Msg = "请求时间格式错误"
+			return
+		}
+		endT := startT.AddDate(0, 0, 1)
+		condition += " AND create_time >= ? AND create_time < ?"
+		pars = append(pars, createTime, endT.Format(utils.FormatDate))
+	}
+
+	sortStr := ``
+	sortParam := ``
+	if sortParamReq != `` {
+		switch sortParamReq {
+		case "EdbNum":
+			sortParam = "edb_num"
+		case "NeedRefreshNum":
+			sortParam = "need_refresh_num"
+		case "hasRefreshNum":
+			sortParam = "has_refresh_num"
+		case "UpdateSuccessNum":
+			sortParam = "update_success_num"
+		case "UpdateFailedNum":
+			sortParam = "update_failed_num"
+		}
+
+		if sortParam == "" {
+			br.Msg = "请输入正确的排序字段"
+			return
+		}
+		if strings.ToLower(sortType) != "asc" && strings.ToLower(sortType) != "desc" {
+			br.Msg = "请输入正确的排序类型"
+			return
+		}
+		sortStr = fmt.Sprintf(" order by %s %s, id desc ", sortParam, sortType)
+	}
+	total, err := data_stat.GetEdbSourceStatCount(condition, pars)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取数据源统计列表总数失败"
+			br.ErrMsg = "获取数据源统计列表总数失败,Err:" + err.Error()
+			return
+		} else {
+			err = nil
+		}
+	}
+	list := make([]*data_stat.EdbInfoSourceStatItem, 0)
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	if total == 0 {
+		resp := data_stat.GetEdbSourceStatResp{
+			Paging: page,
+			List:   list,
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+	tmpList, err := data_stat.GetEdbSourceStatByCondition(condition, pars, sortStr, pageSize, startSize)
+	if err != nil {
+		br.Msg = "获取指标删除列表失败"
+		br.ErrMsg = "获取指标删除列表失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range tmpList {
+		tmp := new(data_stat.EdbInfoSourceStatItem)
+		tmp.Id = v.Id
+		tmp.SourceName = v.SourceName
+		tmp.Source = v.Source
+		tmp.TerminalCode = v.TerminalCode
+		tmp.EdbNum = v.EdbNum
+		tmp.EdbNewNum = v.EdbNewNum
+		tmp.EdbDelNum = v.EdbDelNum
+		tmp.NeedRefreshNum = v.NeedRefreshNum
+		tmp.HasRefreshNum = v.HasRefreshNum
+		tmp.UpdateSuccessNum = v.UpdateSuccessNum
+		tmp.UpdateFailedNum = v.UpdateFailedNum
+		tmp.RefreshSuccessNum = v.RefreshSuccessNum
+		tmp.RefreshFailedNum = v.RefreshFailedNum
+		list = append(list, tmp)
+	}
+
+	resp := data_stat.GetEdbSourceStatResp{
+		Paging: page,
+		List:   list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// EdbUpdateFailedList
+// @Title 查询指标更新失败详情列表
+// @Description 查询指标更新失败详情列表
+// @Success 200 {object} data_stat.GetEdbUpdateLogResp
+// @router /edb_update_stat/failed [get]
+func (this *EdbSourceStatController) EdbUpdateFailedList() {
+	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
+	}
+
+	terminalCode := this.GetString("TerminalCode", "")
+	createTime := this.GetString("CreateTime", "")
+
+	if terminalCode == "" {
+		br.Msg = "请选择对应的终端信息"
+		return
+	}
+	terminalInfo, err := data_manage.GetEdbTerminalByTerminalCode(terminalCode)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "终端不存在"
+			return
+		}
+		br.Msg = "查询终端信息出错"
+		br.ErrMsg = "查询终端信息出错 Err:" + err.Error()
+		return
+	}
+	condition := " and source = ? and terminal_code = ?"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, terminalCode)
+
+	if createTime != "" {
+		startT, err := time.ParseInLocation(utils.FormatDate, createTime, time.Local)
+		if err != nil {
+			br.Msg = "请求时间格式错误"
+			return
+		}
+		endT := startT.AddDate(0, 0, 1)
+		condition += " AND create_time >= ? AND create_time < ?"
+		pars = append(pars, createTime, endT.Format(utils.FormatDate))
+	}
+
+	tmpList, err := data_stat.GetEdbUpdateStatFailedGroupByCondition(condition, pars)
+	if err != nil {
+		br.Msg = "获取指标更新失败详情列表 失败"
+		br.ErrMsg = "获取指标更新失败详情列表 失败,Err:" + err.Error()
+		return
+	}
+
+	list := make([]*data_stat.EdbUpdateFailedList, 0)
+	successNum := 0
+	failedNum := 0
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.SourceUpdateResult == 1 {
+				successNum += v.Num
+			} else {
+				failedNum += v.Num
+				list = append(list, v)
+			}
+		}
+	}
+	resp := data_stat.GetEdbUpdateFailedResp{
+		List:             list,
+		Name:             terminalInfo.Name,
+		TerminalCode:     terminalCode,
+		DirPath:          terminalInfo.DirPath,
+		UpdateSuccessNum: successNum,
+		UpdateFailedNum:  failedNum,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 200 - 0
controllers/data_stat/edb_terminal.go

@@ -0,0 +1,200 @@
+package data_stat
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/services/data_stat"
+	"eta/eta_api/utils"
+)
+
+// EdbTerminalController 数据源终端管理
+type EdbTerminalController struct {
+	controllers.BaseAuthController
+}
+
+// Save
+// @Title 保存数据源终端
+// @Description 保存数据源终端接口
+// @Param	request  body  true data_manage.AddEdbTerminalListReq  "type json string"
+// @Success 200 string "操作成功"
+// @router /terminal/save [post]
+func (this *EdbTerminalController) Save() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	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
+	}
+	var req *data_manage.AddEdbTerminalListReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.Name == "" {
+		br.Msg = "请输入终端名称"
+		return
+	}
+	/*if req.ServerUrl == "" && req.Value == "" {
+		br.Msg = "请输入终端地址或者token"
+		return
+	}*/
+	if req.Num <= 0 {
+		br.Msg = "请输入指标数据量"
+		return
+	}
+	if req.Source == 0 {
+		br.Msg = "请输入终端类型"
+		return
+	}
+
+	// todo 校验终端数据
+
+	errMsg, err := data_stat.SaveEdbTerminal(req)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "SaveEnglishVideoCover ErrMsg:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	return
+}
+
+// SetStatus
+// @Title 启用/禁用数据源终端
+// @Description 启用/禁用数据源终端
+// @Param	request  body  true data_manage.SetEdbTerminalStatusReq  "type json string"
+// @Success 200 string "操作成功"
+// @router /terminal/status/set [post]
+func (this *EdbTerminalController) SetStatus() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	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
+	}
+	var req *data_manage.SetEdbTerminalStatusReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.TerminalId <= 0 {
+		br.Msg = "请选择要操作的终端"
+		return
+	}
+
+	if req.Status != 1 && req.Status != 2 {
+		br.Msg = "请选择正确的终端状态"
+		return
+	}
+
+	errMsg, err := data_stat.SetEdbTerminalStatus(req.TerminalId, req.Status)
+	if err != nil {
+		br.Msg = errMsg
+		br.ErrMsg = "SetEdbTerminalStatus ErrMsg:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	return
+}
+
+// List
+// @Title 数据源终端列表
+// @Description 数据源终端列表接口
+// @Success 200 {object} data_manage.EdbTerminalLisResp
+// @router /terminal/list [get]
+func (this *EdbTerminalController) List() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	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
+	}
+
+	list, err := data_manage.GetEdbTerminalList()
+	if err != nil {
+		br.Msg = "获取终端列表失败"
+		br.ErrMsg = "获取终端列表失败 ErrMsg:" + err.Error()
+		return
+	}
+	resp := &data_manage.EdbTerminalListResp{
+		List: list,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// TerminalCodeList
+// @Title 数据源终端列表
+// @Description 数据源终端列表接口
+// @Success 200 {object} data_manage.EdbTerminalCodeResp
+// @router /terminal/code [get]
+func (this *EdbTerminalController) TerminalCodeList() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	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
+	}
+	source, _ := this.GetInt("Source", utils.DATA_SOURCE_MYSTEEL_CHEMICAL)
+	list, err := data_manage.GetEdbTerminalBySource(source)
+	if err != nil {
+		br.Msg = "获取终端列表失败"
+		br.ErrMsg = "获取终端列表失败 ErrMsg:" + err.Error()
+		return
+	}
+	codeList := make([]*data_manage.EdbTerminalCode, 0)
+	if len(list) > 0 {
+		for _, v := range list {
+			tmp := new(data_manage.EdbTerminalCode)
+			tmp.TerminalCode = v.TerminalCode
+			tmp.Source = v.Source
+			tmp.Name = v.Name
+			codeList = append(codeList, tmp)
+		}
+	}
+	resp := &data_manage.EdbTerminalCodeResp{
+		List: codeList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 18 - 0
controllers/english_report/english_classify.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
@@ -469,6 +470,23 @@ func (this *EnglishReportController) DelClassify() {
 		return
 	}
 
+	// 查询该分类是否关联了审批流
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowCond := fmt.Sprintf(` AND %s = ? AND (%s = ? Or %s = ?)`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowPars := make([]interface{}, 0)
+	flowPars = append(flowPars, report_approve.FlowReportTypeEnglish, classifyId, classifyId)
+	flowCount, e := flowOb.GetCountByCondition(flowCond, flowPars)
+	if e != nil {
+		br.Msg = "检测失败"
+		br.ErrMsg = "获取关联审批流失败, Err: " + e.Error()
+		return
+	}
+	if flowCount > 0 {
+		br.Msg = "该分类关联审批流,不允许删除"
+		br.Ret = 403
+		return
+	}
+
 	if err = models.DeleteEnglishClassify(classifyId); err != nil {
 		br.Msg = "删除失败"
 		br.ErrMsg = "删除报告失败, Err: " + err.Error()

+ 3 - 4
controllers/english_report/english_company.go

@@ -2,14 +2,14 @@ package english_report
 
 import (
 	"encoding/json"
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
@@ -62,8 +62,7 @@ func (this *EnglishCompanyController) List() {
 	var cond, order string
 	var pars []interface{}
 	if keywords != "" {
-		k := "%" + keywords + "%"
-		companyIds, e := models.GetEnCompanyIdsByKeyword(k)
+		companyIds, e := models.GetEnCompanyIdsByKeyword(keywords)
 		if e != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "关键词获取英文客户IDs失败, Err: " + e.Error()

+ 288 - 22
controllers/english_report/report.go

@@ -5,9 +5,11 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/company"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/paging"
@@ -84,6 +86,14 @@ func (this *EnglishReportController) Add() {
 		return
 	}
 
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
 	item := new(models.EnglishReport)
 	item.AddType = req.AddType
 	item.ClassifyIdFirst = req.ClassifyIdFirst
@@ -94,7 +104,7 @@ func (this *EnglishReportController) Add() {
 	item.Abstract = req.Abstract
 	item.Author = req.Author
 	item.Frequency = req.Frequency
-	item.State = req.State
+	item.State = state
 	item.Content = html.EscapeString(req.Content)
 	item.Stage = maxStage + 1
 	item.ContentSub = html.EscapeString(contentSub)
@@ -188,15 +198,27 @@ func (this *EnglishReportController) Edit() {
 	}
 
 	var stage int
-	report, _ := models.GetEnglishReportById(int(req.ReportId))
-	if report != nil {
-		if report.ClassifyNameFirst != req.ClassifyNameFirst || report.ClassifyNameSecond != req.ClassifyNameSecond {
-			maxStage, _ := models.GetEnglishReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, int(req.ReportId))
-			maxStage = maxStage + 1
-			stage = maxStage
-		} else {
-			stage = report.Stage
+	report, e := models.GetEnglishReportById(int(req.ReportId))
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
 		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+	if report.State == models.ReportStatePublished || report.State == models.ReportStatePass {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+	if report.ClassifyNameFirst != req.ClassifyNameFirst || report.ClassifyNameSecond != req.ClassifyNameSecond {
+		maxStage, _ := models.GetEnglishReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, int(req.ReportId))
+		maxStage = maxStage + 1
+		stage = maxStage
+	} else {
+		stage = report.Stage
 	}
 
 	item := new(models.EnglishReport)
@@ -208,7 +230,7 @@ func (this *EnglishReportController) Edit() {
 	item.Abstract = req.Abstract
 	item.Author = req.Author
 	item.Frequency = req.Frequency
-	item.State = req.State
+	item.State = report.State // 编辑不变更状态
 	item.Stage = stage
 	item.Content = html.EscapeString(req.Content)
 	item.ContentSub = html.EscapeString(contentSub)
@@ -306,7 +328,7 @@ func (this *EnglishReportController) Detail() {
 // @Description 获取报告列表
 // @Param   PageSize   query   int  true       "每页数据条数"
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
-// @Param   TimeType     query string true  "筛选的时间类别:publish_time(发布时间),modify_time(更新时间)"
+// @Param   TimeType     query string true  "筛选的时间类别:publish_time(发布时间),modify_time(更新时间);approve_time(审批时间)"
 // @Param   StartDate   query   string  true       "开始时间"
 // @Param   EndDate   query   string  true       "结束时间"
 // @Param   Frequency   query   string  true       "频度"
@@ -361,13 +383,14 @@ func (this *EnglishReportController) ListReport() {
 	var pars []interface{}
 
 	if keyWord != "" {
-		condition += ` AND (title LIKE '%` + keyWord + `%' OR admin_real_name LIKE '%` + keyWord + `%' ) `
+		condition += ` AND (title LIKE ? OR admin_real_name LIKE ? ) `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	}
 
 	if timeType == "" {
 		timeType = "publish_time"
 	}
-	if timeType != "publish_time" && timeType != "modify_time" {
+	if timeType != "publish_time" && timeType != "modify_time" && timeType != "approve_time" {
 		br.Msg = "请选择正确的时间"
 		br.ErrMsg = "请选择正确的时间"
 		return
@@ -489,7 +512,7 @@ func (this *EnglishReportController) ListReport() {
 		fieldArr := []string{
 			"id", "add_type", "classify_id_first", "classify_name_first", "classify_id_second", "classify_name_second", "title", "abstract", "author",
 			"frequency", "create_time", "modify_time", "state", "publish_time", "pre_publish_time", "stage", "msg_is_send", "report_code", "pv", "share_url",
-			"pv_email", "email_state", "from_report_id", "key_takeaways", "admin_id", "admin_real_name",
+			"pv_email", "email_state", "from_report_id", "key_takeaways", "admin_id", "admin_real_name", "approve_time",
 		}
 		items, e := models.GetEnglishReportList(condition, pars, companyType, startSize, pageSize, fieldArr)
 		if e != nil {
@@ -643,6 +666,7 @@ func (this *EnglishReportController) ListReport() {
 	br.Data = resp
 }
 
+// PublishReport
 // @Title 发布报告接口
 // @Description 发布报告
 // @Param	request	body models.PublishReq true "type json string"
@@ -687,6 +711,15 @@ func (this *EnglishReportController) PublishReport() {
 			return
 		}
 
+		// 图表刷新状态
+		refreshResult := data.CheckBatchChartRefreshResult("report", vint, 0)
+		if !refreshResult {
+			br.Msg = "图表刷新未完成,请稍后操作"
+			br.ErrMsg = "图表刷新未完成,请稍后操作"
+			br.IsSendEmail = false
+			return
+		}
+
 		var tmpErr error
 
 		if report.Content == "" {
@@ -701,14 +734,33 @@ func (this *EnglishReportController) PublishReport() {
 		} else {
 			publishTime = time.Now().Format(utils.FormatDateTime)
 		}
-		if tmpErr = models.PublishEnglishReportById(report.Id, publishTime); tmpErr != nil {
-			br.Msg = "报告发布失败"
-			br.ErrMsg = "报告发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(report.Id)
+
+		// 根据审批开关及审批流判断当前报告状态
+		state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, report.ClassifyIdFirst, report.ClassifyIdSecond, models.ReportOperatePublish)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
 			return
 		}
-		go func() {
-			_ = services.UpdateEnglishReportEs(report.Id, 2)
-		}()
+
+		if state == models.ReportStatePublished {
+			// 发布报告
+			if tmpErr = models.PublishEnglishReportById(report.Id, publishTime); tmpErr != nil {
+				br.Msg = "报告发布失败"
+				br.ErrMsg = "报告发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(report.Id)
+				return
+			}
+			go func() {
+				_ = services.UpdateEnglishReportEs(report.Id, 2)
+			}()
+		} else {
+			// 从无审批切换为有审批, 状态重置
+			if e = models.ResetEnglishReportById(report.Id, state); tmpErr != nil {
+				br.Msg = "操作失败"
+				br.ErrMsg = fmt.Sprintf("重置英文报告状态失败, Err: %s, ReportId: %d", e.Error(), report.Id)
+				return
+			}
+		}
 	}
 
 	br.Ret = 200
@@ -781,6 +833,18 @@ func (this *EnglishReportController) PrePublishReport() {
 		return
 	}
 
+	// 校验是否开启了审批流
+	opening, e := services.CheckReportOpenApprove(report_approve.FlowReportTypeEnglish, report.ClassifyIdFirst, report.ClassifyIdSecond)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告是否开启审批流失败, Err: " + e.Error()
+		return
+	}
+	if opening {
+		br.Msg = "报告已开启审批流, 不可设置定时发布"
+		return
+	}
+
 	var tmpErr error
 	if tmpErr = models.SetPrePublishEnglishReportById(report.Id, req.PrePublishTime); tmpErr != nil {
 		br.Msg = "设置定时发布失败"
@@ -816,7 +880,22 @@ func (this *EnglishReportController) PublishCancleReport() {
 		br.ErrMsg = "参数错误,报告id不可为空"
 		return
 	}
-	err = models.PublishCancelEnglishReport(req.ReportIds)
+	reportInfo, err := models.GetEnglishReportById(req.ReportIds)
+	if err != nil {
+		br.Msg = "获取报告信息失败"
+		br.ErrMsg = "获取报告信息失败,Err:" + err.Error()
+		return
+	}
+
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, models.ReportOperateCancelPublish)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
+	err = models.PublishCancelEnglishReport(req.ReportIds, state)
 	if err != nil {
 		br.Msg = "取消发布失败"
 		br.ErrMsg = "取消发布失败,Err:" + err.Error()
@@ -1056,7 +1135,7 @@ func (this *EnglishReportController) Author() {
 
 	if keyword != `` {
 		condition += ` AND report_author like ? `
-		pars = append(pars, "%"+keyword+"%")
+		pars = append(pars, utils.GetLikeKeyword(keyword))
 	}
 
 	_, items, err := models.GetReportAuthorList(condition, pars, 0, 10000)
@@ -1221,3 +1300,190 @@ func (this *EnglishReportController) EditPolicy() {
 	br.Msg = "保存成功"
 	br.Data = resp
 }
+
+// SubmitApprove
+// @Title 提交审批
+// @Description 提交审批接口
+// @Param	request	body models.ReportSubmitApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/submit [post]
+func (this *EnglishReportController) SubmitApprove() {
+	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"
+		return
+	}
+	var req models.ReportSubmitApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.EnglishReport)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待审批时, 仅更新状态
+	if state != models.ReportStateWaitApprove {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 提交审批
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "提交审批失败, Err: " + e.Error()
+		return
+	}
+	reportItem.ApproveId = approveId
+	reportItem.State = models.ReportStateWaitApprove
+	reportItem.ModifyTime = time.Now().Local()
+	e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// CancelApprove
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body models.ReportCancelApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/cancel [post]
+func (this *EnglishReportController) CancelApprove() {
+	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"
+		return
+	}
+	var req models.ReportCancelApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.EnglishReport)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待提交时, 仅更新状态
+	if state != models.ReportStateWaitSubmit {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+	//if reportItem.ApproveId <= 0 {
+	//	br.Msg = "报告审批不存在"
+	//	br.ErrMsg = fmt.Sprintf("报告审批不存在, ApproveId: %d", reportItem.ApproveId)
+	//	return
+	//}
+
+	// 撤销审批
+	e = services.CancelReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.ApproveId, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "撤销审批失败, Err: " + e.Error()
+		return
+	}
+	//reportItem.ApproveId = 0
+	//reportItem.State = models.ReportStateWaitSubmit
+	//reportItem.ModifyTime = time.Now().Local()
+	//e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	//if e != nil {
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+	//	return
+	//}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 21 - 0
controllers/error.go

@@ -0,0 +1,21 @@
+package controllers
+
+import "eta/eta_api/models"
+
+// ErrorController
+// @Description: 该控制器处理页面错误请求
+type ErrorController struct {
+	BaseCommonController
+}
+
+func (c *ErrorController) Error404() {
+	c.Data["content"] = "很抱歉您访问的地址或者方法不存在"
+	//c.TplName = "error/404.html"
+
+	br := new(models.BaseResponse).Init()
+
+	br.Msg = "您访问的资源不存在"
+	br.Ret = 404
+	c.Data["json"] = br
+	c.ServeJSON()
+}

+ 104 - 11
controllers/ppt_english.go

@@ -68,7 +68,7 @@ func (this *PptEnglishController) ListPpt() {
 
 	if keyWord != "" {
 		condition += ` AND (title LIKE ? OR admin_real_name LIKE ? ) `
-		pars = append(pars, "%"+keyWord+"%", "%"+keyWord+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	}
 	total, err := ppt_english.GetPptEnglishListCount(condition, pars)
 
@@ -359,9 +359,19 @@ func (this *PptEnglishController) DeletePpt() {
 func (this *PptEnglishController) DetailPpt() {
 	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
+	}
 	pptId, _ := this.GetInt("PptId")
 
 	pptInfo, err := ppt_english.GetPptEnglishById(pptId)
@@ -371,10 +381,21 @@ func (this *PptEnglishController) DetailPpt() {
 		return
 	}
 
+	// 查询编辑中
+	editor, e := services.UpdatePptEditing(pptId, 0, sysUser.AdminId, sysUser.RealName, true)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+		return
+	}
+	resp := new(ppt_english.EnglishPPTDetailResp)
+	resp.PptEnglish = pptInfo
+	resp.Editor = editor
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
-	br.Data = pptInfo
+	br.Data = resp
 }
 
 // DownloadPptx
@@ -574,9 +595,19 @@ func (this *PptEnglishController) PptUpload() {
 func (this *PptEnglishController) SaveLog() {
 	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 ppt_english.AddPptEnglishReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -603,17 +634,26 @@ func (this *PptEnglishController) SaveLog() {
 	}
 
 	//变更ppt内容
-	_, err = ppt_english.GetPptEnglishById(int(req.PptId))
-	if err != nil {
-		br.Msg = "信息获取失败"
-		br.ErrMsg = "信息获取失败,Err:" + err.Error()
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "PPT已删除"
-			br.ErrMsg = "PPT已删除"
-			br.IsSendEmail = false
+	pptItem, e := ppt_english.GetPptEnglishById(int(req.PptId))
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "PPT已被删除, 请刷新页面"
+			return
 		}
+		br.Msg = "信息获取失败"
+		br.ErrMsg = "信息获取失败,Err:" + e.Error()
 		return
 	}
+
+	// 标记编辑状态
+	if pptItem.PptId > 0 {
+		_, e = services.UpdatePptEditing(pptItem.PptId, 1, sysUser.AdminId, sysUser.RealName, true)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+			return
+		}
+	}
 	//pptInfo.TemplateType = req.FirstPage.TemplateType
 	//pptInfo.BackgroundImg = req.FirstPage.ImgUrl
 	//pptInfo.Title = req.FirstPage.Title
@@ -638,7 +678,9 @@ func (this *PptEnglishController) SaveLog() {
 	}
 	_, err = ppt_english.AddPptEnglishSaveLog(logInfo)
 	if err != nil {
-
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存PPT日志失败, Err: " + err.Error()
+		return
 	}
 	br.Ret = 200
 	br.Success = true
@@ -935,3 +977,54 @@ func (this *PptEnglishController) TitleCheck() {
 	br.Success = true
 	br.Msg = "校验成功"
 }
+
+// Editing
+// @Title 标记编辑状态
+// @Description 标记编辑状态
+// @Param	request	body models.PPTEditingReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /editing [post]
+func (this *PptEnglishController) Editing() {
+	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 models.PPTEditingReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.PptId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	if req.Status <= 0 {
+		br.Msg = "标记状态异常"
+		return
+	}
+
+	editor, e := services.UpdatePptEditing(req.PptId, req.Status, sysUser.AdminId, sysUser.RealName, true)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+		return
+	}
+
+	br.Data = editor
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 106 - 8
controllers/ppt_v2.go

@@ -69,7 +69,7 @@ func (this *PptV2Controller) ListPpt() {
 
 	if keyWord != "" {
 		condition += ` AND (title LIKE ? OR admin_real_name LIKE ? ) `
-		pars = append(pars, "%"+keyWord+"%", "%"+keyWord+"%")
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	}
 	total, err := models.GetPptV2ListCount(condition, pars)
 	if err != nil {
@@ -360,9 +360,19 @@ func (this *PptV2Controller) DeletePpt() {
 func (this *PptV2Controller) DetailPpt() {
 	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
+	}
 	pptId, _ := this.GetInt("PptId")
 
 	pptInfo, err := models.GetPptV2ById(pptId)
@@ -372,10 +382,21 @@ func (this *PptV2Controller) DetailPpt() {
 		return
 	}
 
+	// 编辑中
+	editor, e := services.UpdatePptEditing(pptId, 0, sysUser.AdminId, sysUser.RealName, false)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+		return
+	}
+	resp := new(models.PPTDetailResp)
+	resp.PptV2 = pptInfo
+	resp.Editor = editor
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
-	br.Data = pptInfo
+	br.Data = resp
 }
 
 // DownloadPptx
@@ -575,9 +596,19 @@ func (this *PptV2Controller) PptUpload() {
 func (this *PptV2Controller) SaveLog() {
 	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 models.AddPptV2Req
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
@@ -604,12 +635,26 @@ func (this *PptV2Controller) SaveLog() {
 	}
 
 	//变更ppt内容
-	_, err = models.GetPptV2ById(int(req.PptId))
-	if err != nil {
+	pptItem, e := models.GetPptV2ById(int(req.PptId))
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "PPT已被删除, 请刷新页面"
+			return
+		}
 		br.Msg = "信息获取失败"
-		br.ErrMsg = "信息获取失败,Err:" + err.Error()
+		br.ErrMsg = "信息获取失败,Err:" + e.Error()
 		return
 	}
+
+	// 标记编辑状态
+	if pptItem.PptId > 0 {
+		_, e = services.UpdatePptEditing(pptItem.PptId, 1, sysUser.AdminId, sysUser.RealName, false)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+			return
+		}
+	}
 	//pptInfo.TemplateType = req.FirstPage.TemplateType
 	//pptInfo.BackgroundImg = req.FirstPage.ImgUrl
 	//pptInfo.Title = req.FirstPage.Title
@@ -632,9 +677,11 @@ func (this *PptV2Controller) SaveLog() {
 		AdminRealName: this.SysUser.RealName,
 		CreateTime:    time.Now(),
 	}
-	_, err = models.AddPptV2SaveLog(logInfo)
-	if err != nil {
-
+	_, e = models.AddPptV2SaveLog(logInfo)
+	if e != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存PPT日志失败, Err: " + e.Error()
+		return
 	}
 	br.Ret = 200
 	br.Success = true
@@ -1129,3 +1176,54 @@ func (this *PptV2Controller) TitleCheck() {
 	br.Success = true
 	br.Msg = "校验成功"
 }
+
+// Editing
+// @Title 标记编辑状态
+// @Description 标记编辑状态
+// @Param	request	body models.PPTEditingReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /editing [post]
+func (this *PptV2Controller) Editing() {
+	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 models.PPTEditingReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.PptId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	if req.Status <= 0 {
+		br.Msg = "标记状态异常"
+		return
+	}
+
+	editor, e := services.UpdatePptEditing(req.PptId, req.Status, sysUser.AdminId, sysUser.RealName, false)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+		return
+	}
+
+	br.Data = editor
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 333 - 59
controllers/report.go

@@ -3,9 +3,10 @@ package controllers
 import (
 	"encoding/json"
 	"eta/eta_api/models"
-	"eta/eta_api/models/company"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/services"
 	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/server/web"
@@ -40,7 +41,7 @@ type ReportUploadCommonController struct {
 // @Description 获取报告列表
 // @Param   PageSize   query   int  true       "每页数据条数"
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
-// @Param   TimeType     query string true  "筛选的时间类别:publish_time(发布时间),modify_time(更新时间)"
+// @Param   TimeType     query string true  "筛选的时间类别:publish_time(发布时间),modify_time(更新时间);approve_time(审批时间)"
 // @Param   StartDate   query   string  true       "开始时间"
 // @Param   EndDate   query   string  true       "结束时间"
 // @Param   Frequency   query   string  true       "频度"
@@ -84,7 +85,7 @@ func (this *ReportController) ListReport() {
 	if timeType == "" {
 		timeType = "publish_time"
 	}
-	if timeType != "publish_time" && timeType != "modify_time" {
+	if timeType != "publish_time" && timeType != "modify_time" && timeType != "approve_time" {
 		br.Msg = "请选择正确的时间"
 		br.ErrMsg = "请选择正确的时间"
 		return
@@ -94,7 +95,8 @@ func (this *ReportController) ListReport() {
 	var pars []interface{}
 
 	if keyWord != "" {
-		condition += ` AND (title LIKE '%` + keyWord + `%' OR admin_real_name LIKE '%` + keyWord + `%' ) `
+		condition += ` AND (title LIKE ? OR admin_real_name LIKE ? ) `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	}
 	if startDate != "" {
 		condition += ` AND ` + timeType + ` >= ? `
@@ -264,6 +266,8 @@ func (this *ReportController) PublishReport() {
 		br.ErrMsg = "参数错误,报告id不可为空"
 		return
 	}
+
+	// 这里实际上不会批量发布了...
 	reportArr := strings.Split(reportIds, ",")
 	tips := ""
 	for _, v := range reportArr {
@@ -283,6 +287,15 @@ func (this *ReportController) PublishReport() {
 			br.Msg = "报告不存在"
 			return
 		}
+
+		refreshResult := data.CheckBatchChartRefreshResult("report", vint, 0)
+		if !refreshResult {
+			br.Msg = "图表刷新未完成,请稍后操作"
+			br.ErrMsg = "图表刷新未完成,请稍后操作"
+			br.IsSendEmail = false
+			return
+		}
+
 		var publishTime time.Time
 		if report.MsgIsSend == 1 && report.PublishTime != "" { //如果报告曾经发布过,并且已经发送过模版消息,则章节的发布时间为报告的发布时间
 			publishTime, _ = time.ParseInLocation(utils.FormatDateTime, report.PublishTime, time.Local)
@@ -303,28 +316,47 @@ func (this *ReportController) PublishReport() {
 				br.ErrMsg = "报告内容为空,不需要生成,report_id:" + strconv.Itoa(report.Id)
 				return
 			}
-			if tmpErr = models.PublishReportById(report.Id, publishTime); tmpErr != nil {
-				br.Msg = "报告发布失败"
-				br.ErrMsg = "报告发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(report.Id)
+
+			// 根据审批开关及审批流判断当前报告状态
+			state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, report.ClassifyIdFirst, report.ClassifyIdSecond, models.ReportOperatePublish)
+			if e != nil {
+				br.Msg = "操作失败"
+				br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
 				return
 			}
 
-			go func() {
-				// 生成音频
-				if report.VideoUrl == "" {
-					_ = services.CreateVideo(report)
+			if state == models.ReportStatePublished {
+				// 发布报告
+				if tmpErr = models.PublishReportById(report.Id, publishTime); tmpErr != nil {
+					br.Msg = "报告发布失败"
+					br.ErrMsg = "报告发布失败, Err:" + tmpErr.Error() + ", report_id:" + strconv.Itoa(report.Id)
+					return
 				}
-				//// 推送找钢网
-				//if utils.RunMode == "release" && (report.ClassifyNameSecond == "知白守黑日评" || report.ClassifyNameSecond == "股债日评") {
-				//	_ = services.ZhaoGangSend(report)
-				//}
-				// 更新报告Es
-				_ = services.UpdateReportEs(report.Id, 2)
-			}()
+				go func() {
+					// 生成音频
+					if report.VideoUrl == "" {
+						_ = services.CreateVideo(report)
+					}
+					//// 推送找钢网
+					//if utils.RunMode == "release" && (report.ClassifyNameSecond == "知白守黑日评" || report.ClassifyNameSecond == "股债日评") {
+					//	_ = services.ZhaoGangSend(report)
+					//}
+					// 更新报告Es
+					_ = services.UpdateReportEs(report.Id, 2)
+				}()
+			} else {
+				// 从无审批切换为有审批, 状态重置
+				if e = models.ResetReportById(report.Id, state); tmpErr != nil {
+					br.Msg = "操作失败"
+					br.ErrMsg = fmt.Sprintf("重置报告状态失败, Err: %s, ReportId: %d", e.Error(), report.Id)
+					return
+				}
+			}
+
 			recordItem := &models.ReportStateRecord{
 				ReportId:   vint,
 				ReportType: 1,
-				State:      2,
+				State:      state,
 				AdminId:    this.SysUser.AdminId,
 				AdminName:  this.SysUser.AdminName,
 				CreateTime: time.Now(),
@@ -378,7 +410,16 @@ func (this *ReportController) PublishCancleReport() {
 	if reportInfo.MsgIsSend == 1 {
 		publishTimeNullFlag = false
 	}
-	err = models.PublishCancleReport(req.ReportIds, publishTimeNullFlag)
+
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, models.ReportOperateCancelPublish)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
+	err = models.PublishCancelReport(req.ReportIds, state, publishTimeNullFlag)
 	if err != nil {
 		br.Msg = "取消发布失败"
 		br.ErrMsg = "取消发布失败,Err:" + err.Error()
@@ -389,24 +430,24 @@ func (this *ReportController) PublishCancleReport() {
 		go services.UpdateReportEs(req.ReportIds, 1)
 	}
 
-	// 获取审批流设置
-	confKey := "approval_flow"
-	confTmp, e := company.GetConfigDetailByCode(confKey)
-	if e != nil {
-		br.Msg = "获取审批流配置失败"
-		br.ErrMsg = "获取审批流配置失败, Err: " + e.Error()
-		return
-	}
-	if confTmp.ConfigValue == "1" || confTmp.ConfigValue == "2" || confTmp.ConfigValue == "3" {
-		br.Msg = "撤销成功"
-	} else {
-		br.Msg = "取消发布成功"
-	}
+	//// 获取审批流设置
+	//confKey := "approval_flow"
+	//confTmp, e := company.GetConfigDetailByCode(confKey)
+	//if e != nil {
+	//	br.Msg = "获取审批流配置失败"
+	//	br.ErrMsg = "获取审批流配置失败, Err: " + e.Error()
+	//	return
+	//}
+	//if confTmp.ConfigValue == "1" || confTmp.ConfigValue == "2" || confTmp.ConfigValue == "3" {
+	//	br.Msg = "撤销成功"
+	//} else {
+	//	br.Msg = "取消发布成功"
+	//}
 
 	recordItem := &models.ReportStateRecord{
 		ReportId:   req.ReportIds,
 		ReportType: 1,
-		State:      1,
+		State:      state,
 		AdminId:    this.SysUser.AdminId,
 		AdminName:  this.SysUser.AdminName,
 		CreateTime: time.Now(),
@@ -503,6 +544,14 @@ func (this *ReportController) Add() {
 		return
 	}
 
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
 	item := new(models.Report)
 	item.AddType = req.AddType
 	item.ClassifyIdFirst = req.ClassifyIdFirst
@@ -513,7 +562,7 @@ func (this *ReportController) Add() {
 	item.Abstract = req.Abstract
 	item.Author = req.Author
 	item.Frequency = req.Frequency
-	item.State = req.State
+	item.State = state
 	item.Content = html.EscapeString(req.Content)
 	item.Stage = maxStage + 1
 	item.ContentSub = html.EscapeString(contentSub)
@@ -634,34 +683,41 @@ func (this *ReportController) Edit() {
 	}
 
 	var stage int
-	report, _ := models.GetReportById(int(req.ReportId))
-	if report != nil {
-		if report.ClassifyNameFirst != req.ClassifyNameFirst || report.ClassifyNameSecond != req.ClassifyNameSecond {
-			maxStage, _ := models.GetReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, int(req.ReportId))
-			maxStage = maxStage + 1
-			stage = maxStage
-		} else {
-			stage = report.Stage
+	report, e := models.GetReportById(int(req.ReportId))
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
 		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
 	}
-	if report.State == 2 {
+	if report.State == models.ReportStatePublished || report.State == models.ReportStatePass {
 		br.Msg = "该报告已发布,不允许编辑"
 		br.ErrMsg = "该报告已发布,不允许编辑"
 		return
 	}
-	if req.State != report.State {
-		recordItem := &models.ReportStateRecord{
-			ReportId:   int(req.ReportId),
-			ReportType: 1,
-			State:      req.State,
-			AdminId:    this.SysUser.AdminId,
-			AdminName:  this.SysUser.AdminName,
-			CreateTime: time.Now(),
-		}
-		go func() {
-			_, _ = models.AddReportStateRecord(recordItem)
-		}()
-	}
+	if report.ClassifyNameFirst != req.ClassifyNameFirst || report.ClassifyNameSecond != req.ClassifyNameSecond {
+		maxStage, _ := models.GetReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, int(req.ReportId))
+		maxStage = maxStage + 1
+		stage = maxStage
+	} else {
+		stage = report.Stage
+	}
+	//if req.State != report.State {
+	//	recordItem := &models.ReportStateRecord{
+	//		ReportId:   int(req.ReportId),
+	//		ReportType: 1,
+	//		State:      req.State,
+	//		AdminId:    this.SysUser.AdminId,
+	//		AdminName:  this.SysUser.AdminName,
+	//		CreateTime: time.Now(),
+	//	}
+	//	go func() {
+	//		_, _ = models.AddReportStateRecord(recordItem)
+	//	}()
+	//}
 
 	item := new(models.Report)
 	item.ClassifyIdFirst = req.ClassifyIdFirst
@@ -672,7 +728,7 @@ func (this *ReportController) Edit() {
 	item.Abstract = req.Abstract
 	item.Author = req.Author
 	item.Frequency = req.Frequency
-	item.State = req.State
+	item.State = report.State // 编辑不变更状态
 	item.Stage = stage
 	item.Content = html.EscapeString(req.Content)
 	item.ContentSub = html.EscapeString(contentSub)
@@ -1046,7 +1102,7 @@ func (this *ReportController) Author() {
 
 	if keyword != `` {
 		condition += ` AND report_author like ? `
-		pars = append(pars, "%"+keyword+"%")
+		pars = append(pars, utils.GetLikeKeyword(keyword))
 	}
 
 	_, items, err := models.GetReportAuthorList(condition, pars, 0, 10000)
@@ -2738,6 +2794,15 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 		return
 	}
 
+	// 图表刷新状态
+	refreshResult := data.CheckBatchChartRefreshResult("report", chapterInfo.ReportId, chapterInfo.ReportChapterId)
+	if !refreshResult {
+		br.Msg = "图表刷新未完成,请稍后操作"
+		br.ErrMsg = "图表刷新未完成,请稍后操作"
+		br.IsSendEmail = false
+		return
+	}
+
 	// 获取规则配置
 	reportChapterTypeRule, err := models.GetReportChapterTypeById(chapterInfo.TypeId)
 	if err != nil {
@@ -2910,6 +2975,16 @@ func (this *ReportController) PublishDayWeekReport() {
 		br.Msg = "该报告已发布"
 		return
 	}
+
+	// 图表刷新状态
+	refreshResult := data.CheckBatchChartRefreshResult("report", reportId, 0)
+	if !refreshResult {
+		br.Msg = "图表刷新未完成,请稍后操作"
+		br.ErrMsg = "图表刷新未完成,请稍后操作"
+		br.IsSendEmail = false
+		return
+	}
+
 	tips, err := services.PublishDayWeekReport(reportId)
 	if err != nil {
 		br.Msg = "发布失败"
@@ -3330,6 +3405,18 @@ func (this *ReportController) PrePublishReport() {
 		return
 	}
 
+	// 校验是否开启了审批流
+	opening, e := services.CheckReportOpenApprove(report_approve.FlowReportTypeChinese, report.ClassifyIdFirst, report.ClassifyIdSecond)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告是否开启审批流失败, Err: " + e.Error()
+		return
+	}
+	if opening {
+		br.Msg = "报告已开启审批流, 不可设置定时发布"
+		return
+	}
+
 	var tmpErr error
 	if tmpErr = models.SetPrePublishReportById(report.Id, req.PrePublishTime, req.PreMsgSend); tmpErr != nil {
 		br.Msg = "设置定时发布失败"
@@ -3341,3 +3428,190 @@ func (this *ReportController) PrePublishReport() {
 	br.Success = true
 	br.Msg = "定时发布成功"
 }
+
+// SubmitApprove
+// @Title 提交审批
+// @Description 提交审批接口
+// @Param	request	body models.ReportSubmitApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/submit [post]
+func (this *ReportController) SubmitApprove() {
+	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"
+		return
+	}
+	var req models.ReportSubmitApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.Report)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待审批时, 仅更新状态
+	if state != models.ReportStateWaitApprove {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 提交审批
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeChinese, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "提交审批失败, Err: " + e.Error()
+		return
+	}
+	reportItem.ApproveId = approveId
+	reportItem.State = models.ReportStateWaitApprove
+	reportItem.ModifyTime = time.Now().Local()
+	e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// CancelApprove
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body models.ReportCancelApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/cancel [post]
+func (this *ReportController) CancelApprove() {
+	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"
+		return
+	}
+	var req models.ReportCancelApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(models.Report)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待提交时, 仅更新状态
+	if state != models.ReportStateWaitSubmit {
+		reportItem.State = state
+		e = reportItem.UpdateReport([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+	//if reportItem.ApproveId <= 0 {
+	//	br.Msg = "报告审批不存在"
+	//	br.ErrMsg = fmt.Sprintf("报告审批不存在, ApproveId: %d", reportItem.ApproveId)
+	//	return
+	//}
+
+	// 撤销审批
+	e = services.CancelReportApprove(report_approve.FlowReportTypeChinese, reportItem.Id, reportItem.ApproveId, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "撤销审批失败, Err: " + e.Error()
+		return
+	}
+	//reportItem.ApproveId = 0
+	//reportItem.State = models.ReportStateWaitSubmit
+	//reportItem.ModifyTime = time.Now().Local()
+	//e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	//if e != nil {
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+	//	return
+	//}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 931 - 0
controllers/report_approve/report_approve.go

@@ -0,0 +1,931 @@
+package report_approve
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"sort"
+	"strings"
+	"time"
+)
+
+// ReportApproveController 报告审批
+type ReportApproveController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 审批列表
+// @Description 审批列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Param   ListType			query   int     true	"列表类型:1-待处理;2-已处理;3-我发起的"
+// @Param   ReportType			query   int     false	"报告类型:1-中文研报;2-英文研报;3-智能研报"
+// @Param   ClassifyIdFirst		query	int		false	"一级分类ID"
+// @Param   ClassifyIdSecond	query	int		false	"二级分类ID"
+// @Param   Keyword				query	string	false	"搜索关键词"
+// @Param   ApproveState		query	int		false	"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"
+// @Param   TimeType			query	int		false	"时间类型:1-提交时间;2-处理时间;3-审批时间"
+// @Param   StartTime			query	string	false	"开始时间"
+// @Param   EndTime				query	string	false	"结束时间"
+// @Param   SortField			query	int		false	"排序字段:1-提交时间;2-处理时间;3-审批时间"
+// @Param   SortRule			query	int		false	"排序方式: 1-正序; 2-倒序(默认)"
+// @Success 200 {object} report_approve.ReportApproveListResp
+// @router /list [get]
+func (this *ReportApproveController) 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
+	}
+	params := new(report_approve.ReportApproveListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+	if params.ListType != 1 && params.ListType != 2 && params.ListType != 3 {
+		br.Msg = "列表类型有误"
+		return
+	}
+
+	// 报告分类
+	cnClassifyIdName, enClassifyIdName := make(map[int]string), make(map[int]string)
+	cnClassify, e := models.GetAllClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取中文分类失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range cnClassify {
+		cnClassifyIdName[v.Id] = v.ClassifyName
+	}
+	enClassify, e := models.GetEnglishClassifies()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文分类失败, Err: " + e.Error()
+		return
+	}
+	enRootIdMap := make(map[int]int) // 英文分类的一级分类ID
+	for _, v := range enClassify {
+		enClassifyIdName[v.Id] = v.ClassifyName
+		enRootIdMap[v.Id] = v.RootId
+	}
+
+	// 分页
+	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)
+
+	resp := new(report_approve.ReportApproveListResp)
+	respTotal := 0
+	respList := make([]*report_approve.ReportApproveItem, 0)
+	timeField := map[int]string{1: fmt.Sprintf("a.%s", report_approve.ReportApproveCols.CreateTime), 2: fmt.Sprintf("a.%s", report_approve.ReportApproveRecordCols.ApproveTime), 3: fmt.Sprintf("b.%s", report_approve.ReportApproveCols.ApproveTime)}
+	mineTimeField := map[int]string{1: fmt.Sprintf("%s", report_approve.ReportApproveCols.CreateTime), 3: fmt.Sprintf("%s", report_approve.ReportApproveCols.ApproveTime)}
+	orderRules := map[int]string{1: "ASC", 2: "DESC"}
+	ormList := make([]*report_approve.ReportApproveItemOrm, 0)
+
+	// 待处理
+	if params.ListType == 1 {
+		cond := fmt.Sprintf(` AND a.%s = ? AND b.%s = ? AND a.%s = ?`, report_approve.ReportApproveRecordCols.State, report_approve.ReportApproveCols.State, report_approve.ReportApproveRecordCols.ApproveUserId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, report_approve.ReportApproveStateApproving, report_approve.ReportApproveStateApproving, sysUser.AdminId)
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ? AND b.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType <= 0 {
+			params.TimeType = 1
+		}
+		if params.TimeType == 1 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			cond += fmt.Sprintf(` AND (b.%s BETWEEN ? AND ?)`, report_approve.ReportApproveCols.CreateTime)
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND b.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := timeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		total, e := report_approve.GetApprovingReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovingReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApprovingReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovingReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 已处理
+	if params.ListType == 2 {
+		cond := fmt.Sprintf(` AND a.%s = ? AND a.%s IN (%s)`, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State, utils.GetOrmInReplace(2))
+		pars := make([]interface{}, 0)
+		pars = append(pars, sysUser.AdminId, []int{report_approve.ReportApproveStatePass, report_approve.ReportApproveStateRefuse})
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ? AND b.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			cond += fmt.Sprintf(` AND (%s BETWEEN ? AND ?)`, timeField[params.TimeType])
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND b.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := timeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		if params.ApproveState > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveRecordCols.State)
+			pars = append(pars, params.ApproveState)
+		}
+		total, e := report_approve.GetApprovedReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovedReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApprovedReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApprovedReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 我发起的
+	if params.ListType == 3 {
+		cond := fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ApplyUserId)
+		pars := make([]interface{}, 0)
+		pars = append(pars, sysUser.AdminId)
+		order := ""
+
+		// 筛选条件
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ? AND a.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
+			_, e := time.Parse(utils.FormatDate, params.StartTime)
+			if e != nil {
+				br.Msg = "开始时间格式有误"
+				return
+			}
+			_, e = time.Parse(utils.FormatDate, params.EndTime)
+			if e != nil {
+				br.Msg = "结束时间格式有误"
+				return
+			}
+			st := fmt.Sprintf("%s %s", params.StartTime, "00:00:00")
+			ed := fmt.Sprintf("%s %s", params.EndTime, "23:59:59")
+			field := mineTimeField[params.TimeType]
+			if field == "" {
+				br.Msg = "筛选时间有误"
+				return
+			}
+			cond += fmt.Sprintf(` AND (%s BETWEEN ? AND ?)`, field)
+			pars = append(pars, st, ed)
+		}
+		params.Keyword = strings.TrimSpace(params.Keyword)
+		if params.Keyword != "" {
+			kw := fmt.Sprint("%", params.Keyword, "%")
+			cond += fmt.Sprintf(` AND a.%s LIKE ?`, report_approve.ReportApproveCols.ReportTitle)
+			pars = append(pars, kw)
+		}
+		if params.SortField > 0 && params.SortRule > 0 {
+			orderField := mineTimeField[params.SortField]
+			if orderField == "" {
+				br.Msg = "时间排序字段有误"
+				return
+			}
+			orderRule := orderRules[params.SortRule]
+			if orderRule == "" {
+				br.Msg = "时间排序方式有误"
+				return
+			}
+			order = fmt.Sprintf("%s %s", orderField, orderRule)
+		}
+		if params.ApproveState > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveRecordCols.State)
+			pars = append(pars, params.ApproveState)
+		}
+		total, e := report_approve.GetApplyReportApproveCount(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApplyReportApproveCount err: " + e.Error()
+			return
+		}
+		respTotal = total
+		list, e := report_approve.GetApplyReportApprovePageList(cond, pars, order, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "GetApplyReportApprovePageList err: " + e.Error()
+			return
+		}
+		ormList = list
+	}
+
+	// 格式化列表
+	for _, v := range ormList {
+		t := report_approve.FormatReportApproveOrm2Item(v)
+		if v.ReportType == report_approve.FlowReportTypeEnglish {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], enClassifyIdName[v.ClassifyFirstId], enClassifyIdName[v.ClassifySecondId])
+		} else {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId], cnClassifyIdName[v.ClassifySecondId])
+		}
+		respList = append(respList, t)
+	}
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, respTotal)
+	resp.Paging = page
+	resp.List = respList
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Detail
+// @Title 审批详情
+// @Description 审批详情
+// @Param   ReportApproveId  query  int  true  "审批ID"
+// @Success 200 {object} report_approve.ReportApproveDetail
+// @router /detail [get]
+func (this *ReportApproveController) Detail() {
+	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
+	}
+	approveId, _ := this.GetInt("ReportApproveId")
+	if approveId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveId: %d", approveId)
+		return
+	}
+
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(approveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批信息
+	detail := new(report_approve.ReportApproveDetail)
+	detail.Approve = new(report_approve.ReportApproveDetailItem)
+	detail.Approve.ReportApproveId = approveItem.ReportApproveId
+	detail.Approve.State = approveItem.State
+	detail.Approve.FlowId = approveItem.FlowId
+	detail.Approve.FlowVersion = approveItem.FlowVersion
+	detail.Approve.StartNodeId = approveItem.StartNodeId
+	detail.Approve.CurrNodeId = approveItem.CurrNodeId
+	detail.Approve.ApplyUserId = approveItem.ApplyUserId
+	detail.Approve.ApplyUserName = approveItem.ApplyUserName
+	detail.Approve.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.ApproveTime)
+	detail.Approve.CreateTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.CreateTime)
+	detail.Approve.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, approveItem.ModifyTime)
+
+	// 审批流
+	//flowOb := new(report_approve.ReportApproveFlow)
+	//flowItem, e := flowOb.GetItemById(approveItem.FlowId)
+	//if e != nil {
+	//	if e.Error() == utils.ErrNoRow() {
+	//		br.Msg = "审批流已被删除, 请刷新页面"
+	//		return
+	//	}
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取审批流失败, Err: " + e.Error()
+	//	return
+	//}
+	//detail.ApproveFlow = report_approve.FormatReportApproveFlow2Item(flowItem)
+
+	// 审批节点
+	nodeOb := new(report_approve.ReportApproveNode)
+	nodeCond := fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveNodeCols.ReportApproveFlowId, report_approve.ReportApproveNodeCols.CurrVersion)
+	nodePars := make([]interface{}, 0)
+	nodePars = append(nodePars, approveItem.FlowId, approveItem.FlowVersion)
+	nodeItems, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批节点失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批记录
+	recordOb := new(report_approve.ReportApproveRecord)
+	recordCond := fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveRecordCols.ReportApproveId)
+	recordPars := make([]interface{}, 0)
+	recordPars = append(recordPars, approveItem.ReportApproveId)
+	recordItems, e := recordOb.GetItemsByCondition(recordCond, recordPars, []string{}, fmt.Sprintf("%s DESC", report_approve.ReportApproveRecordCols.ApproveTime))
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批记录失败, Err: " + e.Error()
+		return
+	}
+	recordMap := make(map[string]*report_approve.ReportApproveRecord)
+	for _, v := range recordItems {
+		k := fmt.Sprintf("%d-%d", v.NodeId, v.ApproveUserId)
+		recordMap[k] = v
+	}
+
+	// 审批流节点详情
+	detail.ApproveFlowNodes = make([]*report_approve.ReportApproveDetailNodes, 0)
+	for _, v := range nodeItems {
+		t := new(report_approve.ReportApproveDetailNodes)
+		t.ReportApproveNodeId = v.ReportApproveNodeId
+		t.ReportApproveFlowId = v.ReportApproveFlowId
+		t.PrevNodeId = v.PrevNodeId
+		t.NextNodeId = v.NextNodeId
+		t.NodeType = v.NodeType
+		t.ApproveType = v.ApproveType
+		t.Users = make([]*report_approve.ReportApproveDetailNodeUser, 0)
+		us := make([]*report_approve.ReportApproveNodeUserReq, 0)
+		if v.Users != "" {
+			e = json.Unmarshal([]byte(v.Users), &us)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "节点用户解析失败, Err: " + e.Error()
+				return
+			}
+		}
+		for _, vu := range us {
+			u := new(report_approve.ReportApproveDetailNodeUser)
+			u.UserType = vu.UserType
+			u.UserId = vu.UserId
+			u.UserName = vu.UserName
+			u.Sort = vu.Sort
+			// 审批记录
+			k := fmt.Sprintf("%d-%d", v.ReportApproveNodeId, vu.UserId)
+			r := recordMap[k]
+			if r != nil {
+				u.ApproveRecord = new(report_approve.ReportApproveDetailNodeUserRecord)
+				u.ApproveRecord.ReportApproveRecordId = r.ReportApproveRecordId
+				u.ApproveRecord.State = r.State
+				u.ApproveRecord.ApproveUserId = r.ApproveUserId
+				u.ApproveRecord.ApproveUserName = r.ApproveUserName
+				u.ApproveRecord.ApproveRemark = r.ApproveRemark
+				u.ApproveRecord.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, r.ApproveTime)
+			}
+			t.Users = append(t.Users, u)
+		}
+		sort.Slice(t.Users, func(k, j int) bool {
+			return t.Users[k].Sort < t.Users[j].Sort
+		})
+		detail.ApproveFlowNodes = append(detail.ApproveFlowNodes, t)
+	}
+
+	// 报告信息
+	cnClassifyIdName, enClassifyIdName := make(map[int]string), make(map[int]string)
+	cnClassify, e := models.GetAllClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取中文分类失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range cnClassify {
+		cnClassifyIdName[v.Id] = v.ClassifyName
+	}
+	enClassify, e := models.GetEnglishClassifies()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文分类失败, Err: " + e.Error()
+		return
+	}
+	enRootIdMap := make(map[int]int) // 英文分类的一级分类ID
+	for _, v := range enClassify {
+		enClassifyIdName[v.Id] = v.ClassifyName
+		enRootIdMap[v.Id] = v.RootId
+	}
+	detail.Report = new(report_approve.ReportApproveDetailReport)
+	detail.Report.ReportType = approveItem.ReportType
+	detail.Report.ReportId = approveItem.ReportId
+	detail.Report.ReportTitle = approveItem.ReportTitle
+	// 报告分类路由
+	if approveItem.ReportType == report_approve.FlowReportTypeChinese {
+		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], cnClassifyIdName[approveItem.ClassifyFirstId], cnClassifyIdName[approveItem.ClassifySecondId])
+	}
+	if approveItem.ReportType == report_approve.FlowReportTypeEnglish {
+		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], enClassifyIdName[enRootIdMap[approveItem.ClassifySecondId]], enClassifyIdName[approveItem.ClassifyFirstId], enClassifyIdName[approveItem.ClassifySecondId])
+	}
+	if approveItem.ReportType == report_approve.FlowReportTypeSmart {
+		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], cnClassifyIdName[approveItem.ClassifyFirstId], cnClassifyIdName[approveItem.ClassifySecondId])
+	}
+
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Approve
+// @Title 通过审批
+// @Description 通过审批
+// @Param	request	body report_approve.ReportApprovePassReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /approve [post]
+func (this *ReportApproveController) Approve() {
+	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 report_approve.ReportApprovePassReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveId: %d", req.ReportApproveId)
+		return
+	}
+
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(req.ReportApproveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批信息失败, Err: " + e.Error()
+		return
+	}
+	if approveItem.State != report_approve.ReportApproveStateApproving {
+		br.Msg = "审批状态有误, 请刷新页面"
+		br.ErrMsg = fmt.Sprintf("审批状态有误, State: %d", approveItem.State)
+		return
+	}
+
+	// 校验审批记录和审批
+	recordOb := new(report_approve.ReportApproveRecord)
+	recordCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveRecordCols.ReportApproveId, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State)
+	recordPars := make([]interface{}, 0)
+	recordPars = append(recordPars, approveItem.ReportApproveId, sysUser.AdminId, report_approve.ReportApproveStateApproving)
+	recordItem, e := recordOb.GetItemByCondition(recordCond, recordPars, "")
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "无权审批"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批记录失败, Err: " + e.Error()
+		return
+	}
+
+	// 通过审批
+	tips, e := services.PassReportApprove(approveItem, recordItem, sysUser.AdminId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "通过审批失败, Err: " + e.Error()
+		return
+	}
+	if tips != "" {
+		br.Msg = tips
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Refuse
+// @Title 驳回审批
+// @Description 驳回审批
+// @Param	request	body report_approve.ReportApproveRefuseReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /refuse [post]
+func (this *ReportApproveController) Refuse() {
+	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 report_approve.ReportApproveRefuseReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveId: %d", req.ReportApproveId)
+		return
+	}
+
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(req.ReportApproveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批信息失败, Err: " + e.Error()
+		return
+	}
+	if approveItem.State != report_approve.ReportApproveStateApproving {
+		br.Msg = "审批状态有误, 请刷新页面"
+		br.ErrMsg = fmt.Sprintf("审批状态有误, State: %d", approveItem.State)
+		return
+	}
+
+	// 校验审批记录和审批
+	recordOb := new(report_approve.ReportApproveRecord)
+	recordCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveRecordCols.ReportApproveId, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State)
+	recordPars := make([]interface{}, 0)
+	recordPars = append(recordPars, approveItem.ReportApproveId, sysUser.AdminId, report_approve.ReportApproveStateApproving)
+	recordItem, e := recordOb.GetItemByCondition(recordCond, recordPars, "")
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "无权审批"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批记录失败, Err: " + e.Error()
+		return
+	}
+
+	// 驳回审批
+	if e = services.RefuseReportApprove(approveItem, recordItem, req.ApproveRemark, sysUser.AdminId); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "驳回审批失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Cancel
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body report_approve.ReportApproveCancelReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /cancel [post]
+func (this *ReportApproveController) Cancel() {
+	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 report_approve.ReportApproveCancelReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveId: %d", req.ReportApproveId)
+		return
+	}
+
+	approveOb := new(report_approve.ReportApprove)
+	approveItem, e := approveOb.GetItemById(req.ReportApproveId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批失败, Err: " + e.Error()
+		return
+	}
+	if approveItem.ApplyUserId != sysUser.AdminId {
+		br.Msg = "非申请人不可撤销"
+		return
+	}
+
+	// 撤销审批
+	e = services.CancelReportApprove(approveItem.ReportType, approveItem.ReportId, approveItem.ReportApproveId, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "撤销审批失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// MessageList
+// @Title 审批消息列表
+// @Description 审批消息列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Success 200 {object} report_approve.ReportApproveMessageListResp
+// @router /message/list [get]
+func (this *ReportApproveController) MessageList() {
+	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
+	}
+	params := new(report_approve.ReportApproveListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		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)
+
+	resp := new(report_approve.ReportApproveMessageListResp)
+	resp.List = make([]*report_approve.ReportApproveMessageItem, 0)
+	cond := fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveMessageCols.ReceiveUserId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, sysUser.AdminId)
+	order := fmt.Sprintf(`%s ASC, %s DESC`, report_approve.ReportApproveMessageCols.IsRead, report_approve.ReportApproveMessageCols.CreateTime)
+
+	messageOb := new(report_approve.ReportApproveMessage)
+	total, e := messageOb.GetCountByCondition(cond, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批消息列表总数失败, Err: " + e.Error()
+		return
+	}
+	list, e := messageOb.GetPageItemsByCondition(cond, pars, []string{}, order, startSize, params.PageSize)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批消息列表失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range list {
+		t := report_approve.FormatReportApproveMessage2Item(v)
+		resp.List = append(resp.List, t)
+	}
+
+	// 未读消息数
+	cond += fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveMessageCols.IsRead)
+	pars = append(pars, 0)
+	unreadTotal, e := messageOb.GetCountByCondition(cond, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批消息列表总数失败, Err: " + e.Error()
+		return
+	}
+	resp.UnreadTotal = unreadTotal
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	resp.Paging = page
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// MessageRead
+// @Title 消息已读
+// @Description 消息已读
+// @Param	request	body report_approve.ReportApproveMessageReadReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /message/read [post]
+func (this *ReportApproveController) MessageRead() {
+	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 report_approve.ReportApproveMessageReadReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.MessageId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, MessageId: %d", req.MessageId)
+		return
+	}
+
+	messageOb := new(report_approve.ReportApproveMessage)
+	messageItem, e := messageOb.GetItemById(req.MessageId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "消息不存在, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批消息失败, Err: " + e.Error()
+		return
+	}
+	messageItem.IsRead = 1
+	messageItem.ModifyTime = time.Now().Local()
+	cols := []string{"IsRead", "ModifyTime"}
+	if e = messageItem.Update(cols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新审批消息已读失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// CheckApproveOpen
+// @Title 校验分类是否开启审批
+// @Description 校验分类是否开启审批
+// @Param	request	body report_approve.ReportApproveCheckApproveOpenReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /classify/check_open [post]
+func (this *ReportApproveController) CheckApproveOpen() {
+	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 report_approve.ReportApproveCheckApproveOpenReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验是否开启了审批流
+	opening, e := services.CheckReportOpenApprove(req.ReportType, req.ClassifyFirstId, req.ClassifySecondId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告是否开启审批流失败, Err: " + e.Error()
+		return
+	}
+
+	br.Data = opening
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 741 - 0
controllers/report_approve/report_approve_flow.go

@@ -0,0 +1,741 @@
+package report_approve
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strings"
+	"sync"
+	"time"
+)
+
+// ReportApproveFlowController 报告审批流
+type ReportApproveFlowController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 报告列表
+// @Description 报告列表
+// @Param   PageSize			query	int		true	"每页数据条数"
+// @Param   CurrentIndex		query	int		true	"当前页页码"
+// @Param   ReportType			query   int     false	"报告类型:1-中文研报;2-英文研报;3-智能研报"
+// @Param   ClassifyIdFirst		query	int		false	"一级分类ID"
+// @Param   ClassifyIdSecond	query	int		false	"二级分类ID"
+// @Param   Keyword				query	string	false	"搜索关键词"
+// @Param   SortRule			query	int		false	"排序方式: 1-正序; 2-倒序(默认)"
+// @Success 200 {object} report_approve.ReportApproveFlowListResp
+// @router /flow/list [get]
+func (this *ReportApproveFlowController) 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
+	}
+	params := new(report_approve.ReportApproveFlowListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+
+	var cond, orderRule string
+	var pars []interface{}
+	// 筛选项
+	{
+		keyword := strings.TrimSpace(params.Keyword)
+		if keyword != "" {
+			kw := fmt.Sprint("%", keyword, "%")
+			cond += fmt.Sprintf(` AND %s LIKE ?`, report_approve.ReportApproveFlowCols.FlowName)
+			pars = append(pars, kw)
+		}
+		if params.ReportType > 0 && params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifySecondId)
+			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		}
+		if params.SortRule > 0 {
+			orderMap := map[int]string{1: "ASC", 2: "DESC"}
+			orderRule = fmt.Sprintf("%s %s", report_approve.ReportApproveFlowCols.CreateTime, orderMap[params.SortRule])
+		}
+	}
+
+	resp := new(report_approve.ReportApproveFlowListResp)
+	flowOb := new(report_approve.ReportApproveFlow)
+	total, e := flowOb.GetCountByCondition(cond, 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)
+
+	list, e := flowOb.GetPageItemsByCondition(cond, pars, []string{}, orderRule, startSize, params.PageSize)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流分页列表失败, Err:" + e.Error()
+		return
+	}
+
+	// 指标分类
+	cnClassifyIdName, enClassifyIdName := make(map[int]string), make(map[int]string)
+	cnClassify, e := models.GetAllClassify()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取中文分类失败, Err: " + e.Error()
+		return
+	}
+	for _, v := range cnClassify {
+		cnClassifyIdName[v.Id] = v.ClassifyName
+	}
+	enClassify, e := models.GetEnglishClassifies()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文分类失败, Err: " + e.Error()
+		return
+	}
+	enRootIdMap := make(map[int]int) // 英文分类的一级分类ID
+	for _, v := range enClassify {
+		enClassifyIdName[v.Id] = v.ClassifyName
+		enRootIdMap[v.Id] = v.RootId
+	}
+
+	for _, v := range list {
+		t := report_approve.FormatReportApproveFlow2Item(v)
+		if v.ReportType == report_approve.FlowReportTypeEnglish {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], enClassifyIdName[v.ClassifyFirstId], enClassifyIdName[v.ClassifySecondId])
+		} else {
+			t.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId], cnClassifyIdName[v.ClassifySecondId])
+		}
+		resp.List = append(resp.List, t)
+	}
+
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Add
+// @Title 新增审批流
+// @Description 新增审批流
+// @Param	request	body report_approve.ReportApproveFlowAddReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/add [post]
+func (this *ReportApproveFlowController) 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 report_approve.ReportApproveFlowAddReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	req.FlowName = strings.TrimSpace(req.FlowName)
+	if req.FlowName == "" {
+		br.Msg = "请输入审批流名称"
+		return
+	}
+	if len([]rune(req.FlowName)) > 20 {
+		br.Msg = "审批流名称最多输入20个字符"
+		return
+	}
+	reportTypes := []int{report_approve.FlowReportTypeChinese, report_approve.FlowReportTypeEnglish, report_approve.FlowReportTypeSmart}
+	if !utils.InArrayByInt(reportTypes, req.ReportType) {
+		br.Msg = "审批流报告类型有误"
+		br.ErrMsg = fmt.Sprintf("审批流报告类型有误, ReportType: %d", req.ReportType)
+		return
+	}
+	if req.ClassifyFirstId <= 0 || req.ClassifySecondId <= 0 {
+		br.Msg = "请选择报告分类"
+		return
+	}
+	if len(req.Nodes) <= 0 {
+		br.Msg = "请添加审批流程"
+		return
+	}
+	approveTypes := []int{report_approve.NodeApproveTypeRoll, report_approve.NodeApproveTypeAll, report_approve.NodeApproveTypeAny}
+	approveUserTypes := []string{report_approve.NodeUserTypeNormal, report_approve.NodeUserTypeRole}
+	for _, v := range req.Nodes {
+		if !utils.InArrayByInt(approveTypes, v.ApproveType) {
+			br.Msg = "审批流类型有误"
+			br.ErrMsg = fmt.Sprintf("审批流类型有误, ApproveType: %d", v.ApproveType)
+			return
+		}
+		for _, v2 := range v.Users {
+			if !utils.InArrayByStr(approveUserTypes, v2.UserType) {
+				br.Msg = "审批流用户类型有误"
+				br.ErrMsg = fmt.Sprintf("审批流用户类型有误, UserType: %d", v2.UserType)
+				return
+			}
+		}
+	}
+
+	// 审批流是否已存在
+	{
+		flowOb := new(report_approve.ReportApproveFlow)
+		existCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+		existPars := make([]interface{}, 0)
+		existPars = append(existPars, req.ReportType, req.ClassifyFirstId, req.ClassifySecondId)
+		exist, e := flowOb.GetItemByCondition(existCond, existPars, "")
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取审批流是否已存在失败, Err: " + e.Error()
+			return
+		}
+		if exist != nil {
+			br.Msg = "该分类已有审批流, 请勿重复添加"
+			return
+		}
+	}
+
+	flowItem := new(report_approve.ReportApproveFlow)
+	flowItem.FlowName = req.FlowName
+	flowItem.ReportType = req.ReportType
+	flowItem.ClassifyFirstId = req.ClassifyFirstId
+	flowItem.ClassifySecondId = req.ClassifySecondId
+	flowItem.CurrVersion = 1
+	flowItem.CreateTime = time.Now().Local()
+	flowItem.ModifyTime = time.Now().Local()
+
+	nodeItems := make([]*report_approve.ReportApproveNode, 0)
+	for _, v := range req.Nodes {
+		n := new(report_approve.ReportApproveNode)
+		n.ApproveType = v.ApproveType
+		n.CurrVersion = flowItem.CurrVersion
+		j, _ := json.Marshal(v.Users)
+		n.Users = string(j)
+		n.CreateTime = time.Now().Local()
+		nodeItems = append(nodeItems, n)
+	}
+
+	// 新增审批流和节点
+	if e := flowItem.CreateFlowAndNodes(flowItem, nodeItems); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "新增审批流和节点失败, Err: " + e.Error()
+		return
+	}
+
+	// 返回详情
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodeItems)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
+		return
+	}
+
+	// 更新审批对应的报告状态:未发布->待提交
+	go func() {
+		_ = services.FlowOperateResetReportState(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId, models.ReportStateUnpublished, models.ReportStateWaitSubmit)
+	}()
+
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Edit
+// @Title 编辑审批流
+// @Description 编辑审批流
+// @Param	request	body report_approve.ReportApproveFlowEditReq true "type json string"
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/edit [post]
+func (this *ReportApproveFlowController) Edit() {
+	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 report_approve.ReportApproveFlowEditReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveFlowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", req.ReportApproveFlowId)
+		return
+	}
+	req.FlowName = strings.TrimSpace(req.FlowName)
+	if req.FlowName == "" {
+		br.Msg = "请输入审批流名称"
+		return
+	}
+	if len([]rune(req.FlowName)) > 20 {
+		br.Msg = "审批流名称最多输入20个字符"
+		return
+	}
+	reportTypes := []int{report_approve.FlowReportTypeChinese, report_approve.FlowReportTypeEnglish, report_approve.FlowReportTypeSmart}
+	if !utils.InArrayByInt(reportTypes, req.ReportType) {
+		br.Msg = "审批流报告类型有误"
+		br.ErrMsg = fmt.Sprintf("审批流报告类型有误, ReportType: %d", req.ReportType)
+		return
+	}
+	if req.ClassifyFirstId <= 0 || req.ClassifySecondId <= 0 {
+		br.Msg = "请选择报告分类"
+		return
+	}
+	if len(req.Nodes) <= 0 {
+		br.Msg = "请添加审批流程"
+		return
+	}
+	approveTypes := []int{report_approve.NodeApproveTypeRoll, report_approve.NodeApproveTypeAll, report_approve.NodeApproveTypeAny}
+	approveUserTypes := []string{report_approve.NodeUserTypeNormal, report_approve.NodeUserTypeRole}
+	for _, v := range req.Nodes {
+		if !utils.InArrayByInt(approveTypes, v.ApproveType) {
+			br.Msg = "审批流类型有误"
+			br.ErrMsg = fmt.Sprintf("审批流类型有误, ApproveType: %d", v.ApproveType)
+			return
+		}
+		for _, v2 := range v.Users {
+			if !utils.InArrayByStr(approveUserTypes, v2.UserType) {
+				br.Msg = "审批流用户类型有误"
+				br.ErrMsg = fmt.Sprintf("审批流用户类型有误, UserType: %d", v2.UserType)
+				return
+			}
+		}
+	}
+
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(req.ReportApproveFlowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批流是否已存在
+	{
+		existCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ? AND %s <> ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId, report_approve.ReportApproveFlowCols.ReportApproveFlowId)
+		existPars := make([]interface{}, 0)
+		existPars = append(existPars, req.ReportType, req.ClassifyFirstId, req.ClassifySecondId, req.ReportApproveFlowId)
+		exist, e := flowOb.GetItemByCondition(existCond, existPars, "")
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取审批流是否已存在失败, Err: " + e.Error()
+			return
+		}
+		if exist != nil {
+			br.Msg = "该分类已有审批流, 请勿重复添加"
+			return
+		}
+	}
+
+	// 校验审批流是否关联了进行中的审批
+	{
+		approvingOb := new(report_approve.ReportApprove)
+		approvingCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveCols.FlowId, report_approve.ReportApproveCols.FlowVersion, report_approve.ReportApproveCols.State)
+		approvingPars := make([]interface{}, 0)
+		approvingPars = append(approvingPars, flowItem.ReportApproveFlowId, flowItem.CurrVersion, report_approve.ReportApproveStateApproving)
+		count, e := approvingOb.GetCountByCondition(approvingCond, approvingPars)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取审批流关联进行中的审批数失败. Err: " + e.Error()
+			return
+		}
+		if count > 0 {
+			br.Msg = "当前有未走完流程的报告,请走完流程后再做变更"
+			return
+		}
+	}
+
+	// 变更了报告分类时, 判断是否允许变更
+	if req.ReportType != flowItem.ReportType || req.ClassifyFirstId != flowItem.ClassifyFirstId || req.ClassifySecondId != flowItem.ClassifySecondId {
+		checkOk, e := services.CheckReportApproveFlowChange(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "校验审批流是否可变更失败, Err: " + e.Error()
+			return
+		}
+		if !checkOk {
+			br.Msg = "当前有未走完流程的报告, 请走完流程后再做变更!"
+			return
+		}
+	}
+
+	flowItem.FlowName = req.FlowName
+	flowItem.ReportType = req.ReportType
+	flowItem.ClassifyFirstId = req.ClassifyFirstId
+	flowItem.ClassifySecondId = req.ClassifySecondId
+	flowItem.CurrVersion += 1
+	flowItem.ModifyTime = time.Now().Local()
+
+	nodeItems := make([]*report_approve.ReportApproveNode, 0)
+	for _, v := range req.Nodes {
+		n := new(report_approve.ReportApproveNode)
+		n.ApproveType = v.ApproveType
+		n.CurrVersion = flowItem.CurrVersion
+		j, _ := json.Marshal(v.Users)
+		n.Users = string(j)
+		n.CreateTime = time.Now().Local()
+		nodeItems = append(nodeItems, n)
+	}
+
+	// 更新审批流和节点
+	if e := flowItem.UpdateFlowAndNodes(flowItem, nodeItems); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新审批流和节点失败, Err: " + e.Error()
+		return
+	}
+
+	// 返回详情
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodeItems)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
+		return
+	}
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// Detail
+// @Title 审批流详情
+// @Description 审批流详情
+// @Param   ReportApproveFlowId  query  int  true  "审批流ID"
+// @Success 200 {object} report_approve.ReportApproveFlowDetailItem
+// @router /flow/detail [get]
+func (this *ReportApproveFlowController) Detail() {
+	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
+	}
+	flowId, _ := this.GetInt("ReportApproveFlowId")
+	if flowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", flowId)
+		return
+	}
+
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(flowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 审批节点
+	nodeOb := new(report_approve.ReportApproveNode)
+	nodeCond := fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveNodeCols.ReportApproveFlowId, report_approve.ReportApproveNodeCols.CurrVersion)
+	nodePars := make([]interface{}, 0)
+	nodePars = append(nodePars, flowItem.ReportApproveFlowId, flowItem.CurrVersion)
+	nodes, e := nodeOb.GetItemsByCondition(nodeCond, nodePars, []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批节点失败, Err: " + e.Error()
+		return
+	}
+
+	detail, e := report_approve.FormatFlowAndNodesItem2Detail(flowItem, nodes)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批详情失败, Err: " + e.Error()
+		return
+	}
+	br.Data = detail
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Remove
+// @Title 删除审批流
+// @Description 删除审批流
+// @Param	request	body report_approve.ReportApproveFlowRemoveReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /flow/remove [post]
+func (this *ReportApproveFlowController) 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 report_approve.ReportApproveFlowRemoveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	if req.ReportApproveFlowId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportApproveFlowId: %d", req.ReportApproveFlowId)
+		return
+	}
+
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowItem, e := flowOb.GetItemById(req.ReportApproveFlowId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "审批流已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验是否允许删除
+	checkOk, e := services.CheckReportApproveFlowChange(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验审批流是否可变更失败, Err: " + e.Error()
+		return
+	}
+	if !checkOk {
+		br.Msg = "当前有未走完流程的报告, 请走完流程后再做删除!"
+		return
+	}
+
+	// 删除审批流, 保留审批节点, 历史审批回显会用得到
+	if e = flowItem.Del(); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "删除审批流失败, Err: " + e.Error()
+		return
+	}
+
+	// 更新审批对应的报告状态:待提交->未发布
+	go func() {
+		_ = services.FlowOperateResetReportState(flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId, models.ReportStateWaitSubmit, models.ReportStateUnpublished)
+	}()
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// ReportClassifyTree
+// @Title 报告分类树
+// @Description 报告分类树
+// @Param   ReportApproveFlowId  query  int  false  "审批流ID"
+// @Success 200 {object} report_approve.ReportClassifyTreeItem
+// @router /report/classify_tree [get]
+func (this *ReportApproveFlowController) ReportClassifyTree() {
+	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
+	}
+	flowId, _ := this.GetInt("ReportApproveFlowId")
+
+	// 获取审批流信息, 用于查询分类是否可选
+	var flowKey string
+	if flowId > 0 {
+		flowOb := new(report_approve.ReportApproveFlow)
+		flowItem, e := flowOb.GetItemById(flowId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "审批流已被删除, 请刷新页面"
+				return
+			}
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取审批流信息失败, Err: " + e.Error()
+			return
+		}
+		flowKey = fmt.Sprintf("%d-%d-%d", flowItem.ReportType, flowItem.ClassifyFirstId, flowItem.ClassifySecondId)
+	}
+
+	// 获取审批流列表
+	flowOb := new(report_approve.ReportApproveFlow)
+	flows, e := flowOb.GetItemsByCondition(``, make([]interface{}, 0), []string{}, "")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取审批流列表失败, Err: " + e.Error()
+		return
+	}
+	hasFlowMap := make(map[string]bool)
+	for _, v := range flows {
+		k := fmt.Sprintf("%d-%d-%d", v.ReportType, v.ClassifyFirstId, v.ClassifySecondId)
+		if k == flowKey {
+			// 当前审批流对应的分类标记为可选状态
+			continue
+		}
+		hasFlowMap[k] = true
+	}
+
+	resp, cnTree, smartTree, enTree := make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0), make([]*report_approve.ReportClassifyTreeItem, 0)
+
+	var cnErr, enErr error
+	wg := sync.WaitGroup{}
+	wg.Add(2)
+
+	// 中文/智能研报分类
+	go func() {
+		defer func() {
+			wg.Done()
+		}()
+
+		classify, e := models.GetAllClassify()
+		if e != nil {
+			cnErr = fmt.Errorf("GetAllClassify err: %s", e.Error())
+			return
+		}
+		cnTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range cnTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeChinese, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
+
+		smartTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range smartTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeSmart, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
+	}()
+
+	// 英文研报分类
+	go func() {
+		defer func() {
+			wg.Done()
+		}()
+
+		classify, e := models.GetAllEnglishClassify()
+		if e != nil {
+			enErr = fmt.Errorf("GetAllEnglishClassify err: %s", e.Error())
+			return
+		}
+		enTree = services.GetReportClassifyTreeRecursive(classify, 0)
+		for _, v := range enTree {
+			for _, v2 := range v.Children {
+				k := fmt.Sprintf("%d-%d-%d", report_approve.FlowReportTypeEnglish, v.ClassifyId, v2.ClassifyId)
+				v2.HasFlow = hasFlowMap[k]
+			}
+		}
+	}()
+
+	wg.Wait()
+
+	if cnErr != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取中文分类失败, Err: " + cnErr.Error()
+		return
+	}
+	if enErr != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取英文分类失败, Err: " + enErr.Error()
+		return
+	}
+
+	resp = append(resp, &report_approve.ReportClassifyTreeItem{
+		ClassifyId:   report_approve.FlowReportTypeChinese,
+		ClassifyName: "研报列表",
+		Children:     cnTree,
+	}, &report_approve.ReportClassifyTreeItem{
+		ClassifyId:   report_approve.FlowReportTypeEnglish,
+		ClassifyName: "英文研报",
+		Children:     enTree,
+	}, &report_approve.ReportClassifyTreeItem{
+		ClassifyId:   report_approve.FlowReportTypeSmart,
+		ClassifyName: "智能研报",
+		Children:     smartTree,
+	})
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 2 - 2
controllers/report_author.go

@@ -2,9 +2,9 @@ package controllers
 
 import (
 	"encoding/json"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"eta/eta_api/models"
 	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
 )
@@ -57,7 +57,7 @@ func (this *ReportAuthorController) Author() {
 
 	if keyword != `` {
 		condition += ` AND report_author like ? `
-		pars = append(pars, "%"+keyword+"%")
+		pars = append(pars, utils.GetLikeKeyword(keyword))
 	}
 
 	total, items, err := models.GetReportAuthorList(condition, pars, startSize, pageSize)

+ 78 - 43
controllers/sandbox/sandbox.go

@@ -177,7 +177,8 @@ func (this *SandboxController) FirstVersionList() {
 	condition += " AND b.curr_version < a.curr_version "
 
 	if keyword != "" {
-		condition += ` AND  ( a.name LIKE '%` + keyword + `%'  OR  b.name LIKE '%` + keyword + `%' )`
+		condition += ` AND  ( a.name LIKE ?  OR  b.name LIKE ? )`
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	//获取指标信息
@@ -250,7 +251,8 @@ func (this *SandboxController) VersionList() {
 	condition += " AND b.curr_version < a.curr_version "
 
 	if keyWord != "" {
-		condition += ` AND  ( a.op_user_name LIKE '%` + keyWord + `%'  OR  a.name LIKE '%` + keyWord + `%' or a.op_user_name LIKE '%` + keyWord + `%'  OR  a.name LIKE '%` + keyWord + `%' )`
+		condition += ` AND  ( a.op_user_name LIKE ? OR  a.name LIKE ? or a.op_user_name LIKE ? OR  a.name LIKE ? )`
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 4)
 	}
 
 	//获取指标信息
@@ -787,7 +789,8 @@ func (this *SandboxController) ListByQuote() {
 	}
 
 	if keyword != "" {
-		condition += ` AND  ( a.name LIKE '%` + keyword + `%' OR  a.chart_permission_name LIKE '%` + keyword + `%' )`
+		condition += ` AND  ( a.name LIKE ? OR  a.chart_permission_name LIKE ? )`
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 	}
 
 	//获取指标信息
@@ -995,32 +998,42 @@ func (this *SandboxController) EditSandboxClassify() {
 		return
 	}
 
-	item, err := sandbox.GetSandboxClassifyById(req.SandboxClassifyId)
+	//item, err := sandbox.GetSandboxClassifyById(req.SandboxClassifyId)
+	//if err != nil {
+	//	br.Msg = "保存失败"
+	//	br.Msg = "获取分类信息失败,Err:" + err.Error()
+	//	return
+	//}
+
+	//count, err := sandbox.GetSandboxClassifyCount(req.SandboxClassifyName, item.ParentId)
+	//if err != nil {
+	//	br.Msg = "判断名称是否已存在失败"
+	//	br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+	//	return
+	//}
+	//if count > 0 {
+	//	br.Msg = "分类名称已存在,请重新输入"
+	//	br.IsSendEmail = false
+	//	return
+	//}
+
+	err = sandbox.EditSandboxClassify(req.SandboxClassifyId, req.ChartPermissionId, req.SandboxClassifyName, req.ChartPermissionName)
 	if err != nil {
 		br.Msg = "保存失败"
-		br.Msg = "获取分类信息失败,Err:" + err.Error()
+		br.ErrMsg = "保存失败,Err:" + err.Error()
 		return
 	}
-
-	if item.SandboxClassifyName != req.SandboxClassifyName {
-		count, err := sandbox.GetSandboxClassifyCount(req.SandboxClassifyName, item.ParentId)
-		if err != nil {
-			br.Msg = "判断名称是否已存在失败"
-			br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
-			return
-		}
-		if count > 0 {
-			br.Msg = "分类名称已存在,请重新输入"
-			br.IsSendEmail = false
-			return
-		}
-
-		err = sandbox.EditSandboxClassify(req.SandboxClassifyId, req.SandboxClassifyName)
-		if err != nil {
-			br.Msg = "保存失败"
-			br.ErrMsg = "保存失败,Err:" + err.Error()
-			return
-		}
+	ids, err := sandbox.GetSandboxClassifySubcategories(req.SandboxClassifyId)
+	if err != nil {
+		br.Msg = "查询子级分类id失败"
+		br.ErrMsg = "查询子级分类id失败,Err:" + err.Error()
+		return
+	}
+	err  = sandbox.UpdateSandboxClassifyChartPermissionById(req.ChartPermissionId, req.ChartPermissionName, ids)
+	if err != nil {
+		br.Msg = "修改子级分类错误"
+		br.ErrMsg = "修改子级分类错误,Err:" + err.Error()
+		return
 	}
 	br.Ret = 200
 	br.Msg = "保存成功"
@@ -1243,19 +1256,20 @@ func (this *SandboxController) ChartClassifyMove() {
 		}
 
 		//如果改变了分类,那么移动该图表数据
+		// 11/22 ETA逻辑优化去除名称重复限制
 		if sandboxInfo.SandboxClassifyId != req.ParentClassifyId {
-			//查询需要修改的分类下是否存在同一个图表名称
-			tmpSandboxInfo, tmpErr := sandbox.GetSandboxByClassifyIdAndName(req.ParentClassifyId, sandboxInfo.Name)
-			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
-				br.Msg = "移动失败"
-				br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
-				return
-			}
-			if tmpSandboxInfo != nil {
-				br.Msg = "移动失败,同一个分类下沙盘名称不允许重复"
-				br.ErrMsg = "移动失败,同一个分类下沙盘名称不允许重复"
-				return
-			}
+			////查询需要修改的分类下是否存在同一个图表名称
+			//tmpSandboxInfo, tmpErr := sandbox.GetSandboxByClassifyIdAndName(req.ParentClassifyId, sandboxInfo.Name)
+			//if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			//	br.Msg = "移动失败"
+			//	br.ErrMsg = "移动失败,Err:" + tmpErr.Error()
+			//	return
+			//}
+			//if tmpSandboxInfo != nil {
+			//	br.Msg = "移动失败,同一个分类下沙盘名称不允许重复"
+			//	br.ErrMsg = "移动失败,同一个分类下沙盘名称不允许重复"
+			//	return
+			//}
 			err = sandbox.MoveSandbox(req.SandboxId, req.ParentClassifyId)
 			if err != nil {
 				br.Msg = "移动失败"
@@ -1619,6 +1633,26 @@ func (this *SandboxController) ChartClassifyMove() {
 				br.ErrMsg = "修改失败,Err:" + err.Error()
 				return
 			}
+			if req.ParentClassifyId > 0 {
+				ids, err := sandbox.GetSandboxClassifySubcategories(req.ClassifyId)
+				if err != nil {
+					br.Msg = "查询子级分类id失败"
+					br.ErrMsg = "查询子级分类id失败,Err:" + err.Error()
+					return
+				}
+				parentChartClassifyInfo, err := sandbox.GetSandboxClassifyById(req.ParentClassifyId)
+				if err != nil {
+					br.Msg = "移动失败"
+					br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
+					return
+				}
+				err  = sandbox.UpdateSandboxClassifyChartPermissionById(parentChartClassifyInfo.ChartPermissionId, parentChartClassifyInfo.ChartPermissionName, ids)
+				if err != nil {
+					br.Msg = "修改子级分类错误"
+					br.ErrMsg = "修改子级分类错误,Err:" + err.Error()
+					return
+				}
+			}
 		}
 	}
 
@@ -1789,13 +1823,14 @@ func (this *SandboxController) SaveV2() {
 			PicUrl:            utils.TrimStr(req.PicUrl),
 			ModifyTime:        time.Now(),
 			SandboxClassifyId: req.SandboxClassifyId,
+			Style:             req.Style,
 		}
 		//缩略图为空时不更新
 		var updateSandboxColumn = []string{}
-		if req.PicUrl == ""{
-			updateSandboxColumn = []string{"Content", "MindmapData", "ModifyTime", "SandboxClassifyId"}
+		if req.PicUrl == "" {
+			updateSandboxColumn = []string{"Content", "MindmapData", "ModifyTime", "SandboxClassifyId", "Style"}
 		} else {
-			updateSandboxColumn = []string{"Content", "MindmapData", "PicUrl", "ModifyTime", "SandboxClassifyId"}
+			updateSandboxColumn = []string{"Content", "MindmapData", "PicUrl", "ModifyTime", "SandboxClassifyId", "Style"}
 		}
 		err = sandboxInfo.Update(updateSandboxColumn)
 		if err != nil {
@@ -1887,7 +1922,7 @@ func (this *SandboxController) GetSandboxDetail() {
 	}
 
 	//获取沙盘数据详情(已保存的)
-	sandboxVersionInfo, err := sandbox.GetSandboxById(sandboxId)
+	sandboxInfo, err := sandbox.GetSandboxById(sandboxId)
 	if err != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败,Err:" + err.Error()
@@ -1897,7 +1932,7 @@ func (this *SandboxController) GetSandboxDetail() {
 	br.Ret = 200
 	br.Success = true
 	br.Msg = msg
-	br.Data = sandboxVersionInfo
+	br.Data = sandboxInfo
 }
 
 //// SandboxClassifyItems
@@ -2369,4 +2404,4 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 	br.Msg = "检测成功"
 	br.Success = true
 	br.Data = resp
-}
+}

+ 1 - 1
controllers/semantic_analysis/sa_compare.go

@@ -698,7 +698,7 @@ func (this *SaCompareController) Search() {
 	existPars := make([]interface{}, 0)
 	if keyword != "" {
 		existCond += ` AND  ( title LIKE ? )`
-		existPars = append(existPars, `%`+keyword+`%`)
+		existPars = append(existPars, utils.GetLikeKeyword(keyword))
 	}
 	total, list, err = saCompare.GetPageItemsByCondition(startSize, pageSize, existCond, existPars, []string{}, "")
 	if err != nil && err.Error() != utils.ErrNoRow() {

+ 279 - 26
controllers/smart_report/smart_report.go

@@ -4,10 +4,11 @@ import (
 	"encoding/json"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
+	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/smart_report"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
-	smartReportService "eta/eta_api/services/smart_report"
+	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/kgiannakakis/mp3duration/src/mp3duration"
@@ -77,6 +78,14 @@ func (this *SmartReportController) Add() {
 	}
 	stageMax += 1
 
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
 	item := new(smart_report.SmartReport)
 	item.AddType = req.AddType
 	item.ClassifyIdFirst = req.ClassifyIdFirst
@@ -92,9 +101,14 @@ func (this *SmartReportController) Add() {
 	item.AdminRealName = sysUser.RealName
 	item.LastModifyAdminId = sysUser.AdminId
 	item.LastModifyAdminName = sysUser.RealName
-	item.State = smart_report.SmartReportStateWaitPublish
+	item.State = state
 	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)
@@ -130,7 +144,7 @@ func (this *SmartReportController) Add() {
 	recordItem := &models.ReportStateRecord{
 		ReportId:   item.SmartReportId,
 		ReportType: 2,
-		State:      smart_report.SmartReportStateWaitPublish,
+		State:      state,
 		AdminId:    this.SysUser.AdminId,
 		AdminName:  this.SysUser.AdminName,
 		CreateTime: time.Now(),
@@ -213,7 +227,7 @@ func (this *SmartReportController) Edit() {
 		br.ErrMsg = "获取研报失败, Err: " + e.Error()
 		return
 	}
-	if item.State == 2 {
+	if item.State == models.ReportStatePublished || item.State == models.ReportStatePass {
 		br.Msg = "报告已发布, 请取消发布后编辑"
 		return
 	}
@@ -230,7 +244,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
@@ -243,8 +257,10 @@ 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
 		item.LastModifyAdminName = sysUser.RealName
 		item.ContentModifyTime = time.Now().Local()
@@ -319,7 +335,7 @@ func (this *SmartReportController) Remove() {
 
 	// ES更新报告为未发布
 	go func() {
-		_ = smartReportService.SmartReportElasticUpsert(item.SmartReportId, 1)
+		_ = services.SmartReportElasticUpsert(item.SmartReportId, 1)
 	}()
 
 	br.Ret = 200
@@ -413,6 +429,13 @@ func (this *SmartReportController) Publish() {
 		br.Msg = "参数有误"
 		return
 	}
+	operate := 0
+	if req.PublishState == smart_report.SmartReportStateWaitPublish {
+		operate = models.ReportOperateCancelPublish
+	}
+	if req.PublishState == smart_report.SmartReportStatePublished {
+		operate = models.ReportOperatePublish
+	}
 
 	ob := new(smart_report.SmartReport)
 	item, e := ob.GetItemById(req.SmartReportId)
@@ -426,10 +449,27 @@ func (this *SmartReportController) Publish() {
 		return
 	}
 
+	// 图表刷新状态
+	refreshResult := data.CheckBatchChartRefreshResult("report", item.SmartReportId, 0)
+	if !refreshResult {
+		br.Msg = "图表刷新未完成,请稍后操作"
+		br.ErrMsg = "图表刷新未完成,请稍后操作"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, item.ClassifyIdFirst, item.ClassifyIdSecond, operate)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
 	cols := []string{"State", "ModifyTime"}
-	item.State = req.PublishState
+	item.State = state
 	item.ModifyTime = time.Now().Local()
-	if req.PublishState == smart_report.SmartReportStatePublished {
+	if state == smart_report.SmartReportStatePublished {
 		cols = append(cols, "PublishTime")
 		item.PublishTime = time.Now().Local()
 
@@ -439,8 +479,9 @@ func (this *SmartReportController) Publish() {
 		queue.ReportCode = item.ReportCode
 		_ = utils.Rc.LPush(utils.CACHE_CREATE_REPORT_IMGPDF_QUEUE, queue)
 	}
+
 	// 取消发布时同时清除掉Img和PDF的文件地址
-	if req.PublishState == smart_report.SmartReportStateWaitPublish {
+	if state == smart_report.SmartReportStateWaitPublish {
 		cols = append(cols, "DetailImgUrl", "DetailPdfUrl")
 		item.DetailImgUrl = ""
 		item.DetailPdfUrl = ""
@@ -450,10 +491,11 @@ func (this *SmartReportController) Publish() {
 		br.ErrMsg = "更新研报失败, Err: " + e.Error()
 		return
 	}
+
 	recordItem := &models.ReportStateRecord{
 		ReportId:   req.SmartReportId,
 		ReportType: 2,
-		State:     req.PublishState,
+		State:      state,
 		AdminId:    this.SysUser.AdminId,
 		AdminName:  this.SysUser.AdminName,
 		CreateTime: time.Now(),
@@ -461,15 +503,24 @@ func (this *SmartReportController) Publish() {
 	go func() {
 		_, _ = models.AddReportStateRecord(recordItem)
 	}()
-	// 生成音频
-	if req.PublishState == smart_report.SmartReportStatePublished && item.VideoUrl == "" {
-		go smartReportService.SmartReportBuildVideoAndUpdate(item)
-	}
 
-	// ES更新报告
-	go func() {
-		_ = smartReportService.SmartReportElasticUpsert(item.SmartReportId, req.PublishState)
-	}()
+	if state == smart_report.SmartReportStatePublished {
+		// 生成音频
+		if item.VideoUrl == "" {
+			go services.SmartReportBuildVideoAndUpdate(item)
+		}
+
+		// ES更新报告
+		go func() {
+			_ = services.SmartReportElasticUpsert(item.SmartReportId, models.ReportStatePublished)
+		}()
+	}
+	if state == smart_report.SmartReportStateWaitPublish {
+		// ES更新报告
+		go func() {
+			_ = services.SmartReportElasticUpsert(item.SmartReportId, models.ReportStateUnpublished)
+		}()
+	}
 
 	br.Ret = 200
 	br.Success = true
@@ -555,6 +606,18 @@ func (this *SmartReportController) PrePublish() {
 		return
 	}
 
+	// 校验是否开启了审批流
+	opening, e := services.CheckReportOpenApprove(report_approve.FlowReportTypeSmart, item.ClassifyIdFirst, item.ClassifyIdSecond)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告是否开启审批流失败, Err: " + e.Error()
+		return
+	}
+	if opening {
+		br.Msg = "报告已开启审批流, 不可设置定时发布"
+		return
+	}
+
 	item.PrePublishTime = preTime
 	item.PreMsgSend = req.PreMsgSend
 	cols := []string{"PrePublishTime", "PreMsgSend"}
@@ -715,7 +778,7 @@ func (this *SmartReportController) SaveContent() {
 	for _, ad := range admins {
 		adminIdName[ad.AdminId] = ad.RealName
 	}
-	editing, e := smartReportService.UpdateSmartReportEditing(req.SmartReportId, 1, sysUser.AdminId, sysUser.RealName, adminIdName)
+	editing, e := services.UpdateSmartReportEditing(req.SmartReportId, 1, sysUser.AdminId, sysUser.RealName, adminIdName)
 	if e != nil {
 		br.Msg = e.Error()
 		return
@@ -744,7 +807,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 = "更新报告内容失败"
@@ -821,7 +887,7 @@ func (this *SmartReportController) MarkEditStatus() {
 		adminIdName[ad.AdminId] = ad.RealName
 	}
 
-	data, e := smartReportService.UpdateSmartReportEditing(req.SmartReportId, req.Status, sysUser.AdminId, sysUser.RealName, adminIdName)
+	data, e := services.UpdateSmartReportEditing(req.SmartReportId, req.Status, sysUser.AdminId, sysUser.RealName, adminIdName)
 	if e != nil {
 		br.Msg = e.Error()
 		return
@@ -838,7 +904,7 @@ func (this *SmartReportController) MarkEditStatus() {
 // @Description 报告列表
 // @Param   PageSize			query	int		true	"每页数据条数"
 // @Param   CurrentIndex		query	int		true	"当前页页码"
-// @Param   TimeType			query	string	false	"筛选的时间类别: publish_time-发布时间, modify_time-更新时间"
+// @Param   TimeType			query	string	false	"筛选的时间类别: publish_time-发布时间, modify_time-更新时间, approve_time-审批时间"
 // @Param   StartDate			query   string  false	"开始时间"
 // @Param   EndDate				query   string  false	"结束时间"
 // @Param   Frequency			query   string  false	"频度"
@@ -885,7 +951,7 @@ func (this *SmartReportController) List() {
 	if params.TimeType == "" {
 		params.TimeType = "publish_time"
 	}
-	if params.TimeType != "publish_time" && params.TimeType != "modify_time" {
+	if params.TimeType != "publish_time" && params.TimeType != "modify_time" && params.TimeType != "approve_time" {
 		br.Msg = "请选择正确的时间类型"
 		return
 	}
@@ -961,7 +1027,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", "approve_time",
 	}
 	list, e := reportOB.GetPageItemsByCondition(condition, pars, fields, "", startSize, params.PageSize)
 	if e != nil {
@@ -984,7 +1050,7 @@ func (this *SmartReportController) List() {
 
 	for _, v := range list {
 		item := smart_report.FormatSmartReport2Item(v)
-		mark, e := smartReportService.UpdateSmartReportEditing(v.SmartReportId, 2, sysUser.AdminId, sysUser.RealName, adminIdName)
+		mark, e := services.UpdateSmartReportEditing(v.SmartReportId, 2, sysUser.AdminId, sysUser.RealName, adminIdName)
 		if e != nil {
 			br.Msg = "获取失败"
 			br.ErrMsg = "查询编辑中标记失败, Err:" + e.Error()
@@ -1237,3 +1303,190 @@ func (this *SmartReportController) VoiceUpload() {
 	br.Data = resp
 	return
 }
+
+// SubmitApprove
+// @Title 提交审批
+// @Description 提交审批接口
+// @Param	request	body models.ReportSubmitApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/submit [post]
+func (this *SmartReportController) SubmitApprove() {
+	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"
+		return
+	}
+	var req models.ReportSubmitApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(smart_report.SmartReport)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待审批时, 仅更新状态
+	if state != models.ReportStateWaitApprove {
+		reportItem.State = state
+		e = reportItem.Update([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+
+	// 提交审批
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeSmart, reportItem.SmartReportId, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "提交审批失败, Err: " + e.Error()
+		return
+	}
+	reportItem.ApproveId = approveId
+	reportItem.State = models.ReportStateWaitApprove
+	reportItem.ModifyTime = time.Now().Local()
+	e = reportItem.Update([]string{"ApproveId", "State", "ModifyTime"})
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// CancelApprove
+// @Title 撤销审批
+// @Description 撤销审批
+// @Param	request	body models.ReportCancelApproveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /approve/cancel [post]
+func (this *SmartReportController) CancelApprove() {
+	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"
+		return
+	}
+	var req models.ReportCancelApproveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	reportId := req.ReportId
+	if reportId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, ReportId: %d", req.ReportId)
+		return
+	}
+
+	reportOb := new(smart_report.SmartReport)
+	reportItem, e := reportOb.GetItemById(reportId)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	// 校验当前审批配置, 返回下一个状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 下一个状态不为待提交时, 仅更新状态
+	if state != models.ReportStateWaitSubmit {
+		reportItem.State = state
+		e = reportItem.Update([]string{"State"})
+		if e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "操作成功"
+		return
+	}
+	//if reportItem.ApproveId <= 0 {
+	//	br.Msg = "报告审批不存在"
+	//	br.ErrMsg = fmt.Sprintf("报告审批不存在, ApproveId: %d", reportItem.ApproveId)
+	//	return
+	//}
+
+	// 撤销审批
+	e = services.CancelReportApprove(report_approve.FlowReportTypeSmart, reportItem.SmartReportId, reportItem.ApproveId, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "撤销审批失败, Err: " + e.Error()
+		return
+	}
+	//reportItem.ApproveId = 0
+	//reportItem.State = models.ReportStateWaitSubmit
+	//reportItem.ModifyTime = time.Now().Local()
+	//e = reportItem.UpdateReport([]string{"ApproveId", "State", "ModifyTime"})
+	//if e != nil {
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "更新报告状态失败, Err: " + e.Error()
+	//	return
+	//}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 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 = "操作成功"
+}

+ 9 - 12
controllers/sys_admin.go

@@ -76,7 +76,8 @@ func (this *SysAdminController) ListSysuser() {
 	}
 
 	if keyWord != "" {
-		condition += ` AND (real_name LIKE '%` + keyWord + `%' OR admin_name LIKE '%` + keyWord + `%' OR mobile LIKE '%` + keyWord + `%' )  `
+		condition += ` AND (real_name LIKE ? OR admin_name LIKE ? OR mobile LIKE ? ) `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 3)
 	}
 
 	var total int
@@ -847,6 +848,9 @@ func (this *SysAdminController) EditEnabled() {
 		syncData.Source = utils.SOURCE_ETA_FLAG
 		syncData.AdminName = adminItem.AdminName
 		_ = utils.Rc.LPush(utils.CACHE_SYNC_ADMIN, syncData)
+
+		// 联动弘则研究公司下的联系人启禁用
+		go services.SwitchHzUserEnabledByMobile(req.Enabled, adminItem.Mobile)
 	}
 
 	//用户被禁用的情况下,需要将他对应的token给过期
@@ -854,11 +858,6 @@ func (this *SysAdminController) EditEnabled() {
 		logOutSystemUser(adminItem.AdminId)
 	}
 
-	// 联动弘则研究公司下的联系人启禁用
-	{
-		go services.SwitchHzUserEnabledByMobile(req.Enabled, adminItem.Mobile)
-	}
-
 	if err != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "操作失败,Err:" + err.Error()
@@ -911,16 +910,15 @@ func (this *SysAdminController) Delete() {
 		syncData.Source = utils.SOURCE_ETA_FLAG
 		syncData.AdminName = adminInfo.AdminName
 		_ = utils.Rc.LPush(utils.CACHE_SYNC_ADMIN, syncData)
+
+		// 删除弘则研究公司下的相同手机号联系人
+		go services.DeleteHzUserByMobile(mobile)
 	}
 
 	// 删除手工数据关联用户
 	{
 		go data_manage.DeleteManualUser(req.AdminId)
 	}
-	// 删除弘则研究公司下的相同手机号联系人
-	{
-		go services.DeleteHzUserByMobile(mobile)
-	}
 
 	// 清楚系统用户列表缓存key
 	utils.Rc.Delete(utils.CACHE_KEY_ADMIN)
@@ -1262,7 +1260,6 @@ func (this *SysAdminController) ResetPass() {
 	br.Msg = "重置密码成功"
 }
 
-
 // Add
 // @Title 用户详情信息
 // @Description 用户详情信息
@@ -1280,4 +1277,4 @@ func (this *SysAdminController) Detail() {
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
-}
+}

+ 11 - 12
controllers/sys_role.go

@@ -3,7 +3,6 @@ package controllers
 import (
 	"encoding/json"
 	"eta/eta_api/models"
-	"eta/eta_api/models/company"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
@@ -718,17 +717,17 @@ func (this *SysRoleController) SystemConfig() {
 	list = append(list, osc)
 
 	// 获取审批流设置
-	confKey := "approval_flow"
-	confTmp, e := company.GetConfigDetailByCode(confKey)
-	if e != nil {
-		br.Msg = "获取审批流配置失败"
-		br.ErrMsg = "获取审批流配置失败, Err: " + e.Error()
-		return
-	}
-	list = append(list, system.BusinessConf{
-		ConfKey: "ApprovalFlow",
-		ConfVal: confTmp.ConfigValue,
-	})
+	//confKey := "approval_flow"
+	//confTmp, e := company.GetConfigDetailByCode(confKey)
+	//if e != nil {
+	//	br.Msg = "获取审批流配置失败"
+	//	br.ErrMsg = "获取审批流配置失败, Err: " + e.Error()
+	//	return
+	//}
+	//list = append(list, system.BusinessConf{
+	//	ConfKey: "ApprovalFlow",
+	//	ConfVal: confTmp.ConfigValue,
+	//})
 
 	br.Data = list
 	br.Ret = 200

+ 2 - 3
controllers/sys_role_admin.go

@@ -2,12 +2,12 @@ package controllers
 
 import (
 	"encoding/json"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"eta/eta_api/models"
 	"eta/eta_api/models/system"
 	"eta/eta_api/models/system/request"
 	"eta/eta_api/models/system/response"
 	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
@@ -75,9 +75,8 @@ func (this *SysRoleAdminController) List() {
 
 	reqKeyword := this.GetString("Keyword")
 	if reqKeyword != "" {
-		reqKeyword = "%" + reqKeyword + "%"
 		condition += " AND (a.real_name LIKE ? OR a.mobile LIKE ?)"
-		pars = append(pars, reqKeyword, reqKeyword)
+		pars = utils.GetLikeKeywordPars(pars, reqKeyword, 2)
 	}
 	adminList, err := system.GetRoleAdminList(condition, pars, startSize, pageSize)
 	if err != nil {

+ 6 - 5
controllers/target.go

@@ -81,7 +81,8 @@ func (this *TargetController) DataList() {
 	var pars []interface{}
 
 	if keyWord != "" {
-		condition += ` AND a.SEC_NAME LIKE '%` + keyWord + `%' `
+		condition += ` AND a.SEC_NAME LIKE ? `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 1)
 	}
 	if startDate != "" {
 		condition += ` AND c.DT >= ? `
@@ -3323,7 +3324,7 @@ func (this *TargetController) ImportTargetFailListDownload() {
 // @Title 复制EXCEL数据保存
 // @Description 复制EXCEL数据保存
 // @Param  request	body models.ExcelStyleReq true "type json string"
-// @Success 200 {object}
+// @Success 200
 // @router /target/excel_style/add [post]
 func (this *TargetController) ExcelDataAdd() {
 	br := new(models.BaseResponse).Init()
@@ -3475,7 +3476,7 @@ func (this *TargetController) ExcelDataAdd() {
 			if i > 4 {
 				for index := 1; index < len(req.Data[i]); index++ {
 					if req.Data[i][index] == nil {
-						break
+						continue
 					}
 					valueMap := req.Data[i][index].(map[string]interface{})
 					value, _ := valueMap["m"]
@@ -3485,7 +3486,7 @@ func (this *TargetController) ExcelDataAdd() {
 					valueListMap[index] = valueMap["m"].(string)
 
 					// 09-27 千位分隔符时用 "m" 取字符串存数据库会把逗号当小数点,现在换用 "v" 直接取数字再转为字符串,看看会不会有问题
-					if ct, ok := valueMap["ct"].(map[string]interface{}); ok{
+					if ct, ok := valueMap["ct"].(map[string]interface{}); ok {
 						fa, _ := ct["fa"]
 						if fa == "#,##0.000" {
 							value = valueMap["v"]
@@ -3817,7 +3818,7 @@ func (this *TargetController) ExcelDataAdd() {
 // @Param   ClassifyId   query   string  false       "指标唯一编码"
 // @Param   TradeCode   query   string  false       "指标唯一编码"
 // @Param   Frequency   query   string  true       "频度"
-// @Success 200 {object}
+// @Success 200
 // @router /target/excel_style/edit [get]
 func (this *TargetController) ExcelDataEdit() {
 	br := new(models.BaseResponse).Init()

+ 42 - 24
controllers/user_login.go

@@ -242,7 +242,7 @@ func (this *UserLoginController) GetVerifyCode() {
 func (this *UserLoginController) Login() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
-		if br.ErrMsg != "" {
+		if br.ErrMsg == "" {
 			br.IsSendEmail = false
 		}
 		this.Data["json"] = br
@@ -257,6 +257,7 @@ func (this *UserLoginController) Login() {
 		Mobile     string `description:"手机号"`
 		Email      string `description:"邮箱"`
 		VerifyCode string `description:"验证码"`
+		ReqTime    string `description:"登录时间戳"`
 	}
 	var req UserLoginReq
 	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
@@ -308,38 +309,55 @@ func (this *UserLoginController) Login() {
 			return
 		}
 
-		// 账号密码校验
+		// 查询账号信息
 		errPassKey := fmt.Sprint(utils.CACHE_LOGIN_ERR_PASS, req.Username)
-		accountUser, e := system.CheckSysUser(req.Username, req.Password)
+		accountUser, e := system.GetSysUserByAdminName(req.Username)
 		if e != nil {
 			br.Ret = models.BaseRespCodeLoginErr
-			if e.Error() == utils.ErrNoRow() {
-				br.Msg = "登录失败, 账号或密码错误"
-				if isAbnormal != "" {
-					return
-				}
-				// 错误密码计数, 超过6次标记异常
-				if !utils.Rc.IsExist(errPassKey) {
-					_ = utils.Rc.Put(errPassKey, 1, utils.GetTodayLastSecond())
-					return
-				}
-				errNum, _ := utils.Rc.RedisInt(errPassKey)
-				errNum += 1
-				if errNum >= 6 {
-					br.Ret = models.BaseRespCodeAbnormalLogin
-					br.Msg = "账号异常, 请进行手机号/邮箱校验"
-					// 标记异常登录, 重置计数
-					_ = utils.Rc.Put(abnormalKey, "true", utils.GetTodayLastSecond())
-					_ = utils.Rc.Delete(errPassKey)
-					return
-				}
+			br.Msg = "登录失败, 账号或密码错误"
+			// 账号查询异常均进行标记, 避免一直尝试进行登录
+			if !utils.Rc.IsExist(errPassKey) {
+				_ = utils.Rc.Put(errPassKey, 1, utils.GetTodayLastSecond())
+				return
+			}
+			errNum, _ := utils.Rc.RedisInt(errPassKey)
+			errNum += 1
+			if errNum < 6 {
 				_ = utils.Rc.Put(errPassKey, errNum, utils.GetTodayLastSecond())
 				return
 			}
+			// 标记异常登录, 重置计数
+			br.Ret = models.BaseRespCodeAbnormalLogin
+			br.Msg = "账号异常, 请进行手机号/邮箱校验"
+			_ = utils.Rc.Put(abnormalKey, "true", utils.GetTodayLastSecond())
+			_ = utils.Rc.Delete(errPassKey)
+			return
+		}
+
+		// 账号密码校验
+		dbPass := utils.MD5(fmt.Sprintf("%s%s%s", accountUser.Password, utils.UserLoginSalt, req.ReqTime))
+		if req.Password != dbPass {
+			br.Ret = models.BaseRespCodeLoginErr
 			br.Msg = "登录失败, 账号或密码错误"
-			br.ErrMsg = "登录失败, Err:" + e.Error()
+			// 错误密码计数, 超过6次标记异常
+			if !utils.Rc.IsExist(errPassKey) {
+				_ = utils.Rc.Put(errPassKey, 1, utils.GetTodayLastSecond())
+				return
+			}
+			errNum, _ := utils.Rc.RedisInt(errPassKey)
+			errNum += 1
+			if errNum < 6 {
+				_ = utils.Rc.Put(errPassKey, errNum, utils.GetTodayLastSecond())
+				return
+			}
+			// 标记异常登录, 重置计数
+			br.Ret = models.BaseRespCodeAbnormalLogin
+			br.Msg = "账号异常, 请进行手机号/邮箱校验"
+			_ = utils.Rc.Put(abnormalKey, "true", utils.GetTodayLastSecond())
+			_ = utils.Rc.Delete(errPassKey)
 			return
 		}
+
 		if accountUser.Enabled == 0 {
 			br.Msg = "您的账号已被禁用, 如需登录, 请联系管理员"
 			br.ErrMsg = fmt.Sprintf("账号已被禁用, 登录账号: %s, 账户名称: %s", accountUser.AdminName, accountUser.RealName)

+ 0 - 0
etalogs/binlog/20231023.log


+ 2 - 5
go.mod

@@ -11,7 +11,7 @@ require (
 	github.com/alibabacloud-go/tea v1.1.20
 	github.com/alibabacloud-go/tea-utils/v2 v2.0.1
 	github.com/aliyun/alibaba-cloud-sdk-go v1.61.1656
-	github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible
+	github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible
 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
 	github.com/aws/aws-sdk-go v1.42.23
 	github.com/beego/bee/v2 v2.0.4
@@ -30,14 +30,12 @@ require (
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/shopspring/decimal v1.3.1
 	github.com/silenceper/wechat/v2 v2.1.3
-	github.com/sirupsen/logrus v1.9.3
 	github.com/tealeg/xlsx v1.0.5
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.541
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.541
 	github.com/xuri/excelize/v2 v2.7.1
 	github.com/yidane/formula v0.0.0-20210902154546-0782e1736717
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
-	gopkg.in/natefinch/lumberjack.v2 v2.2.1
 )
 
 require (
@@ -55,7 +53,6 @@ require (
 	github.com/aliyun/credentials-go v1.1.2 // indirect
 	github.com/andybalholm/cascadia v1.3.1 // indirect
 	github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211218165449-dd623ecc2f02 // indirect
-	github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
@@ -98,8 +95,8 @@ require (
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
 	github.com/rs/xid v1.5.0 // indirect
-	github.com/satori/go.uuid v1.2.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
+	github.com/sirupsen/logrus v1.9.3 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
 	github.com/stretchr/testify v1.8.1 // indirect
 	github.com/tidwall/gjson v1.14.1 // indirect

+ 2 - 8
go.sum

@@ -61,8 +61,8 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn
 github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1656 h1:YTWW7mBjwviuRvqiEpqaAj0AyVPj9AoJmQGCb5lXYUc=
 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1656/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible h1:ht2+VfbXtNLGhCsnTMc6/N26nSTBK6qdhktjYyjJQkk=
-github.com/aliyun/aliyun-oss-go-sdk v2.2.0+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible h1:so4m5rRA32Tc5GgKg/5gKUu0CRsYmVO3ThMP6T3CwLc=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.1+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
 github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
 github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
@@ -75,8 +75,6 @@ github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoU
 github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
 github.com/aws/aws-sdk-go v1.42.23 h1:V0V5hqMEyVelgpu1e4gMPVCJ+KhmscdNxP/NWP1iCOA=
 github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f h1:ZNv7On9kyUzm7fvRZumSyy/IUiSC7AzL0I1jKKtwooA=
-github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
 github.com/beego/bee/v2 v2.0.4 h1:nEjPwxJ8D+cr54eWChJGoGRH7bJ7OQwbhx8rU0OQf7E=
 github.com/beego/bee/v2 v2.0.4/go.mod h1:wq0YrEmPcdNfDNpaUgiTkaW9zso7M8n0HCCShEBOzM0=
 github.com/beego/beego/v2 v2.0.7 h1:9KNnUM40tn3pbCOFfe6SJ1oOL0oTi/oBS/C/wCEdAXA=
@@ -374,8 +372,6 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
 github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
-github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
@@ -629,8 +625,6 @@ gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 6 - 1
main.go

@@ -1,8 +1,9 @@
 package main
 
 import (
-	"fmt"
+	"eta/eta_api/controllers"
 	"eta/eta_api/services/alarm_msg"
+	"fmt"
 	"runtime"
 	"time"
 
@@ -21,6 +22,10 @@ func main() {
 		web.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
 	}
 	go services.Task()
+
+	// 异常处理
+	web.ErrorController(&controllers.ErrorController{})
+
 	web.BConfig.RecoverFunc = Recover
 	web.Run()
 }

+ 151 - 0
models/aimod/ai.go

@@ -0,0 +1,151 @@
+package aimod
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type AiChatTopic struct {
+	AiChatTopicId   int `orm:"column(ai_chat_topic_id);pk"`
+	TopicName       string
+	SysUserId       int
+	SysUserRealName string
+	CreateTime      time.Time
+	ModifyTime      time.Time
+}
+
+type AiChat struct {
+	AiChatId        int `orm:"column(ai_chat_id);pk"`
+	AiChatTopicId   int
+	Ask             string
+	AskUuid         string
+	Answer          string
+	Model           string
+	SysUserId       int
+	SysUserRealName string
+	CreateTime      time.Time
+	ModifyTime      time.Time
+}
+
+type ChatReq struct {
+	AiChatTopicId int    `description:"主题id"`
+	Ask           string `description:"提问"`
+}
+
+func GetAiChatByAsk(askUuid string) (item *AiChat, err error) {
+	sql := `SELECT * FROM ai_chat WHERE ask_uuid=?`
+	o := orm.NewOrmUsingDB("ai")
+	err = o.Raw(sql, askUuid).QueryRow(&item)
+	return
+}
+
+type ChatResp struct {
+	AiChatTopicId int    `description:"主题id"`
+	Ask           string `description:"提问"`
+	Answer        string `description:"回答"`
+	Model         string
+}
+
+// AddAiChatTopic 新增主题
+func AddAiChatTopic(item *AiChatTopic) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("ai")
+	lastId, err = o.Insert(item)
+	return
+}
+
+// AddAiChat 新增聊天
+func AddAiChat(item *AiChat) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("ai")
+	lastId, err = o.Insert(item)
+	return
+}
+
+type AiChatTopicView struct {
+	AiChatTopicId int    `description:"主题id"`
+	TopicName     string `description:"主题名称"`
+	CreateTime    string `description:"创建时间"`
+	ModifyTime    string `description:"修改时间"`
+}
+
+func GetAiChatTopicList(sysUserId int) (item []*AiChatTopicView, err error) {
+	sql := ` SELECT * FROM ai_chat_topic WHERE sys_user_id=? ORDER BY create_time DESC `
+	o := orm.NewOrmUsingDB("ai")
+	_, err = o.Raw(sql, sysUserId).QueryRows(&item)
+	return
+}
+
+type AiChatTopicListResp struct {
+	List []*AiChatTopicView
+}
+
+type AiChatView struct {
+	AiChatId      int    `description:"记录id"`
+	AiChatTopicId int    `description:"主题id"`
+	Ask           string `description:"提问"`
+	Answer        string `description:"答案"`
+	Model         string
+	CreateTime    string `description:"创建时间"`
+	ModifyTime    string `description:"修改时间"`
+}
+
+func GetAiChatList(aiChatTopicId int) (item []*AiChatView, err error) {
+	sql := ` SELECT * FROM ai_chat WHERE ai_chat_topic_id=? ORDER BY create_time ASC `
+	o := orm.NewOrmUsingDB("ai")
+	_, err = o.Raw(sql, aiChatTopicId).QueryRows(&item)
+	return
+}
+
+type AiChatDetailResp struct {
+	List []*AiChatView
+}
+
+type TopicDeleteReq struct {
+	AiChatTopicId int `description:"主题id"`
+}
+
+func DeleteTopic(topicId int) (err error) {
+	o := orm.NewOrmUsingDB("ai")
+	tx, err := o.Begin()
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	sql := ` DELETE FROM ai_chat_topic WHERE  ai_chat_topic_id=? `
+	_, err = tx.Raw(sql, topicId).Exec()
+	if err != nil {
+		return err
+	}
+	sql = ` DELETE FROM ai_chat WHERE  ai_chat_topic_id=? `
+	_, err = tx.Raw(sql, topicId).Exec()
+	if err != nil {
+		return err
+	}
+	return err
+}
+
+type TopicEditReq struct {
+	AiChatTopicId int    `description:"主题id"`
+	TopicName     string `description:"主题名称"`
+}
+
+func GetAiChatTopicByTopicName(topicName string) (item *AiChatTopicView, err error) {
+	sql := ` SELECT * FROM ai_chat_topic WHERE topic_name=? `
+	o := orm.NewOrmUsingDB("ai")
+	err = o.Raw(sql, topicName).QueryRow(&item)
+	return
+}
+
+func EditTopic(topicId int, topicName string) (err error) {
+	o := orm.NewOrmUsingDB("ai")
+	sql := ` UPDATE ai_chat_topic SET topic_name=? WHERE  ai_chat_topic_id=? `
+	_, err = o.Raw(sql, topicName, topicId).Exec()
+	return err
+}
+
+type HistoryChat struct {
+	Ask    string
+	Answer string
+}

+ 31 - 0
models/api_uri.go

@@ -0,0 +1,31 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type ApiUriTest struct {
+	ApiUri         string
+	ParentUri      string
+	Method         string
+	Description    string
+	MenuId         string
+	ParentMenu     string // 一级菜单
+	ChildMenu      string // 二级菜单
+	ButtonName     string // 按钮名称
+	Id             int    `orm:"column(id);pk"`
+	IsPublic       int    // 是否公共api,0否,1是
+	ChildChildMenu string // 三级菜单
+}
+
+func GetApiUriTest() (items []*ApiUriTest, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := ` SELECT * FROM api_uri_test `
+	_,err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+func UpdateApiUriTest(api string, menuId int) (err error) {
+	o := orm.NewOrm()
+	sql := ` UPDATE sys_menu SET api = ? where menu_id = ?`
+	_, err = o.Raw(sql, api, menuId).Exec()
+	return
+}

+ 20 - 6
models/business_conf.go

@@ -9,12 +9,19 @@ import (
 )
 
 const (
-	BusinessConfUseXf          = "UseXf"
-	BusinessConfXfAppid        = "XfAppid"
-	BusinessConfXfApiKey       = "XfApiKey"
-	BusinessConfXfApiSecret    = "XfApiSecret"
-	BusinessConfXfVcn          = "XfVcn"
-	BusinessConfEnPptCoverImgs = "EnPptCoverImgs"
+	BusinessConfUseXf             = "UseXf"
+	BusinessConfXfAppid           = "XfAppid"
+	BusinessConfXfApiKey          = "XfApiKey"
+	BusinessConfXfApiSecret       = "XfApiSecret"
+	BusinessConfXfVcn             = "XfVcn"
+	BusinessConfEnPptCoverImgs    = "EnPptCoverImgs"
+	BusinessConfIsReportApprove   = "IsReportApprove"
+	BusinessConfReportApproveType = "ReportApproveType"
+)
+
+const (
+	BusinessConfReportApproveTypeEta   = "eta"
+	BusinessConfReportApproveTypeOther = "other"
 )
 
 // BusinessConf 商户配置表
@@ -165,3 +172,10 @@ func UpdateBusinessConfMulti(items []BusinessConfUpdate) (err error) {
 	}
 	return
 }
+
+func GetBusinessConfByKey(key string) (item *BusinessConf, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM business_conf WHERE conf_key = ? LIMIT 1`)
+	err = o.Raw(sql, key).QueryRow(&item)
+	return
+}

+ 27 - 12
models/classify.go

@@ -214,17 +214,19 @@ func GetClassifyList(startSize, pageSize int, keyWord, companyType string, hideD
 	} else if companyType == "权益" {
 		companyTypeSqlStr = " AND (id = 40 or parent_id = 40)  "
 	}
+	pars := make([]interface{}, 0)
 	if keyWord != "" {
 		sql = `SELECT * FROM (
                    SELECT * FROM classify
-                   WHERE parent_id=0 ` + companyTypeSqlStr + `  AND classify_name LIKE '%` + keyWord + `%'
+                   WHERE parent_id=0 ` + companyTypeSqlStr + `  AND classify_name LIKE ?
                    UNION
                    SELECT * FROM classify
-                   WHERE id IN(SELECT parent_id FROM classify
-                   WHERE parent_id>0 ` + companyTypeSqlStr + `  AND classify_name LIKE '%` + keyWord + `%')
+                   WHERE id IN( SELECT parent_id FROM classify
+                   WHERE parent_id>0 ` + companyTypeSqlStr + `  AND classify_name LIKE ? )
                    )AS t
                    ORDER BY sort ASC,create_time ASC
                    LIMIT ?,? `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	} else {
 		sql = `SELECT * FROM classify WHERE parent_id=0 ` + companyTypeSqlStr
 		if hideDayWeek == 1 {
@@ -232,8 +234,10 @@ func GetClassifyList(startSize, pageSize int, keyWord, companyType string, hideD
 		}
 		sql += ` ORDER BY sort ASC, create_time ASC LIMIT ?,? `
 	}
+	pars = append(pars, startSize, pageSize)
+
 	o := orm.NewOrmUsingDB("rddp")
-	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
 	return
 }
 
@@ -246,16 +250,19 @@ func GetClassifyListCount(keyWord, companyType string, hideDayWeek int) (count i
 	} else if companyType == "权益" {
 		companyTypeSqlStr = " AND (id = 40 or parent_id = 40)  "
 	}
+
+	pars := make([]interface{}, 0)
+
 	if keyWord != "" {
 		sqlCount = `SELECT  COUNT(1) AS count FROM (
                SELECT * FROM classify
-               WHERE parent_id=0 ` + companyTypeSqlStr + `  AND classify_name LIKE '%` + keyWord + `%'
+               WHERE parent_id=0 ` + companyTypeSqlStr + `  AND classify_name LIKE ?
                UNION
                SELECT * FROM classify
                WHERE id IN(SELECT parent_id FROM classify
-               WHERE parent_id>0 ` + companyTypeSqlStr + `  AND classify_name LIKE '%` + keyWord + `%')
+               WHERE parent_id>0 ` + companyTypeSqlStr + `  AND classify_name LIKE ? )
                )AS t `
-
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
 	} else {
 		sqlCount = `SELECT COUNT(1) AS count FROM classify WHERE parent_id=0 ` + companyTypeSqlStr
 		if hideDayWeek == 1 {
@@ -263,7 +270,7 @@ func GetClassifyListCount(keyWord, companyType string, hideDayWeek int) (count i
 		}
 	}
 	o := orm.NewOrmUsingDB("rddp")
-	err = o.Raw(sqlCount).QueryRow(&count)
+	err = o.Raw(sqlCount, pars...).QueryRow(&count)
 	return
 }
 
@@ -292,12 +299,16 @@ type FindByIdClassifyReq struct {
 func GetClassifyChild(parentId int, keyWord string) (items []*Classify, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := ``
+	pars := make([]interface{}, 0)
 	if keyWord != "" {
-		sql = `SELECT * FROM classify WHERE parent_id=? AND classify_name LIKE '%` + keyWord + `%' ORDER BY create_time ASC `
+		sql = `SELECT * FROM classify WHERE classify_name LIKE ? AND parent_id=? ORDER BY create_time ASC `
+		pars = append(pars, utils.GetLikeKeyword(keyWord))
 	} else {
 		sql = `SELECT * FROM classify WHERE parent_id=? ORDER BY create_time ASC `
 	}
-	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	pars = append(pars, parentId)
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+
 	return
 }
 
@@ -308,12 +319,16 @@ func GetClassifyChildByParentIds(parentId []int, keyWord string) (items []*Class
 	}
 	o := orm.NewOrmUsingDB("rddp")
 	sql := ``
+	pars := make([]interface{}, 0)
+	pars = append(pars, parentId)
 	if keyWord != "" {
-		sql = `SELECT * FROM classify WHERE parent_id IN (` + utils.GetOrmInReplace(parentIdLen) + `) AND classify_name LIKE '%` + keyWord + `%' ORDER BY create_time ASC `
+		sql = `SELECT * FROM classify WHERE parent_id IN (` + utils.GetOrmInReplace(parentIdLen) + `) AND classify_name LIKE ? ORDER BY create_time ASC `
+		pars = append(pars, utils.GetLikeKeyword(keyWord))
 	} else {
 		sql = `SELECT * FROM classify WHERE parent_id IN (` + utils.GetOrmInReplace(parentIdLen) + `) ORDER BY create_time ASC `
 	}
-	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+
 	return
 }
 

+ 2 - 2
models/data_manage/baiinfo_data.go

@@ -138,8 +138,8 @@ func GetBaiinfoIndexDataCount(indexCode string) (count int, err error) {
 // GetBaiinfoItemList 模糊查询Baiinfo数据库指标列表
 func GetBaiinfoItemList(keyword string) (items []*BaiinfoIndex, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := "SELECT * FROM base_from_baiinfo_index WHERE CONCAT(index_name,index_code) LIKE '%" + keyword + "%'"
-	_, err = o.Raw(sql).QueryRows(&items)
+	sql := "SELECT * FROM base_from_baiinfo_index WHERE CONCAT(index_name,index_code) LIKE ? "
+	_, err = o.Raw(sql, utils.GetLikeKeyword(keyword)).QueryRows(&items)
 	return
 }
 

+ 1 - 1
models/data_manage/base_from_eia_stero.go

@@ -134,7 +134,7 @@ func GetEiaSteoIndexDataList(indexCode string, startSize, pageSize int) (items [
 func GetEiaSteoItemList(keyword string) (items []*BaseFromEiaSteoIndexItem, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := "SELECT * FROM base_from_eia_steo_index WHERE index_name LIKE ?  OR index_code like ?"
-	_, err = o.Raw(sql, `%`+keyword+`%`, `%`+keyword+`%`).QueryRows(&items)
+	_, err = o.Raw(sql, utils.GetLikeKeyword(keyword), utils.GetLikeKeyword(keyword)).QueryRows(&items)
 	return
 }
 

+ 98 - 0
models/data_manage/base_from_smm.go

@@ -4,6 +4,7 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"time"
 )
 
@@ -72,6 +73,10 @@ type BaseFromSmmIndex struct {
 	Sort               int
 	CreateTime         time.Time
 	ModifyTime         time.Time
+	DataState          string
+	ReleaseTime        string
+	StartDate          string
+	EndDate            string
 }
 
 func AddBaseFromSmmIndex(item *BaseFromSmmIndex) (lastId int64, err error) {
@@ -327,3 +332,96 @@ type SmmSingleDataResp struct {
 	ModifyTime         string
 	Data               []*SmmIndexData
 }
+
+func GetSmmIndexDataList(condition, sortStr string, pars []interface{}, startSize, pageSize int) (items []*BaseFromSmmIndexItem, err error) {
+	sql := `select * FROM base_from_smm_index
+               WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY ` + sortStr
+	sql += `  limit ?,? `
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetSmmIndexDataListCount(condition string, pars []interface{}) (total int, err error) {
+	sql := `select count(1) FROM base_from_smm_index
+               WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	o := orm.NewOrmUsingDB("data")
+	err = o.Raw(sql, pars).QueryRow(&total)
+	return
+}
+
+type BaseFromSmmIndexListResp struct {
+	List   []*BaseFromSmmIndexItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type BaseFromSmmIndexItem struct {
+	BaseFromSmmIndexId int `orm:"column(base_from_smm_index_id);pk"`
+	ClassifyId         int
+	Interface          string
+	Name               string
+	IndexCode          string
+	IndexName          string
+	Type1              string `orm:"column(type_1)"`
+	Type2              string `orm:"column(type_2)"`
+	Type3              string `orm:"column(type_3)"`
+	Frequency          string
+	Unit               string
+	ApiStartTime       string
+	ApiUpdateTime      string
+	StartTime          string
+	FinishTime         string
+	Sort               int
+	CreateTime         string
+	ModifyTime         string
+	DataState          string
+	ReleaseTime        string
+	StartDate          string
+	EndDate            string
+	TypeAll            string
+}
+
+type BaseFromSmmIndexTypeList struct {
+	Type1 string `orm:"column(type_1)"`
+	Type2 string `orm:"column(type_2)"`
+	Type3 string `orm:"column(type_3)"`
+}
+
+
+// GetBaseFromSmmIndexTypeList
+func GetBaseFromSmmIndexTypeList() (list []BaseFromSmmIndexTypeList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT type_1,type_2, type_3 from base_from_smm_index GROUP BY type_1,type_2,type_3 `
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
+type TypeListRespItem struct {
+	Type string
+	Child []TypeListRespItem
+}
+
+func GetSmmIndexDataListNoPage(condition string, pars []interface{}) (items []*BaseFromSmmIndexItem, err error) {
+	sql := `select * FROM base_from_smm_index
+               WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func GetBaseFromSmmIndexByIndexCodes(indexCodes string) (list []*BaseFromSmmIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_smm_index WHERE index_code IN (` + indexCodes + `)`
+	_,err = o.Raw(sql).QueryRows(&list)
+	return
+}

+ 9 - 1
models/data_manage/base_from_smm_classify.go

@@ -1,9 +1,9 @@
 package data_manage
 
 import (
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
-	"eta/eta_api/utils"
 	"time"
 )
 
@@ -103,6 +103,14 @@ func GetBaseFromSmmClassifyByParentId(parentId int) (items []*BaseFromSmmClassif
 	return
 }
 
+// GetBaseFromSmmClassifyByIds 根据id获取当下的分类列表数据
+func GetBaseFromSmmClassifyByIds(classifyIds []int) (items []*BaseFromSmmClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_smm_classify WHERE parent_id > 0 and classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `) order by sort asc, classify_id asc`
+	_, err = o.Raw(sql, classifyIds).QueryRows(&items)
+	return
+}
+
 // GetAllBaseFromSmmClassify 获取所有的分类列表数据
 func GetAllBaseFromSmmClassify() (items []*BaseFromSmmClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")

+ 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
+}

+ 23 - 0
models/data_manage/chart_classify.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
@@ -214,6 +215,14 @@ func GetFirstChartClassifyByParentId(parentId int) (item *ChartClassify, err err
 	return
 }
 
+// GetFirstChartClassifyByParentIdAndSource 获取当前父级图表分类下的排序第一条的数据
+func GetFirstChartClassifyByParentIdAndSource(parentId, source int) (item *ChartClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM chart_classify WHERE parent_id=?  and source = ? order by sort asc,chart_classify_id asc limit 1`
+	err = o.Raw(sql, parentId, source).QueryRow(&item)
+	return
+}
+
 // UpdateChartClassifySortByParentId 根据图表父类id更新排序
 func UpdateChartClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -294,3 +303,17 @@ func GetAllChartClassifyItemsBySource(source int) (items []*ChartClassifyItems,
 	_, err = o.Raw(sql, source).QueryRows(&items)
 	return
 }
+
+// GetCrossVarietyChartClassifyBySysUserId
+// @Description: 根据创建人获取跨品种分析的分类
+// @author: Roc
+// @datetime 2023-11-24 14:05:43
+// @param sysUserId int
+// @return item *ChartClassify
+// @return err error
+func GetCrossVarietyChartClassifyBySysUserId(sysUserId int) (item *ChartClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_classify WHERE source = ? AND sys_user_id=?`
+	err = o.Raw(sql, utils.CHART_SOURCE_CROSS_HEDGING, sysUserId).QueryRow(&item)
+	return
+}

+ 108 - 7
models/data_manage/chart_edb_mapping.go

@@ -2,8 +2,11 @@ package data_manage
 
 import (
 	"eta/eta_api/utils"
+	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
+	"strings"
 	"time"
 )
 
@@ -36,7 +39,7 @@ func AddChartEdbMapping(items []*ChartEdbMapping) (err error) {
 
 func GetChartEdbMappingList(chartInfoId int) (list []*ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.*,b.source_name,b.source,b.classify_id,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
+	sql := ` SELECT a.*,b.source_name,b.source,b.sub_source,b.classify_id,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE chart_info_id=? 
@@ -47,7 +50,7 @@ func GetChartEdbMappingList(chartInfoId int) (list []*ChartEdbInfoMapping, err e
 
 func GetChartEdbMappingListByChartInfoIds(chartInfoIds string) (list []*ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.*,b.source_name,b.source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
+	sql := ` SELECT a.*,b.source_name,b.source,b.sub_source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type,b.edb_type
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE chart_info_id in (` + chartInfoIds + `) 
@@ -58,7 +61,7 @@ func GetChartEdbMappingListByChartInfoIds(chartInfoIds string) (list []*ChartEdb
 
 func GetChartEdbMappingListByEdbInfoId(edbInfoStr string) (list []*ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT edb_info_id,source_name,source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value,edb_type
+	sql := ` SELECT edb_info_id,source_name,source,sub_source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value,edb_type
              FROM edb_info
 			 WHERE edb_info_id IN(` + edbInfoStr + `)
 			ORDER BY FIELD(edb_info_id,` + edbInfoStr + `)
@@ -74,7 +77,7 @@ func GetChartEdbMappingListByEdbInfoIdList(edbIdList []int) (list []*ChartEdbInf
 		return
 	}
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT edb_info_id,source_name,source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value,edb_type
+	sql := ` SELECT edb_info_id,source_name,source,sub_source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value,edb_type
              FROM edb_info
 			 WHERE edb_info_id IN(` + utils.GetOrmInReplace(num) + `)
 			ORDER BY FIELD(edb_info_id,` + utils.GetOrmInReplace(num) + `)
@@ -90,7 +93,7 @@ func GetChartEdbMappingListByIdList(chartInfoIdList []int) (list []*ChartEdbInfo
 		return
 	}
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.*,b.source_name,b.source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type,b.edb_type AS edb_info_category_type
+	sql := ` SELECT a.*,b.source_name,b.source,b.sub_source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type,b.edb_type AS edb_info_category_type
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE chart_info_id in (` + utils.GetOrmInReplace(num) + `) 
@@ -134,7 +137,7 @@ func GetEtaEdbChartEdbMapping(chartInfoId int) (item *ChartEdbInfoMapping, err e
 	o := orm.NewOrmUsingDB("data")
 	aField := `a.chart_edb_mapping_id,a.chart_info_id,a.edb_info_id,a.create_time,a.modify_time,a.unique_code,a.max_data,a.min_data,a.is_order,a.is_axis,a.edb_info_type,a.lead_value,a.lead_unit,a.chart_style,a.chart_color,a.predict_chart_color,a.chart_width,a.source as mapping_source`
 
-	sql := ` SELECT ` + aField + `,b.source_name,b.source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type
+	sql := ` SELECT ` + aField + `,b.source_name,b.source,b.sub_source,b.edb_code,b.edb_name,b.edb_name_en,b.frequency,b.unit,b.unit_en,b.start_date,b.end_date,b.modify_time,b.latest_date,b.latest_value,b.unique_code,b.edb_info_type AS edb_info_category_type
              FROM chart_edb_mapping AS a
 			 INNER JOIN edb_info AS b ON a.edb_info_id=b.edb_info_id
 			 WHERE a.chart_info_id=? AND a.source = ?
@@ -182,7 +185,7 @@ func GetChartEdbMappingListV2(chartInfoId int) (list []*ChartEdbInfoMapping, err
 // GetChartEdbMappingByEdbInfoId 根据指标id获取edb_mapping
 func GetChartEdbMappingByEdbInfoId(edbInfoId int) (item *ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT edb_info_id,source_name,classify_id,source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value
+	sql := ` SELECT edb_info_id,source_name,classify_id,source,sub_source,edb_code,edb_name,edb_name_en,frequency,unit,unit_en,start_date,end_date,modify_time,latest_date,latest_value,unique_code,edb_info_type AS edb_info_category_type,max_value,min_value
              FROM edb_info
 			 WHERE edb_info_id = ? limit 1`
 	err = o.Raw(sql, edbInfoId).QueryRow(&item)
@@ -198,3 +201,101 @@ func GetChartEdbMappingByFutureGoodEdbInfoId(edbInfoId int) (item *ChartEdbInfoM
 	err = o.Raw(sql, edbInfoId).QueryRow(&item)
 	return
 }
+
+// ModifyChartEdbMapping
+// @Description: 修改图表的关系表
+// @author: Roc
+// @datetime 2023-12-11 17:23:32
+// @param chartInfoId int
+// @param edbInfoList []*EdbInfo
+// @return err error
+func ModifyChartEdbMapping(chartInfoId int, edbInfoList []*EdbInfo) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			fmt.Println("AddCalculateHcz,Err:" + err.Error())
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+	list := make([]*ChartEdbMapping, 0)
+	sql := ` SELECT a.*
+             FROM chart_edb_mapping AS a
+			 WHERE chart_info_id=? 
+             ORDER BY chart_edb_mapping_id ASC `
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&list)
+
+	if err != nil {
+		return
+	}
+
+	mappingIdMap := make(map[int]*ChartEdbMapping)
+	removeMapping := make(map[int]int)
+	for _, v := range list {
+		mappingIdMap[v.EdbInfoId] = v
+		removeMapping[v.EdbInfoId] = v.ChartEdbMappingId
+	}
+
+	addList := make([]*ChartEdbMapping, 0)
+	for _, v := range edbInfoList {
+		_, ok := mappingIdMap[v.EdbInfoId]
+		// 存在该指标关系就不处理了
+		if ok {
+			delete(removeMapping, v.EdbInfoId)
+			continue
+		}
+		timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		// 不存在就添加
+		addList = append(addList, &ChartEdbMapping{
+			//ChartEdbMappingId: 0,
+			ChartInfoId: chartInfoId,
+			EdbInfoId:   v.EdbInfoId,
+			CreateTime:  time.Now(),
+			ModifyTime:  time.Now(),
+			UniqueCode:  utils.MD5(utils.CHART_PREFIX + "_" + fmt.Sprint(chartInfoId) + "_" + fmt.Sprint(v.EdbInfoId) + "_" + timestamp),
+			MaxData:     v.MaxValue,
+			MinData:     v.MinValue,
+			//IsOrder:     v.IsOrder,
+			//IsAxis:      v.IsAxis,
+			EdbInfoType: v.EdbInfoType,
+			//LeadValue:   v.LeadValue,
+			//LeadUnit:    v.LeadUnit,
+			//ChartStyle:  v.ChartStyle,
+			//ChartColor:  v.ChartColor,
+			//ChartWidth:  v.ChartWidth,
+			Source: v.Source,
+		})
+	}
+
+	// 需要添加的话,那就添加吧
+	if len(addList) > 0 {
+		_, err = o.InsertMulti(len(addList), addList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 移除不必要的mapping
+	if len(removeMapping) > 0 {
+		removeIdList := make([]string, 0) //需要移除的日期
+		for _, v := range removeMapping {
+			removeIdList = append(removeIdList, fmt.Sprint(v))
+		}
+		removeIdStr := strings.Join(removeIdList, `","`)
+		removeIdStr = `"` + removeIdStr + `"`
+		//如果拼接指标变更了,那么需要删除所有的指标数据
+		sql := fmt.Sprintf(` DELETE FROM chart_edb_mapping WHERE chart_edb_mapping_id in (%s) `, removeIdStr)
+
+		_, err = o.Raw(sql).Exec()
+		if err != nil {
+			err = fmt.Errorf("移除不必要的mapping失败,Err:" + err.Error())
+			return
+		}
+	}
+
+	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
 }

+ 18 - 14
models/data_manage/chart_info.go

@@ -72,7 +72,7 @@ func GetChartInfoAll(sourceList []int) (items []*ChartClassifyItems, err error)
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT chart_info_id,chart_classify_id,chart_name AS chart_classify_name,
              unique_code,sys_user_id,sys_user_real_name,date_type,start_date,end_date,chart_type,calendar,season_start_date,season_end_date,source
-            FROM chart_info WHERE source in (` + utils.GetOrmInReplace(num) + `)  ORDER BY sort asc,create_time ASC `
+            FROM chart_info WHERE source in (` + utils.GetOrmInReplace(num) + `)  ORDER BY sort asc,chart_info_id ASC `
 	_, err = o.Raw(sql, sourceList).QueryRows(&items)
 	return
 }
@@ -322,8 +322,8 @@ type EdbDataList struct {
 }
 
 // GetEdbDataList 获取指标的数据(日期正序返回)
-func GetEdbDataList(source, endInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
-	tableName := GetEdbDataTableName(source)
+func GetEdbDataList(source, subSource, endInfoId int, startDate, endDate string) (list []*EdbDataList, err error) {
+	tableName := GetEdbDataTableName(source, subSource)
 	if tableName == "" {
 		err = errors.New("无效的渠道:" + strconv.Itoa(source))
 		list = make([]*EdbDataList, 0)
@@ -355,8 +355,8 @@ type EdbDataListByUniqueCode struct {
 	Value         float64 `description:"数据值"`
 }
 
-func GetEdbDataListByByUniqueCode(source, endInfoId int, startDate, endDate string) (list []*EdbDataListByUniqueCode, err error) {
-	tableName := GetEdbDataTableName(source)
+func GetEdbDataListByByUniqueCode(source, subSource, endInfoId int, startDate, endDate string) (list []*EdbDataListByUniqueCode, err error) {
+	tableName := GetEdbDataTableName(source, subSource)
 	if tableName == "" {
 		err = errors.New("无效的渠道:" + strconv.Itoa(source))
 		list = make([]*EdbDataListByUniqueCode, 0)
@@ -389,8 +389,8 @@ func GetEdbDataLunarList(endInfoId int, startDate, endDate string) (list []*EdbD
 	return
 }
 
-func GetEdbDataListMinAndMax(source, endInfoId int, startDate, endDate string) (min_data, max_data float64, err error) {
-	tableName := GetEdbDataTableName(source)
+func GetEdbDataListMinAndMax(source, subSource, endInfoId int, startDate, endDate string) (min_data, max_data float64, err error) {
+	tableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT min(value) AS min_data,max(value) AS max_data FROM %s WHERE edb_info_id=? `
 	var pars []interface{}
 	var condition string
@@ -420,6 +420,7 @@ type ChartEdbInfoMapping struct {
 	EdbInfoId           int     `description:"指标id"`
 	SourceName          string  `description:"来源名称"`
 	Source              int     `description:"来源id"`
+	SubSource           int     `description:"来源id"`
 	EdbCode             string  `description:"指标编码"`
 	EdbName             string  `description:"指标名称"`
 	EdbAliasName        string  `description:"指标名称(别名)"`
@@ -1012,8 +1013,8 @@ func EditChartEnInfoAndEdbEnInfo(req *EditChartEnInfoReq) (err error) {
 	return
 }
 
-func ModifyEdbDatadTimestamp(source, edbDataId int, dataTimestamp int64) (err error) {
-	tableName := GetEdbDataTableName(source)
+func ModifyEdbDatadTimestamp(source, subSource, edbDataId int, dataTimestamp int64) (err error) {
+	tableName := GetEdbDataTableName(source, subSource)
 	sql := `UPDATE %s SET data_timestamp=? WHERE edb_data_id=? `
 	sql = fmt.Sprintf(sql, tableName)
 	o := orm.NewOrmUsingDB("data")
@@ -1102,15 +1103,15 @@ func ChartInfoExist(condition, edbInfoIdStr string) (count int, err error) {
 	return
 }
 
-func ChartInfoSearchByKeyWord(KeyWord string, showSysId int) (searchList []*ChartInfo, err error) {
+func ChartInfoSearchByKeyWord(keyword string, showSysId int) (searchList []*ChartInfo, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM chart_info WHERE 1=1 `
 
 	var pars []interface{}
 
-	if KeyWord != "" {
+	if keyword != "" {
 		sql += `AND chart_name LIKE ?  `
-		pars = append(pars, "%"+KeyWord+"%")
+		pars = append(pars, utils.GetLikeKeyword(keyword))
 	}
 
 	if showSysId > 0 {
@@ -1118,7 +1119,7 @@ func ChartInfoSearchByKeyWord(KeyWord string, showSysId int) (searchList []*Char
 		pars = append(pars, showSysId)
 	}
 	sql += ` ORDER BY create_time DESC `
-	if KeyWord == "" {
+	if keyword == "" {
 		sql += ` LIMIT 100 `
 	}
 	_, err = o.Raw(sql, pars).QueryRows(&searchList)
@@ -1376,7 +1377,10 @@ func GetChartInfoByClassifyIdAndName(classifyId int, chartName string) (item *Ch
 
 // BatchChartRefreshReq 批量刷新图表请求
 type BatchChartRefreshReq struct {
-	ChartInfoCode []string `description:"图表编码数组"`
+	ChartInfoCode   []string `description:"图表编码数组"`
+	ReportId        int      `description:"报告id"`
+	ReportChapterId int      `description:"报告章节id"`
+	Source          string   `description:"来源,枚举值:report、english_report、smart_report"`
 }
 
 // GetChartInfoListByUniqueCodeSlice 根据图表编码获取图表列表数据

+ 3 - 2
models/data_manage/coal_data.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 )
@@ -15,8 +16,8 @@ type BaseFromCoalmineMapping struct {
 // GetCoalItemList 模糊查询Smm数据库指标列表
 func GetCoalItemList(keyword string) (items []*BaseFromCoalmineMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := "SELECT * FROM base_from_coalmine_mapping WHERE CONCAT(index_name,index_code) LIKE '%" + keyword + "%'"
-	_, err = o.Raw(sql).QueryRows(&items)
+	sql := "SELECT * FROM base_from_coalmine_mapping WHERE CONCAT(index_name,index_code) LIKE ? "
+	_, err = o.Raw(sql, utils.GetLikeKeyword(keyword)).QueryRows(&items)
 	return
 }
 

+ 264 - 0
models/data_manage/cross_variety/chart_info_cross_variety.go

@@ -0,0 +1,264 @@
+package cross_variety
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/cross_variety/request"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// ChartInfoCrossVariety
+// @Description: 跨品种分析配置表
+type ChartInfoCrossVariety struct {
+	Id             int       `orm:"column(id);pk"`
+	ChartInfoId    int       `description:"图表id"`
+	ChartXTagId    int       `description:"X轴的标签ID"`
+	ChartYTagId    int       `description:"X轴的标签ID"`
+	CalculateValue int       `description:"计算窗口"`
+	CalculateUnit  string    `description:"计算频度"`
+	ModifyTime     time.Time `description:"修改时间"`
+	CreateTime     time.Time `description:"创建时间"`
+}
+
+// GetCountChartByTagId
+// @Description: 根据标签id获取引用该标签的图表数量
+// @author: Roc
+// @datetime 2023-11-27 10:41:46
+// @param tagId int
+// @return total int64
+// @return err error
+func GetCountChartByTagId(tagId int) (total int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT count(1) total FROM chart_info AS a JOIN
+    chart_info_cross_variety AS b on a.chart_info_id = b.chart_info_id 
+    WHERE b.chart_x_tag_id = ? or b.chart_y_tag_id=?`
+	err = o.Raw(sql, tagId, tagId).QueryRow(&total)
+
+	return
+}
+
+// GeChartInfoCrossVarietyListByTagId
+// @Description: 根据标签id获取引用该标签的配置列表
+// @author: Roc
+// @datetime 2023-12-11 13:13:59
+// @param tagId int
+// @return items []*ChartInfoCrossVariety
+// @return err error
+func GeChartInfoCrossVarietyListByTagId(tagId int) (items []*ChartInfoCrossVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT b.* FROM chart_info AS a JOIN
+    chart_info_cross_variety AS b on a.chart_info_id = b.chart_info_id 
+    WHERE b.chart_x_tag_id = ? or b.chart_y_tag_id=?`
+	_, err = o.Raw(sql, tagId, tagId).QueryRows(&items)
+
+	return
+}
+
+// GetChartInfoCrossVarietyByChartInfoId
+// @Description: 根据图表id获取跨品种分析配置信息
+// @author: Roc
+// @datetime 2023-11-24 14:34:50
+// @param id int
+// @return item *ChartInfoCrossVariety
+// @return err error
+func GetChartInfoCrossVarietyByChartInfoId(id int) (item *ChartInfoCrossVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_info_cross_variety WHERE chart_info_id = ?`
+	err = o.Raw(sql, id).QueryRow(&item)
+
+	return
+}
+
+// CreateChart
+// @Description: 新增跨品种图表
+// @author: Roc
+// @datetime 2023-11-24 14:27:31
+// @param chartInfo *data_manage.ChartInfo
+// @param classify *data_manage.ChartClassify
+// @param chartVarietyMappingList []*ChartVarietyMapping
+// @param chartInfoCrossVariety *ChartInfoCrossVariety
+// @return chartInfoId int
+// @return err error
+func CreateChart(chartInfo *data_manage.ChartInfo, classify *data_manage.ChartClassify, chartVarietyMappingList []*ChartVarietyMapping, chartInfoCrossVariety *ChartInfoCrossVariety) (chartInfoId int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+		} else {
+			_ = tx.Commit()
+		}
+	}()
+
+	// 判断是否分类已存在,不存在的话,先添加分类
+	if classify.ChartClassifyId <= 0 {
+		newId, tmpErr := tx.Insert(classify)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		classify.ChartClassifyId = int(newId)
+	}
+
+	// 新增图表信息
+	chartInfo.ChartClassifyId = classify.ChartClassifyId
+	newId, err := tx.Insert(chartInfo)
+	if err != nil {
+		return
+	}
+	// 品种列表
+	chartInfo.ChartInfoId = int(newId)
+	chartInfoId = int(newId)
+
+	if len(chartVarietyMappingList) > 0 {
+		for i := range chartVarietyMappingList {
+			chartVarietyMappingList[i].ChartInfoId = chartInfoId
+		}
+		_, err = tx.InsertMulti(len(chartVarietyMappingList), chartVarietyMappingList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 图表配置
+	chartInfoCrossVariety.ChartInfoId = chartInfoId
+	if _, err = tx.Insert(chartInfoCrossVariety); err != nil {
+		return
+	}
+
+	return
+}
+
+// EditChart 修改相关性图表的 图表与指标 的关系
+func EditChart(chartInfo *data_manage.ChartInfo, chartVarietyMappingList []*ChartVarietyMapping, chartInfoCrossVariety *ChartInfoCrossVariety, chartUpdateCols, chartInfoCrossVarietyUpdateCols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 更新图表信息
+	_, err = to.Update(chartInfo, chartUpdateCols...)
+	if err != nil {
+		fmt.Println("UPDATE  chart_info Err:", err.Error())
+		return err
+	}
+
+	// 查找现有的品种列表
+	currVarietyMappingList := make([]*ChartVarietyMapping, 0)
+	sql := `SELECT * FROM chart_variety_mapping WHERE chart_info_id = ? `
+	_, err = to.Raw(sql, chartInfo.ChartInfoId).QueryRows(&currVarietyMappingList)
+	if err != nil {
+		return
+	}
+
+	currVarietyMap := make(map[int]*ChartVarietyMapping)
+	for _, v := range currVarietyMappingList {
+		currVarietyMap[v.ChartVarietyId] = v
+	}
+
+	// 待添加的品种列表
+	addVarietyMappingList := make([]*ChartVarietyMapping, 0)
+
+	for i := range chartVarietyMappingList {
+		_, ok := currVarietyMap[i]
+		if !ok {
+			// 如果不存在,那么就添加
+			chartVarietyMappingList[i].ChartInfoId = chartInfo.ChartInfoId
+			addVarietyMappingList = append(addVarietyMappingList, chartVarietyMappingList[i])
+		} else {
+			// 如果存在那么就移除
+			delete(currVarietyMap, i)
+		}
+	}
+
+	// 添加品种
+	if len(addVarietyMappingList) > 0 {
+		_, err = to.InsertMulti(len(addVarietyMappingList), addVarietyMappingList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除不存在的品种
+	if len(currVarietyMap) > 0 {
+		idStrList := make([]string, 0)
+		for id, _ := range currVarietyMap {
+			idStrList = append(idStrList, fmt.Sprint(id))
+		}
+		removeIdStr := strings.Join(idStrList, `,`)
+		sql = fmt.Sprintf(` DELETE FROM chart_variety_mapping WHERE id in (%s) `, removeIdStr)
+		_, err = to.Raw(sql).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 跨品种分析图表配置
+	_, err = to.Update(chartInfoCrossVariety, chartInfoCrossVarietyUpdateCols...)
+
+	return
+}
+
+// EditChartEn
+// @Description: 修改英文名称
+// @author: Roc
+// @datetime 2023-11-28 21:17:27
+// @param chartInfo *data_manage.ChartInfo
+// @param req request.EditChartEnInfoReq
+// @return err error
+func EditChartEn(chartInfo *data_manage.ChartInfo, req request.EditChartEnInfoReq) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 更新图表信息
+	chartInfo.ChartNameEn = req.ChartNameEn
+	chartInfo.ModifyTime = time.Now().Local()
+	_, err = to.Update(chartInfo, "ChartNameEn", "ModifyTime")
+	if err != nil {
+		fmt.Println("UPDATE  chart_info Err:", err.Error())
+		return err
+	}
+
+	// 更新标签英文名
+	for _, v := range req.TagList {
+		sql := `UPDATE chart_tag SET chart_tag_name_en = ?,modify_time= NOW() WHERE chart_tag_id = ? `
+		_, err = o.Raw(sql, v.TagNameEn, v.ChartTagId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 更新品种英文名
+	for _, v := range req.VarietyList {
+		sql := `UPDATE chart_variety SET chart_variety_name_en = ?,modify_time= NOW() WHERE chart_variety_id = ? `
+		_, err = o.Raw(sql, v.VarietyNameEn, v.ChartVarietyId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}

+ 148 - 0
models/data_manage/cross_variety/chart_tag.go

@@ -0,0 +1,148 @@
+package cross_variety
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ChartTag
+// @Description: chart_tag 图表标签表
+type ChartTag struct {
+	ChartTagId      int       `orm:"column(chart_tag_id);pk"`
+	ChartTagName    string    `description:"标签名称"`
+	ChartTagNameEn  string    `description:"标签名称(英文)"`
+	SysUserId       int       `description:"创建人id"`
+	SysUserRealName string    `description:"创建人姓名"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+}
+
+// GetTagById
+// @Description: 根据标签id获取标签详情
+// @author: Roc
+// @datetime 2023-11-21 14:55:31
+// @param id int
+// @return item *ChartTag
+// @return err error
+func GetTagById(id int) (item *ChartTag, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag WHERE chart_tag_id = ?`
+	err = o.Raw(sql, id).QueryRow(&item)
+
+	return
+}
+
+// GetTagByName
+// @Description: 根据标签名称获取标签详情
+// @author: Roc
+// @datetime 2023-11-21 14:55:20
+// @param name string
+// @return item *ChartTag
+// @return err error
+func GetTagByName(name string) (item *ChartTag, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag WHERE chart_tag_name = ?`
+	err = o.Raw(sql, name).QueryRow(&item)
+
+	return
+}
+
+// AddTag
+// @Description: 添加标签
+// @author: Roc
+// @datetime 2023-11-21 14:52:56
+// @param item *ChartTag
+// @return err error
+func AddTag(item *ChartTag) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	lastId, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+
+	item.ChartTagId = int(lastId)
+
+	return
+}
+
+// GetTagList
+// @Description: 获取所有标签列表
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @return items []*ChartTag
+// @return err error
+func GetTagList() (items []*ChartTag, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag WHERE 1 = 1 `
+	_, err = o.Raw(sql).QueryRows(&items)
+
+	return
+}
+
+// Update
+// @Description: 更新标签
+// @author: Roc
+// @receiver item
+// @datetime 2023-11-21 15:15:17
+// @param updateColList []string
+// @return err error
+func (item *ChartTag) Update(updateColList []string) (err error) {
+	to := orm.NewOrmUsingDB("data")
+	_, err = to.Update(item, updateColList...)
+
+	return
+}
+
+// Delete 删除
+func (item *ChartTag) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(item)
+	return
+}
+
+// GetTagListByIdList
+// @Description: 根据ID列表获取标签列表
+// @author: Roc
+// @datetime 2023-11-23 17:56:39
+// @param idList []int
+// @return items []*ChartTag
+// @return err error
+func GetTagListByIdList(idList []int) (items []*ChartTag, err error) {
+	num := len(idList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag WHERE 1 = 1 AND chart_tag_id in (` + utils.GetOrmInReplace(num) + `)`
+	_, err = o.Raw(sql, idList).QueryRows(&items)
+
+	return
+}
+
+// ChartTagItem
+// @Description: chart_tag 图表标签表
+type ChartTagItem struct {
+	ChartTagId      int       `orm:"column(chart_tag_id);pk"`
+	ChartTagName    string    `description:"标签名称"`
+	ChartTagNameEn  string    `description:"标签名称(英文)"`
+	SysUserId       int       `description:"创建人id"`
+	VarietyTotal    int       `description:"配置关联品种的数量"`
+	SysUserRealName string    `description:"创建人姓名"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+}
+
+// GetTagItemList
+// @Description: 获取所有标签列表(列表页用到的)
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @return items []*ChartTag
+// @return err error
+func GetTagItemList() (items []*ChartTagItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag WHERE 1 = 1 `
+	_, err = o.Raw(sql).QueryRows(&items)
+
+	return
+}

+ 262 - 0
models/data_manage/cross_variety/chart_tag_variety.go

@@ -0,0 +1,262 @@
+package cross_variety
+
+import (
+	"eta/eta_api/models/data_manage/cross_variety/request"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// ChartTagVariety
+// @Description: chart_tag_variety 图表标签品种关系表
+type ChartTagVariety struct {
+	Id                        int       `orm:"column(id);pk"`
+	ChartTagId                int       `description:"标签id"`
+	ChartVarietyId            int       `description:"品种id"`
+	EdbInfoId                 int       `description:"指标id"`
+	LastUpdateSysUserId       int       `description:"最后一次操作人"`
+	LastUpdateSysUserRealName string    `description:"最后一次操作人真实姓名"`
+	ModifyTime                time.Time `description:"修改时间"`
+	CreateTime                time.Time `description:"创建时间"`
+}
+
+// GetChartTagVarietyByTagAndVariety
+// @Description: 根据标签id和品种id获取关系
+// @author: Roc
+// @datetime 2023-11-22 10:42:50
+// @param chartTagId int
+// @param chartVarietyId int
+// @return item *ChartTagVariety
+// @return err error
+func GetChartTagVarietyByTagAndVariety(chartTagId, chartVarietyId int) (item *ChartTagVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag_variety WHERE chart_tag_id = ? AND chart_variety_id = ?`
+	err = o.Raw(sql, chartTagId, chartVarietyId).QueryRow(&item)
+
+	return
+}
+
+// GetChartTagVarietyListByTag
+// @Description: 根据标签id获取所有绑定的品种列表
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @param chartTagId int
+// @param chartVarietyId int
+// @return items []*ChartTagVariety
+// @return err error
+func GetChartTagVarietyListByTag(chartTagId int) (items []*ChartTagVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag_variety WHERE chart_tag_id = ? `
+	_, err = o.Raw(sql, chartTagId).QueryRows(&items)
+
+	return
+}
+
+// GetChartTagVarietyListByTagAndVariety
+// @Description: 根据标签id和品种id列表获取所绑定的品种列表
+// @author: Roc
+// @datetime 2023-11-23 15:04:20
+// @param chartTagId int
+// @param varietyIdList []int
+// @return items []*ChartTagVariety
+// @return err error
+func GetChartTagVarietyListByTagAndVariety(chartTagId int, varietyIdList []int) (items []*ChartTagVariety, err error) {
+	num := len(varietyIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_tag_variety WHERE chart_tag_id = ? AND chart_variety_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, chartTagId, varietyIdList).QueryRows(&items)
+
+	return
+}
+
+// ChartTagVarietyItem
+// @Description: 图表标签/品种/指标数据
+type ChartTagVarietyItem struct {
+	Id             int     `orm:"column(id);pk"`
+	ChartTagId     int     `description:"标签id"`
+	ChartVarietyId int     `description:"品种id"`
+	EdbInfoId      int     `description:"指标id"`
+	EdbCode        string  `description:"指标编码"`
+	EdbName        string  `description:"指标名称"`
+	EndDate        string  `description:"数据的最晚日期"`
+	EndValue       float64 `description:"数据最新值"`
+}
+
+// GetChartTagVarietyItemListByTag
+// @Description: 根据标签id获取所有绑定的品种列表
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @param chartTagId int
+// @param chartVarietyId int
+// @return items []*ChartTagVariety
+// @return err error
+func GetChartTagVarietyItemListByTag(chartTagId int) (items []*ChartTagVarietyItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.*,b.edb_code,b.edb_name,b.end_date,b.end_value FROM chart_tag_variety a 
+         join edb_info b on a.edb_info_id=b.edb_info_id WHERE chart_tag_id = ? `
+	_, err = o.Raw(sql, chartTagId).QueryRows(&items)
+
+	return
+}
+
+// ChartTagVarietyCount
+// @Description: 签绑定的品种数量
+type ChartTagVarietyCount struct {
+	ChartTagId int `description:"标签id"`
+	Total      int `description:"标签配置的品种数量"`
+}
+
+// GetCountChartTagVarietyItemListByTag
+// @Description: 获取所有标签绑定的品种数量
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @return items []*ChartTagVarietyCount
+// @return err error
+func GetCountChartTagVarietyItemListByTag() (items []*ChartTagVarietyCount, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT chart_tag_id,count(1) total FROM chart_tag_variety a 
+         join edb_info b on a.edb_info_id=b.edb_info_id  group by chart_tag_id`
+	_, err = o.Raw(sql).QueryRows(&items)
+
+	return
+}
+
+// SaveVarietyEdb
+// @Description: 配置标签中的指标与品种的映射关系
+// @author: Roc
+// @datetime 2023-11-22 14:26:24
+// @param chartTagId int
+// @param list []request.VarietyEdbReq
+// @param sysUserId int
+// @param sysUserName string
+// @return err error
+func SaveVarietyEdb(chartTagId int, list []request.VarietyEdbReq, sysUserId int, sysUserName string) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+
+	// 查找现在已经存在的品种和指标的关系
+	var items []*ChartTagVariety
+	sql := `SELECT * FROM chart_tag_variety WHERE chart_tag_id = ? `
+	_, err = o.Raw(sql, chartTagId).QueryRows(&items)
+	if err != nil {
+		return
+	}
+
+	hasMap := make(map[int]*ChartTagVariety)
+	existMap := make(map[int]*ChartTagVariety)
+	for _, v := range items {
+		hasMap[v.ChartVarietyId] = v
+		existMap[v.ChartVarietyId] = v
+	}
+
+	// 待添加的配置
+	addList := make([]*ChartTagVariety, 0)
+	for _, v := range list {
+		tmpChartTagVariety, ok := hasMap[v.ChartVarietyId]
+
+		// 找不到就插入
+		if !ok {
+			addList = append(addList, &ChartTagVariety{
+				Id:                        0,
+				ChartTagId:                chartTagId,
+				ChartVarietyId:            v.ChartVarietyId,
+				EdbInfoId:                 v.EdbInfoId,
+				LastUpdateSysUserId:       sysUserId,
+				LastUpdateSysUserRealName: sysUserName,
+				ModifyTime:                time.Now(),
+				CreateTime:                time.Now(),
+			})
+			continue
+		}
+
+		delete(existMap, v.ChartVarietyId)
+
+		// 找到了,如果指标不一致那就修改
+		if tmpChartTagVariety.EdbInfoId != v.EdbInfoId {
+			tmpChartTagVariety.EdbInfoId = v.EdbInfoId
+			tmpChartTagVariety.LastUpdateSysUserId = sysUserId
+			tmpChartTagVariety.LastUpdateSysUserRealName = sysUserName
+			tmpChartTagVariety.ModifyTime = time.Now()
+			_, err = o.Update(tmpChartTagVariety, "EdbInfoId", "LastUpdateSysUserId", "LastUpdateSysUserRealName", "ModifyTime")
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	// 删除不要了的
+	if len(existMap) > 0 {
+		idStrList := make([]string, 0)
+		for _, v := range existMap {
+			idStrList = append(idStrList, fmt.Sprint(v.Id))
+		}
+		removeIdStr := strings.Join(idStrList, `,`)
+		sql = fmt.Sprintf(` DELETE FROM chart_tag_variety WHERE id in (%s) `, removeIdStr)
+		_, err = o.Raw(sql).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 添加配置
+	if len(addList) > 0 {
+		_, err = o.InsertMulti(len(addList), addList)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+// GetCountByEdbInfoId
+// @Description: 根据指标id获取其关联的品种数量
+// @author: Roc
+// @datetime 2023-11-28 19:43:42
+// @param edbInfoId int
+// @return total int
+// @return err error
+func GetCountByEdbInfoId(edbInfoId int) (total int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT count(1) total FROM chart_tag_variety a 
+            INNER JOIN edb_info b ON a.edb_info_id=b.edb_info_id 
+            INNER JOIN chart_tag AS c ON a.chart_tag_id=c.chart_tag_id
+            WHERE a.edb_info_id = ?`
+	err = o.Raw(sql, edbInfoId).QueryRow(&total)
+
+	return
+}
+
+// GetChartTagVarietyListByTagIdList
+// @Description: 根据标签id列表获取所有绑定的品种列表
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @param chartTagId int
+// @param chartVarietyId int
+// @return items []*ChartVariety
+// @return err error
+func GetChartTagVarietyListByTagIdList(chartTagIdList []int) (items []*ChartTagVariety, err error) {
+	num := len(chartTagIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.* FROM chart_tag_variety a 
+         join chart_variety b on a.chart_variety_id=b.chart_variety_id WHERE chart_tag_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, chartTagIdList).QueryRows(&items)
+
+	return
+}

+ 121 - 0
models/data_manage/cross_variety/chart_variety.go

@@ -0,0 +1,121 @@
+package cross_variety
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ChartVariety
+// @Description: chart_variety 图表品种表
+type ChartVariety struct {
+	ChartVarietyId     int       `orm:"column(chart_variety_id);pk"`
+	ChartVarietyName   string    `description:"品种名称"`
+	ChartVarietyNameEn string    `description:"品种名称(英文)"`
+	SysUserId          int       `description:"创建人id"`
+	SysUserRealName    string    `description:"创建人姓名"`
+	ModifyTime         time.Time `description:"修改时间"`
+	CreateTime         time.Time `description:"创建时间"`
+}
+
+// GetVarietyById
+// @Description: 根据品种id获取品种详情
+// @author: Roc
+// @datetime 2023-11-21 14:55:31
+// @param id int
+// @return item *ChartVariety
+// @return err error
+func GetVarietyById(id int) (item *ChartVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety WHERE chart_variety_id = ?`
+	err = o.Raw(sql, id).QueryRow(&item)
+
+	return
+}
+
+// GetVarietyByName
+// @Description: 根据品种名称获取品种详情
+// @author: Roc
+// @datetime 2023-11-21 14:55:20
+// @param name string
+// @return item *ChartVariety
+// @return err error
+func GetVarietyByName(name string) (item *ChartVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety WHERE chart_variety_name = ?`
+	err = o.Raw(sql, name).QueryRow(&item)
+
+	return
+}
+
+// AddVariety
+// @Description: 添加品种
+// @author: Roc
+// @datetime 2023-11-21 14:52:56
+// @param item *ChartVariety
+// @return err error
+func AddVariety(item *ChartVariety) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	lastId, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+
+	item.ChartVarietyId = int(lastId)
+
+	return
+}
+
+// Update
+// @Description: 更新品种
+// @author: Roc
+// @receiver item
+// @datetime 2023-11-21 15:15:17
+// @param updateColList []string
+// @return err error
+func (item *ChartVariety) Update(updateColList []string) (err error) {
+	to := orm.NewOrmUsingDB("data")
+	_, err = to.Update(item, updateColList...)
+
+	return
+}
+
+// Delete 删除
+func (item *ChartVariety) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(item)
+	return
+}
+
+// GetVarietyList
+// @Description: 获取所有品种列表
+// @author: Roc
+// @datetime 2023-11-22 10:44:35
+// @return items []*ChartVariety
+// @return err error
+func GetVarietyList() (items []*ChartVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety WHERE 1 = 1 `
+	_, err = o.Raw(sql).QueryRows(&items)
+
+	return
+}
+
+// GetVarietyListByIdList
+// @Description: 根据ID列表获取品种列表
+// @author: Roc
+// @datetime 2023-11-23 17:56:39
+// @param idList []int
+// @return items []*ChartVariety
+// @return err error
+func GetVarietyListByIdList(idList []int) (items []*ChartVariety, err error) {
+	num := len(idList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety WHERE 1 = 1 AND chart_variety_id in (` + utils.GetOrmInReplace(num) + `)`
+	_, err = o.Raw(sql, idList).QueryRows(&items)
+
+	return
+}

+ 67 - 0
models/data_manage/cross_variety/chart_variety_mapping.go

@@ -0,0 +1,67 @@
+package cross_variety
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ChartVarietyMapping
+// @Description: 图表与品种的关系表
+type ChartVarietyMapping struct {
+	Id             int       `orm:"column(id);pk"`
+	ChartInfoId    int       `description:"图表id"`
+	ChartVarietyId int       `description:"品种id"`
+	ModifyTime     time.Time `description:"修改时间"`
+	CreateTime     time.Time `description:"创建时间"`
+}
+
+// GetChartVarietyMappingList
+// @Description: 获取图表与品种的关系列表表
+// @author: Roc
+// @datetime 2023-11-24 15:22:36
+// @param chartInfoId int
+// @return items []*ChartVarietyMapping
+// @return err error
+func GetChartVarietyMappingList(chartInfoId int) (items []*ChartVarietyMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety_mapping WHERE chart_info_id = ? `
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&items)
+	return
+}
+
+// GetCountChartByVarietyId
+// @Description: 根据品种id获取引用该标签的图表数量
+// @author: Roc
+// @datetime 2023-11-27 10:41:46
+// @param tagId int
+// @return total int64
+// @return err error
+func GetCountChartByVarietyId(varietyId int) (total int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT count(1) total FROM chart_info AS a JOIN
+    chart_variety_mapping AS b on a.chart_info_id = b.chart_info_id 
+    WHERE b.chart_variety_id = ? `
+	err = o.Raw(sql, varietyId).QueryRow(&total)
+
+	return
+}
+
+// GetChartVarietyMappingListByChartInfoIdList
+// @Description: 根据图表id列表获取图表与品种的关系列表
+// @author: Roc
+// @datetime 2023-11-24 15:22:36
+// @param chartInfoId int
+// @return items []*ChartVarietyMapping
+// @return err error
+func GetChartVarietyMappingListByChartInfoIdList(chartInfoIdList []int) (items []*ChartVarietyMapping, err error) {
+	num := len(chartInfoIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_variety_mapping WHERE chart_info_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, chartInfoIdList).QueryRows(&items)
+
+	return
+}

+ 80 - 0
models/data_manage/cross_variety/request/chart.go

@@ -0,0 +1,80 @@
+package request
+
+// ChartConfigReq
+// @Description: 跨品种分析的图表配置
+type ChartConfigReq struct {
+	TagX           int               `description:"X轴的标签ID"`
+	TagY           int               `description:"Y轴的标签ID"`
+	CalculateValue int               `description:"计算窗口"`
+	CalculateUnit  string            `description:"计算频度"`
+	DateConfigList []ChartConfigDate `description:"日期配置列表"`
+	VarietyList    []int             `description:"品种id列表"`
+}
+
+// ChartConfigDate
+// @Description: 跨品种分析的日期配置
+type ChartConfigDate struct {
+	DateType int `description:"日期类型,,1:最新日期;2:N天前"`
+	Num      int
+}
+
+// AddChartReq
+// @Description: 添加图表的请求
+type AddChartReq struct {
+	ChartName      string            `description:"图表名称"`
+	LeftMin        string            `description:"图表左侧最小值"`
+	LeftMax        string            `description:"图表左侧最大值"`
+	ChartImage     string            `description:"图表截图,复制的时候才用到" json:"-"`
+	TagX           int               `description:"X轴的标签ID"`
+	TagY           int               `description:"Y轴的标签ID"`
+	CalculateValue int               `description:"计算窗口"`
+	CalculateUnit  string            `description:"计算频度"`
+	DateConfigList []ChartConfigDate `description:"日期配置列表"`
+	VarietyList    []int
+}
+
+// EditChartReq
+// @Description: 编辑图表的请求
+type EditChartReq struct {
+	ChartInfoId    int               `description:"图表id"`
+	ChartName      string            `description:"图表名称"`
+	LeftMin        string            `description:"图表左侧最小值"`
+	LeftMax        string            `description:"图表左侧最大值"`
+	ChartImage     string            `description:"图表截图,复制的时候才用到" json:"-"`
+	TagX           int               `description:"X轴的标签ID"`
+	TagY           int               `description:"Y轴的标签ID"`
+	CalculateValue int               `description:"计算窗口"`
+	CalculateUnit  string            `description:"计算频度"`
+	DateConfigList []ChartConfigDate `description:"日期配置列表"`
+	VarietyList    []int
+}
+
+// CopyAddChartInfoReq
+// @Description: 复制并新增图表
+type CopyAddChartInfoReq struct {
+	ChartInfoId int    `description:"待复制的图表id"`
+	ChartName   string `description:"图表名称"`
+}
+
+// EditChartEnInfoReq
+// @Description: 编辑图表英文信息
+type EditChartEnInfoReq struct {
+	ChartInfoId int                `description:"图表ID"`
+	ChartNameEn string             `description:"英文图表名称"`
+	TagList     []TagNameEnReq     `description:"标签名称"`
+	VarietyList []VarietyNameEnReq `description:"标签名称"`
+}
+
+// TagNameEnReq
+// @Description: 标签英文名称修改
+type TagNameEnReq struct {
+	ChartTagId int    `json:"ChartTagId"`
+	TagNameEn  string `json:"TagNameEn"`
+}
+
+// VarietyNameEnReq
+// @Description: 品种英文名称修改
+type VarietyNameEnReq struct {
+	ChartVarietyId int    `json:"ChartVarietyId"`
+	VarietyNameEn  string `json:"VarietyNameEn"`
+}

+ 31 - 0
models/data_manage/cross_variety/request/tag.go

@@ -0,0 +1,31 @@
+package request
+
+// AddTagReq 添加标签请求
+type AddTagReq struct {
+	TagName string `description:"标签名称"`
+}
+
+// EditTagReq 编辑标签请求
+type EditTagReq struct {
+	ChartTagId int    `description:"标签id"`
+	TagName    string `description:"标签名称"`
+}
+
+// DelTagReq 删除标签请求
+type DelTagReq struct {
+	ChartTagId int `description:"标签id"`
+}
+
+// SaveTagVarietyEdbReq
+// @Description: 配置标签中的指标与品种的映射关系
+type SaveTagVarietyEdbReq struct {
+	ChartTagId int             `description:"标签id"`
+	VarietyEdb []VarietyEdbReq `description:"品种和指标的映射关系"`
+}
+
+// VarietyEdbReq
+// @Description: 品种和指标的映射关系
+type VarietyEdbReq struct {
+	ChartVarietyId int `description:"品种id"`
+	EdbInfoId      int `description:"指标id"`
+}

+ 17 - 0
models/data_manage/cross_variety/request/variety.go

@@ -0,0 +1,17 @@
+package request
+
+// AddVarietyReq 添加品种请求
+type AddVarietyReq struct {
+	VarietyName string `description:"品种名称"`
+}
+
+// EditVarietyReq 编辑品种请求
+type EditVarietyReq struct {
+	ChartVarietyId int    `description:"品种id"`
+	VarietyName    string `description:"品种名称"`
+}
+
+// DelVarietyReq 删除品种请求
+type DelVarietyReq struct {
+	ChartVarietyId int `description:"品种id"`
+}

+ 21 - 0
models/data_manage/cross_variety/response/chart.go

@@ -0,0 +1,21 @@
+package response
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/cross_variety"
+)
+
+// ChartPreviewResp
+// @Description: 图表预览返回
+type ChartPreviewResp struct {
+	EdbInfoList []*data_manage.ChartEdbInfoMapping
+	DataResp    interface{} `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
+}
+
+// ChartRelationResp
+// @Description: 图表关联配置返回
+type ChartRelationResp struct {
+	ChartInfo   *data_manage.ChartInfoView
+	TagList     []*cross_variety.ChartTag
+	VarietyList []*cross_variety.ChartVariety
+}

+ 26 - 0
models/data_manage/cross_variety/response/tag.go

@@ -0,0 +1,26 @@
+package response
+
+import (
+	"eta/eta_api/models/data_manage/cross_variety"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+// TagDeleteCheckResp 标签删除检测数据返回
+type TagDeleteCheckResp struct {
+	DeleteStatus int    `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:该标签已关联图表,不允许删除!"`
+	TipsMsg      string `description:"提示信息"`
+}
+
+// TagListResp
+// @Description: 标签列表数据
+type TagListResp struct {
+	List   []*cross_variety.ChartTagItem `description:"列表数据"`
+	Paging *paging.PagingItem
+}
+
+// VarietyEdbListResp
+// @Description: 品种与关系的数据返回
+type VarietyEdbListResp struct {
+	List   []*cross_variety.ChartTagVarietyItem `description:"列表数据"`
+	Paging *paging.PagingItem
+}

+ 19 - 0
models/data_manage/cross_variety/response/variety.go

@@ -0,0 +1,19 @@
+package response
+
+import (
+	"eta/eta_api/models/data_manage/cross_variety"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+// VarietyDeleteCheckResp 品种删除检测数据返回
+type VarietyDeleteCheckResp struct {
+	DeleteStatus int    `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:已关联图表的品种,不允许删除!"`
+	TipsMsg      string `description:"提示信息"`
+}
+
+// VarietyListResp
+// @Description: 品种列表数据
+type VarietyListResp struct {
+	List   []*cross_variety.ChartVariety `description:"列表数据"`
+	Paging *paging.PagingItem
+}

+ 2 - 2
models/data_manage/edb_data_baiinfo.go

@@ -25,7 +25,7 @@ func GetEdbDataBaiinfoMaxAndMinDate(edbCode string) (min_date, max_date string,
 }
 
 // 全部刷新有色数据
-func RefreshAllEdbDataByBaiinfo(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
+func RefreshAllEdbDataByBaiinfo(edbInfoId, source, subSource int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -46,7 +46,7 @@ func RefreshAllEdbDataByBaiinfo(edbInfoId, source int, edbCode, startDate, endDa
 
 	//获取已存在指标所有数据
 	existDataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)

+ 93 - 6
models/data_manage/edb_data_base.go

@@ -8,12 +8,21 @@ import (
 )
 
 // GetEdbDataTableName 指标数据->存储表
-func GetEdbDataTableName(source int) (tableName string) {
+func GetEdbDataTableName(source, subSource int) (tableName string) {
 	switch source {
 	case utils.DATA_SOURCE_THS:
 		tableName = "edb_data_ths"
+		if subSource == utils.DATA_SUB_SOURCE_DATE {
+			tableName = "edb_data_ths_ds"
+		} else {
+			tableName = "edb_data_ths"
+		}
 	case utils.DATA_SOURCE_WIND:
-		tableName = "edb_data_wind"
+		if subSource == utils.DATA_SUB_SOURCE_DATE {
+			tableName = "edb_data_wind_wsd"
+		} else {
+			tableName = "edb_data_wind"
+		}
 	case utils.DATA_SOURCE_PB, utils.DATA_SOURCE_PB_FINANCE: //彭博经济数据、彭博财务数据
 		tableName = "edb_data_pb"
 	case utils.DATA_SOURCE_CALCULATE:
@@ -202,12 +211,12 @@ type EdbDataBase struct {
 	DataTimestamp int64
 }
 
-func GetEdbDataAllByEdbCode(edbCode string, source, limit int) (items []*EdbInfoSearchData, err error) {
+func GetEdbDataAllByEdbCode(edbCode string, source, subSource, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCode)
 	o := orm.NewOrmUsingDB("data")
 
-	tableName := GetEdbDataTableName(source)
+	tableName := GetEdbDataTableName(source, subSource)
 	sql := ` SELECT * FROM %s WHERE edb_code=? ORDER BY data_time DESC`
 	if limit > 0 {
 		sql += `  LIMIT ?  `
@@ -218,11 +227,89 @@ func GetEdbDataAllByEdbCode(edbCode string, source, limit int) (items []*EdbInfo
 	return
 }
 
-func GetEdbDataBaseByCodeAndDate(source int, edbCode string, startDate string) (count int, err error) {
+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)
+	tableName := GetEdbDataTableName(source, subSource)
 	sql := ` SELECT COUNT(1) AS count FROM %s WHERE edb_code=? AND data_time=? `
 	sql = fmt.Sprintf(sql, tableName)
 	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
 	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)
+	o := orm.NewOrmUsingDB("data")
+
+	tableName := GetEdbDataTableNameAndSubSource(source, subSource)
+	sql := ` SELECT * FROM %s WHERE edb_code=? ORDER BY data_time DESC`
+	if limit > 0 {
+		sql += `  LIMIT ?  `
+		pars = append(pars, limit)
+	}
+	sql = fmt.Sprintf(sql, tableName)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+// GetEdbDataTableName 指标数据->存储表
+func GetEdbDataTableNameAndSubSource(source, subSource int) (tableName string) {
+	switch source {
+	case utils.DATA_SOURCE_WIND:
+		if subSource == utils.DATA_SUB_SOURCE_EDB {
+			tableName = "edb_data_wind"
+		} else {
+			tableName = "edb_data_wind_wsd"
+		}
+	case utils.DATA_SOURCE_THS:
+		if subSource == utils.DATA_SUB_SOURCE_EDB {
+			tableName = "edb_data_ths"
+		} else {
+			tableName = "edb_data_ths_ds"
+		}
+	default:
+		edbSource := EdbSourceIdMap[source]
+		if edbSource != nil {
+			tableName = edbSource.TableName
+		}
+	}
+	return
+}
+
+func GetEdbDataAllByEdbCodes(edbCodes []string, limit int) (items []*EdbInfoSearchData, err error) {
+	var pars []interface{}
+	pars = append(pars, edbCodes)
+	o := orm.NewOrmUsingDB("data")
+
+	sql := ` SELECT * FROM edb_data_ys WHERE edb_code IN (`+ utils.GetOrmInReplace(len(edbCodes)) +`) ORDER BY data_time DESC`
+	if limit > 0 {
+		sql += `  LIMIT ?  `
+		pars = append(pars, limit)
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}

+ 4 - 4
models/data_manage/edb_data_calculate.go

@@ -2,10 +2,10 @@ package data_manage
 
 import (
 	"errors"
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/yidane/formula"
-	"eta/eta_api/utils"
 	"strconv"
 	"strings"
 	"time"
@@ -50,7 +50,7 @@ func GetEdbDataCalculateByCodeAndDate(edbCode string, startDate string) (count i
 }
 
 // 刷新全部数据
-func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string) (err error) {
+func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source, subSource int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -79,7 +79,7 @@ func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode
 			pars = append(pars, endDate)
 		}
 		fmt.Println("v.Source:", v.Source)
-		dataList, err := GetEdbDataListAll(condition, pars, v.Source, 1)
+		dataList, err := GetEdbDataListAll(condition, pars, v.Source, v.SubSource, 1)
 		if err != nil {
 			return err
 		}
@@ -106,7 +106,7 @@ func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode
 
 	//获取指标所有数据
 	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)

+ 8 - 8
models/data_manage/edb_data_calculate_time_shift.go

@@ -2,10 +2,10 @@ package data_manage
 
 import (
 	"errors"
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/shopspring/decimal"
-	"eta/eta_api/utils"
 	"strconv"
 	"strings"
 	"time"
@@ -91,7 +91,7 @@ func AddCalculateTimeShift(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbIn
 		}
 	} else {
 		edbInfoId = req.EdbInfoId
-		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_TIME_SHIFT)
+		dataTableName := GetEdbDataTableName(utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SUB_SOURCE_EDB)
 		fmt.Println("dataTableName:" + dataTableName)
 		deleteSql := ` DELETE FROM %s WHERE edb_info_id=? `
 		deleteSql = fmt.Sprintf(deleteSql, dataTableName)
@@ -128,7 +128,7 @@ func AddCalculateTimeShift(req *EdbInfoCalculateBatchSaveReq, fromEdbInfo *EdbIn
 	} else {
 		pars = append(pars, fromEdbInfo.EdbInfoId)
 	}
-	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, 0)
+	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, fromEdbInfo.SubSource, 0)
 	if err != nil {
 		return edbInfoId, err
 	}
@@ -277,7 +277,7 @@ func EditCalculateTimeShift(req *EdbInfoCalculateBatchEditReq, fromEdbInfo *EdbI
 		condition += " AND edb_info_id=? "
 		pars = append(pars, req.FromEdbInfoId)
 		fmt.Println("EdbInfoId:", req.FromEdbInfoId)
-		dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, 0)
+		dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, fromEdbInfo.SubSource, 0)
 		if err != nil {
 			return edbInfoId, err
 		}
@@ -368,7 +368,7 @@ func RefreshCalculateTimeShift(edbInfoId, formulaInt, moveType int, fromEdbInfo
 	if moveType == 2 {
 		shiftDay = -shiftDay
 	}
-	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, 0)
+	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, fromEdbInfo.SubSource, 0)
 	if err != nil {
 		return err
 	}
@@ -427,7 +427,7 @@ func GetEdbInfoCalculateTimeShiftDetail(edbInfoId int) (item *EdbInfoCalculateTb
 }
 
 // 刷新所有变频数据
-func RefreshAllCalculateTimeShift(edbInfoId, source, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string) (err error) {
+func RefreshAllCalculateTimeShift(edbInfoId, source, subSource, formulaInt, moveType int, fromEdbInfo *EdbInfo, edbCode, startDate, endDate, moveFrequency string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -482,7 +482,7 @@ func RefreshAllCalculateTimeShift(edbInfoId, source, formulaInt, moveType int, f
 		shiftDay = -shiftDay
 	}
 
-	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, 0)
+	dataList, err := GetEdbDataListAll(condition, pars, fromEdbInfo.Source, fromEdbInfo.SubSource, 0)
 	if err != nil {
 		return err
 	}
@@ -495,7 +495,7 @@ func RefreshAllCalculateTimeShift(edbInfoId, source, formulaInt, moveType int, f
 	fmt.Println("source:", source)
 	//获取指标所有数据
 	existDataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	fmt.Println("dataTableName:", dataTableName)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)

+ 2 - 79
models/data_manage/edb_data_cffex.go

@@ -64,83 +64,6 @@ func GetEdbDataCffexMaxOrMinDate(edbCode string) (minDate, maxDate string, err e
 	return
 }
 
-func GetEdbDataByCffex(edbCode, suffix, startDate, endDate string) (searchItem *EdbInfoSearch, err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	searchItem = new(EdbInfoSearch)
-	searchItem.EdbCode = edbCode
-	cffexBaseDataAll, err := GetBaseFromCffexDataAllByIndexCode(edbCode, suffix)
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		return
-	}
-
-	var isAdd bool
-	addSql := ` INSERT INTO edb_data_cffex(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	dataList := make([]*EdbInfoSearchData, 0)
-	existMap := make(map[string]string)
-
-	for _, sv := range cffexBaseDataAll {
-		eDate := sv.DataTime
-		dataTime, err := time.Parse(utils.FormatDate, eDate)
-		if err != nil {
-			fmt.Println("time.Parse Err:" + eDate)
-			return nil, err
-		}
-		timestamp := dataTime.UnixNano() / 1e6
-		timeStr := fmt.Sprintf("%d", timestamp)
-		if _, ok := existMap[eDate]; !ok {
-			if suffix == "deal" {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.DealValue)
-			} else if suffix == "buy" {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.BuyValue)
-			} else {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.SoldValue)
-			}
-			isAdd = true
-		}
-		if suffix == "deal" {
-			existMap[eDate] = sv.DealValue
-		} else if suffix == "buy" {
-			existMap[eDate] = sv.BuyValue
-		} else {
-			existMap[eDate] = sv.SoldValue
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		utils.FileLog.Info("addSql:" + addSql)
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return searchItem, err
-		}
-	}
-	if err != nil {
-		_ = to.Rollback()
-	} else {
-		_ = to.Commit()
-	}
-	size := utils.EDB_DATA_LIMIT
-	dataList, err = GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_CFFEX, size)
-	if err != nil {
-		utils.FileLogData.Info("GetEdbDataCffexByCode Err:%s", err.Error())
-		return searchItem, err
-	}
-	minDate, maxDate, err := GetEdbDataCffexMaxOrMinDate(edbCode)
-	if err != nil {
-		return searchItem, err
-	}
-	searchItem.DataList = dataList
-	searchItem.StartDate = minDate
-	searchItem.EndDate = maxDate
-	if searchItem.DataList == nil {
-		searchItem.DataList = make([]*EdbInfoSearchData, 0)
-	}
-	return
-}
-
 // RefreshEdbDataByCffex 刷新中金所指标数据
 func RefreshEdbDataByCffex(edbInfoId int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -246,7 +169,7 @@ func RefreshEdbDataByCffex(edbInfoId int, edbCode, startDate, endDate string) (e
 }
 
 // RefreshAllEdbDataByCffex 全部刷新中金所
-func RefreshAllEdbDataByCffex(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
+func RefreshAllEdbDataByCffex(edbInfoId, source, subSource int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -297,7 +220,7 @@ func RefreshAllEdbDataByCffex(edbInfoId, source int, edbCode, startDate, endDate
 
 	//获取指标所有数据
 	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)

+ 2 - 2
models/data_manage/edb_data_coal.go

@@ -156,7 +156,7 @@ func RefreshEdbDataByCoal(edbInfoId int, edbCode, startDate, endDate string) (er
 }
 
 // RefreshAllEdbDataByCoal 全部刷新中金所
-func RefreshAllEdbDataByCoal(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
+func RefreshAllEdbDataByCoal(edbInfoId, source, subSource int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -205,7 +205,7 @@ func RefreshAllEdbDataByCoal(edbInfoId, source int, edbCode, startDate, endDate
 
 	//获取指标所有数据
 	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)

+ 0 - 348
models/data_manage/edb_data_dl.go

@@ -1,11 +1,8 @@
 package data_manage
 
 import (
-	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
-	"strconv"
-	"strings"
 	"time"
 )
 
@@ -64,305 +61,6 @@ func GetEdbDataDlMaxOrMinDate(edbCode string) (minDate, maxDate string, err erro
 	return
 }
 
-func GetEdbDataByDl(edbCode, suffix, startDate, endDate string) (searchItem *EdbInfoSearch, err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	searchItem = new(EdbInfoSearch)
-	searchItem.EdbCode = edbCode
-	dlBaseDataAll, err := GetBaseFromDalianDataAllByIndexCode(edbCode, suffix)
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		return
-	}
-
-	var isAdd bool
-	addSql := ` INSERT INTO edb_data_dl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	dataList := make([]*EdbInfoSearchData, 0)
-	existMap := make(map[string]string)
-
-	for _, sv := range dlBaseDataAll {
-		eDate := sv.DataTime
-		dataTime, err := time.Parse(utils.FormatDate, eDate)
-		if err != nil {
-			fmt.Println("time.Parse Err:" + eDate)
-			return nil, err
-		}
-		timestamp := dataTime.UnixNano() / 1e6
-		timeStr := fmt.Sprintf("%d", timestamp)
-		if _, ok := existMap[eDate]; !ok {
-			if suffix == "deal" {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.DealValue)
-			} else if suffix == "buy" {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.BuyValue)
-			} else {
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.SoldValue)
-			}
-			isAdd = true
-		}
-		if suffix == "deal" {
-			existMap[eDate] = sv.DealValue
-		} else if suffix == "buy" {
-			existMap[eDate] = sv.BuyValue
-		} else {
-			existMap[eDate] = sv.SoldValue
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		utils.FileLog.Info("addSql:" + addSql)
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return searchItem, err
-		}
-	}
-	if err != nil {
-		_ = to.Rollback()
-	} else {
-		_ = to.Commit()
-	}
-
-	size := utils.EDB_DATA_LIMIT
-	dataList, err = GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_DL, size)
-	if err != nil {
-		utils.FileLogData.Info("GetEdbDataDlByCode Err:%s", err.Error())
-		return searchItem, err
-	}
-	minDate, maxDate, err := GetEdbDataDlMaxOrMinDate(edbCode)
-	if err != nil {
-		return searchItem, err
-	}
-	searchItem.DataList = dataList
-	searchItem.StartDate = minDate
-	searchItem.EndDate = maxDate
-	if searchItem.DataList == nil {
-		searchItem.DataList = make([]*EdbInfoSearchData, 0)
-	}
-	return
-}
-
-// RefreshEdbDataByDl 刷新大商所指标数据
-func RefreshEdbDataByDl(edbInfoId int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-	if err != nil {
-		return
-	}
-	var suffix string
-	if strings.Contains(edbCode, "deal") {
-		suffix = "deal"
-	} else if strings.Contains(edbCode, "buy") {
-		suffix = "buy"
-	} else if strings.Contains(edbCode, "sold") {
-		suffix = "sold"
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		if suffix == "deal" {
-			condition += " AND deal_code=? "
-		} else if suffix == "buy" {
-			condition += " AND buy_code=? "
-		} else {
-			condition += " AND sold_code=? "
-		}
-		pars = append(pars, edbCode)
-	}
-
-	if startDate != "" {
-		condition += " AND data_time>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND data_time<=? "
-		pars = append(pars, endDate)
-	}
-
-	glDataList, err := GetDlDataByTradeCode(condition, pars)
-
-	addSql := ` INSERT INTO edb_data_dl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range glDataList {
-		var value string
-		if suffix == "deal" {
-			value = v.DealValue
-		} else if suffix == "buy" {
-			value = v.BuyValue
-		} else {
-			value = v.SoldValue
-		}
-		item := v
-		itemValue := value
-		if _, ok := existMap[v.DataTime]; !ok {
-			count, err := GetEdbDataDlByCodeAndDate(edbCode, v.DataTime)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				return err
-			}
-			if count <= 0 {
-				eDate := item.DataTime
-				sValue := itemValue
-				if sValue != "" {
-					dataTime, err := time.Parse(utils.FormatDate, eDate)
-					if err != nil {
-						return err
-					}
-					timestamp := dataTime.UnixNano() / 1e6
-					timeStr := fmt.Sprintf("%d", timestamp)
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, sValue)
-					isAdd = true
-				}
-			} else {
-				err = ModifyEdbDataDl(int64(edbInfoId), v.DataTime, value)
-				if err != nil {
-					return err
-				}
-			}
-		}
-		existMap[v.DataTime] = value
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// RefreshAllEdbDataByDl 全部刷新大商所
-func RefreshAllEdbDataByDl(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-	var suffix string
-	if strings.Contains(edbCode, "deal") {
-		suffix = "deal"
-	} else if strings.Contains(edbCode, "buy") {
-		suffix = "buy"
-	} else if strings.Contains(edbCode, "sold") {
-		suffix = "sold"
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		if suffix == "deal" {
-			condition += " AND deal_code=? "
-		} else if suffix == "buy" {
-			condition += " AND buy_code=? "
-		} else {
-			condition += " AND sold_code=? "
-		}
-		pars = append(pars, edbCode)
-	}
-
-	if startDate != "" {
-		condition += " AND data_time>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND data_time<=? "
-		pars = append(pars, endDate)
-	}
-
-	glDataList, err := GetDlDataByTradeCode(condition, pars)
-
-	//获取指标所有数据
-	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
-	sql := `SELECT * FROM %s WHERE edb_info_id=? `
-	sql = fmt.Sprintf(sql, dataTableName)
-	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)
-	if err != nil {
-		return err
-	}
-	dataMap := make(map[string]string)
-	for _, v := range dataList {
-		dataMap[v.DataTime] = v.Value
-	}
-
-	addSql := ` INSERT INTO edb_data_dl(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range glDataList {
-		var value string
-		if suffix == "deal" {
-			value = v.DealValue
-		} else if suffix == "buy" {
-			value = v.BuyValue
-		} else {
-			value = v.SoldValue
-		}
-		item := v
-		itemValue := value
-		if _, ok := existMap[v.DataTime]; !ok {
-			eDate := item.DataTime
-			sValue := itemValue
-			if sValue != "" {
-				dataTime, err := time.Parse(utils.FormatDate, eDate)
-				if err != nil {
-					return err
-				}
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				saveValue := sValue
-
-				if existVal, ok := dataMap[eDate]; !ok {
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, saveValue)
-					isAdd = true
-				} else {
-					if existVal != saveValue {
-						sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-						sql = fmt.Sprintf(sql, dataTableName)
-						_, err = to.Raw(sql, sValue, edbInfoId, eDate).Exec()
-						if err != nil {
-							return err
-						}
-					}
-				}
-			}
-		}
-		existMap[v.DataTime] = v.DataTime
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
 // GetBaseInfoFromDalianByIndexCode 获取指标信息
 func GetBaseInfoFromDalianByIndexCode(indexCode, suffix string) (list []*BaseInfoFromDl, err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -371,49 +69,3 @@ func GetBaseInfoFromDalianByIndexCode(indexCode, suffix string) (list []*BaseInf
 	_, err = o.Raw(sql, indexCode).QueryRows(&list)
 	return
 }
-
-func GetDlDataByTradeCode(condition string, pars []interface{}) (item []*BaseFromDlDataSimple, err error) {
-	sql := ` SELECT * FROM base_from_trade_dalian_index WHERE 1=1 `
-	o := orm.NewOrmUsingDB("data")
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY data_time DESC `
-	_, err = o.Raw(sql, pars).QueryRows(&item)
-	return
-}
-
-func AddEdbDataDlBySql(sqlStr string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sqlStr).Exec()
-	return
-}
-
-func GetEdbDataDlByCode(edbCode string) (items []*EdbInfoSearchData, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_data_dl WHERE edb_code=? ORDER BY data_time DESC LIMIT ? `
-	_, err = o.Raw(sql, edbCode, utils.EDB_DATA_LIMIT).QueryRows(&items)
-	return
-}
-
-func GetBaseFromDalianDataAllByIndexCode(indexCode, suffix string) (list []*BaseFromTradeDalianIndex, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT * FROM base_from_trade_dalian_index WHERE %s_code=? `
-	sql = fmt.Sprintf(sql, suffix)
-	_, err = o.Raw(sql, indexCode).QueryRows(&list)
-	return
-}
-
-func GetEdbDataDlByCodeAndDate(edbCode string, startDate string) (count int, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT COUNT(1) AS count FROM edb_data_dl WHERE edb_code=? AND data_time=? `
-	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
-	return
-}
-
-func ModifyEdbDataDl(edbInfoId int64, dataTime, value string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE edb_data_dl SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-	_, err = o.Raw(sql, value, edbInfoId, dataTime).Exec()
-	return
-}

+ 0 - 469
models/data_manage/edb_data_gie.go

@@ -3,9 +3,6 @@ package data_manage
 import (
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
-	"eta/eta_api/utils"
-	"strconv"
-	"strings"
 	"time"
 )
 
@@ -21,401 +18,6 @@ func GetEdbDataGieMaxOrMinDate(edbCode string) (minDate, maxDate string, err err
 	return
 }
 
-func GetEdbDataByGie(edbCode, suffix, startDate, endDate string) (searchItem *EdbInfoSearch, err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	searchItem = new(EdbInfoSearch)
-	searchItem.EdbCode = edbCode
-	eicBaseDataAll, err := GetBaseFromEicDataAllByIndexCode(edbCode, suffix)
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		fmt.Println("GetBaseFromEicDataAllByIndexCode err:", err)
-		return
-	}
-
-	var isAdd bool
-	addSql := ` INSERT INTO edb_data_gie(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	dataList := make([]*EdbInfoSearchData, 0)
-	existMap := make(map[string]string)
-
-	for _, sv := range eicBaseDataAll {
-		eDate := sv.GasDayStartedOn
-		dataTime, err := time.Parse(utils.FormatDate, eDate)
-		if err != nil {
-			fmt.Println("time.Parse Err:" + eDate)
-			return nil, err
-		}
-		timestamp := dataTime.UnixNano() / 1e6
-		timeStr := fmt.Sprintf("%d", timestamp)
-		//var name string
-		if _, ok := existMap[eDate]; !ok {
-			if suffix == "GS" {
-				//name = "gas_in_storage"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.GasInStorage)
-				existMap[eDate] = sv.GasInStorage
-			} else if suffix == "F" {
-				//name = "full"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.Full)
-				existMap[eDate] = sv.Full
-			} else if suffix == "T" {
-				//name = "trend"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.Trend)
-				existMap[eDate] = sv.Trend
-			} else if suffix == "In" {
-				//name = "injection"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.Injection)
-				existMap[eDate] = sv.Injection
-			} else if suffix == "Out" {
-				//name = "withdrawal"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.Withdrawal)
-				existMap[eDate] = sv.Withdrawal
-			} else if suffix == "WGV" {
-				//name = "working_gas_volume"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.WorkingGasVolume)
-				existMap[eDate] = sv.WorkingGasVolume
-			} else if suffix == "IC" {
-				//name = "injection_capacity"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.InjectionCapacity)
-				existMap[eDate] = sv.InjectionCapacity
-			} else if suffix == "WC" {
-				//name = "withdrawal_capacity"
-				addSql += GetAddSql("0", edbCode, eDate, timeStr, sv.WithdrawalCapacity)
-				existMap[eDate] = sv.WithdrawalCapacity
-			}
-			isAdd = true
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		utils.FileLog.Info("addSql:" + addSql)
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			fmt.Println("addSql err:", err)
-			return searchItem, err
-		}
-	}
-	if err != nil {
-		_ = to.Rollback()
-	} else {
-		_ = to.Commit()
-	}
-	size := utils.EDB_DATA_LIMIT
-	dataList, err = GetEdbDataAllByEdbCode(edbCode, utils.DATA_SOURCE_GIE, size)
-	if err != nil {
-		utils.FileLogData.Info("GetEdbDataGieByCode Err:%s", err.Error())
-		return searchItem, err
-	}
-	minDate, maxDate, err := GetEdbDataGieMaxOrMinDate(edbCode)
-	if err != nil {
-		return searchItem, err
-	}
-	searchItem.DataList = dataList
-	searchItem.StartDate = minDate
-	searchItem.EndDate = maxDate
-	if searchItem.DataList == nil {
-		searchItem.DataList = make([]*EdbInfoSearchData, 0)
-	}
-	return
-}
-
-// RefreshEdbDataByGie 刷新欧洲天然气指标数据
-func RefreshEdbDataByGie(edbInfoId int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-	if err != nil {
-		fmt.Println("refresh err:", err)
-		return
-	}
-	var suffix string
-	l := len(edbCode)
-	if strings.Contains(edbCode[l-2:], "GS") {
-		suffix = "GS"
-	} else if strings.Contains(edbCode[l-2:], "CF") {
-		suffix = "CF"
-	} else if strings.Contains(edbCode[l-1:], "T") {
-		suffix = "T"
-	} else if strings.Contains(edbCode[l-2:], "In") {
-		suffix = "In"
-	} else if strings.Contains(edbCode[l-3:], "Out") {
-		suffix = "Out"
-	} else if strings.Contains(edbCode[l-3:], "WGV") {
-		suffix = "WGV"
-	} else if strings.Contains(edbCode[l-2:], "IC") {
-		suffix = "IC"
-	} else if strings.Contains(edbCode[l-2:], "WC") {
-		suffix = "WC"
-	} else if strings.Contains(edbCode[l-1:], "F") {
-		suffix = "F"
-	} else if strings.Contains(edbCode[l-1:], "C") {
-		suffix = "C"
-	} else {
-		suffix = ""
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND eic_code=? "
-		pars = append(pars, edbCode[:l-len(suffix)])
-	}
-
-	if startDate != "" {
-		condition += " AND gas_day_started_on>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND gas_day_started_on<=? "
-		pars = append(pars, endDate)
-	}
-
-	eicDataList, err := GetGieDataByTradeCodeV2(condition, pars)
-	fmt.Println("eicDataList", len(eicDataList))
-	addSql := ` INSERT INTO edb_data_gie(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range eicDataList {
-		var value string
-		if suffix == "GS" {
-			value = v.GasInStorage
-		} else if suffix == "C" {
-			value = v.Consumption
-		} else if suffix == "CF" {
-			value = v.ConsumptionFull
-		} else if suffix == "F" {
-			value = v.Full
-		} else if suffix == "T" {
-			value = v.Trend
-		} else if suffix == "In" {
-			value = v.Injection
-		} else if suffix == "Out" {
-			value = v.Withdrawal
-		} else if suffix == "WGV" {
-			value = v.WorkingGasVolume
-		} else if suffix == "IC" {
-			value = v.InjectionCapacity
-		} else if suffix == "WC" {
-			value = v.WithdrawalCapacity
-		}
-		item := v
-		itemValue := value
-		if _, ok := existMap[v.GasDayStart]; !ok {
-			count, err := GetEdbDataGieByCodeAndDate(edbCode, v.GasDayStart)
-			if err != nil && err.Error() != utils.ErrNoRow() {
-				return err
-			}
-			if count <= 0 {
-				eDate := item.GasDayStart
-				sValue := itemValue
-				if sValue != "" {
-					dataTime, err := time.Parse(utils.FormatDate, eDate)
-					if err != nil {
-						return err
-					}
-					timestamp := dataTime.UnixNano() / 1e6
-					timeStr := fmt.Sprintf("%d", timestamp)
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, sValue)
-					isAdd = true
-				}
-			} else {
-				err = ModifyEdbDataGie(int64(edbInfoId), v.GasDayStart, value)
-				if err != nil {
-					return err
-				}
-			}
-		}
-		existMap[v.GasDayStart] = value
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// RefreshAllEdbDataByGie 全部刷新欧洲天然气
-func RefreshAllEdbDataByGie(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-	if err != nil {
-		return
-	}
-	var suffix string
-	l := len(edbCode)
-	if strings.Contains(edbCode[l-2:], "GS") {
-		suffix = "GS"
-	} else if strings.Contains(edbCode[l-2:], "CF") {
-		suffix = "CF"
-	} else if strings.Contains(edbCode[l-1:], "T") {
-		suffix = "T"
-	} else if strings.Contains(edbCode[l-2:], "In") {
-		suffix = "In"
-	} else if strings.Contains(edbCode[l-3:], "Out") {
-		suffix = "Out"
-	} else if strings.Contains(edbCode[l-3:], "WGV") {
-		suffix = "WGV"
-	} else if strings.Contains(edbCode[l-2:], "IC") {
-		suffix = "IC"
-	} else if strings.Contains(edbCode[l-2:], "WC") {
-		suffix = "WC"
-	} else if strings.Contains(edbCode[l-1:], "F") {
-		suffix = "F"
-	} else if strings.Contains(edbCode[l-1:], "C") {
-		suffix = "C"
-	} else {
-		suffix = ""
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND eic_code=? "
-		pars = append(pars, edbCode[:l-len(suffix)])
-	}
-
-	if startDate != "" {
-		condition += " AND gas_day_start>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND gas_day_start<=? "
-		pars = append(pars, endDate)
-	}
-
-	eicDataList, err := GetGieDataByTradeCodeV2(condition, pars)
-	fmt.Println("all eicDataList", len(eicDataList))
-	//获取指标所有数据
-	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
-	sql := `SELECT * FROM %s WHERE edb_info_id=? `
-	sql = fmt.Sprintf(sql, dataTableName)
-	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)
-	if err != nil {
-		return err
-	}
-	dataMap := make(map[string]string)
-	for _, v := range dataList {
-		dataMap[v.DataTime] = v.Value
-	}
-
-	addSql := ` INSERT INTO edb_data_gie(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	existMap := make(map[string]string)
-	for _, v := range eicDataList {
-		var value string
-		if suffix == "GS" {
-			value = v.GasInStorage
-		} else if suffix == "C" {
-			value = v.Consumption
-		} else if suffix == "CF" {
-			value = v.ConsumptionFull
-		} else if suffix == "F" {
-			value = v.Full
-		} else if suffix == "T" {
-			value = v.Trend
-		} else if suffix == "In" {
-			value = v.Injection
-		} else if suffix == "Out" {
-			value = v.Withdrawal
-		} else if suffix == "WGV" {
-			value = v.WorkingGasVolume
-		} else if suffix == "IC" {
-			value = v.InjectionCapacity
-		} else if suffix == "WC" {
-			value = v.WithdrawalCapacity
-		}
-		item := v
-		itemValue := value
-		if _, ok := existMap[v.GasDayStart]; !ok {
-			eDate := item.GasDayStart
-			sValue := itemValue
-			if sValue != "" {
-				dataTime, err := time.Parse(utils.FormatDate, eDate)
-				if err != nil {
-					return err
-				}
-				timestamp := dataTime.UnixNano() / 1e6
-				timeStr := fmt.Sprintf("%d", timestamp)
-				saveValue := sValue
-
-				if existVal, ok := dataMap[eDate]; !ok {
-					addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, saveValue)
-					isAdd = true
-				} else {
-					if existVal != saveValue {
-						sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-						sql = fmt.Sprintf(sql, dataTableName)
-						_, err = to.Raw(sql, sValue, edbInfoId, eDate).Exec()
-						if err != nil {
-							return err
-						}
-					}
-				}
-			}
-		}
-		existMap[v.GasDayStart] = v.GasDayStart
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// GetBaseInfoFromEicByIndexCode 获取指标信息
-func GetBaseInfoFromEicByIndexCode(indexCode, suffix string) (list []*BaseFromTradeEicIndex, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT * FROM base_from_trade_eic_index WHERE %s_code=? `
-	sql = fmt.Sprintf(sql, suffix)
-	_, err = o.Raw(sql, indexCode).QueryRows(&list)
-	return
-}
-
-func GetGieDataByTradeCode(condition string, pars []interface{}) (item []*BaseFromTradeEicIndex, err error) {
-	sql := ` SELECT * FROM base_from_trade_eic_index WHERE 1=1 `
-	o := orm.NewOrmUsingDB("data")
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY gas_day_started_on DESC `
-	fmt.Println(sql, pars)
-	_, err = o.Raw(sql, pars).QueryRows(&item)
-	return
-}
-
 type EicIndexV2 struct {
 	BaseFromEicIndexId     int `orm:"column(base_from_eic_index_id);pk"`
 	Type                   string
@@ -450,63 +52,6 @@ type EicIndexV2 struct {
 	Children               []BaseFromTradeEicIndexV2
 }
 
-func GetGieDataByTradeCodeV2(condition string, pars []interface{}) (item []*EicIndexV2, err error) {
-	sql := ` SELECT * FROM base_from_trade_eic_index_v2 WHERE 1=1 `
-	o := orm.NewOrmUsingDB("data")
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY gas_day_start DESC `
-	fmt.Println(sql, pars)
-	_, err = o.Raw(sql, pars).QueryRows(&item)
-	return
-}
-
-func AddEdbDataGieBySql(sqlStr string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sqlStr).Exec()
-	return
-}
-
-func GetEdbDataGieByCode(edbCode string) (items []*EdbInfoSearchData, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_data_gie WHERE edb_code=? ORDER BY data_time DESC LIMIT ? `
-	_, err = o.Raw(sql, edbCode, utils.EDB_DATA_LIMIT).QueryRows(&items)
-	return
-}
-
-func GetBaseFromEicDataAllByIndexCode(indexCode, suffix string) (list []*BaseFromTradeEicIndex, err error) {
-	o := orm.NewOrmUsingDB("data")
-	var name string
-	if suffix == "" {
-		name = "eic_code"
-	} else if suffix == "GS" {
-		name = "gas_in_storage_code"
-	} else if suffix == "C" {
-		name = "consumption_code"
-	} else if suffix == "CF" {
-		name = "consumption_full_code"
-	} else if suffix == "F" {
-		name = "full_code"
-	} else if suffix == "T" {
-		name = "trend_code"
-	} else if suffix == "In" {
-		name = "injection_code"
-	} else if suffix == "Out" {
-		name = "withdrawal_code"
-	} else if suffix == "WGV" {
-		name = "working_gas_volume_code"
-	} else if suffix == "IC" {
-		name = "injection_capacity_code"
-	} else if suffix == "WC" {
-		name = "withdrawal_capacity_code"
-	}
-	sql := `SELECT * FROM base_from_trade_eic_index_v2 WHERE %s=? `
-	sql = fmt.Sprintf(sql, name)
-	_, err = o.Raw(sql, indexCode).QueryRows(&list)
-	return
-}
-
 func GetBaseFromEicDataAllByIndexCodeV2(indexCode, suffix string) (list []*BaseFromTradeEicIndexV2, err error) {
 	o := orm.NewOrmUsingDB("data")
 	var name string
@@ -538,17 +83,3 @@ func GetBaseFromEicDataAllByIndexCodeV2(indexCode, suffix string) (list []*BaseF
 	_, err = o.Raw(sql, indexCode).QueryRows(&list)
 	return
 }
-
-func GetEdbDataGieByCodeAndDate(edbCode string, startDate string) (count int, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT COUNT(1) AS count FROM edb_data_gie WHERE edb_code=? AND data_time=? `
-	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
-	return
-}
-
-func ModifyEdbDataGie(edbInfoId int64, dataTime, value string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE edb_data_gie SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-	_, err = o.Raw(sql, value, edbInfoId, dataTime).Exec()
-	return
-}

+ 2 - 2
models/data_manage/edb_data_gl.go

@@ -235,7 +235,7 @@ func RefreshEdbDataByGl(edbInfoId int, edbCode, startDate, endDate string) (err
 }
 
 // 全部刷新隆众数据
-func RefreshAllEdbDataByGl(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
+func RefreshAllEdbDataByGl(edbInfoId, source, subSource int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -276,7 +276,7 @@ func RefreshAllEdbDataByGl(edbInfoId, source int, edbCode, startDate, endDate st
 
 	//获取指标所有数据
 	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)

+ 1 - 1
models/data_manage/edb_data_insert_config.go

@@ -43,7 +43,7 @@ func GetEdbDataInsertConfigByEdbIdList(edbInfoIdList []int) (items []*EdbDataIns
 func CreateEdbDataInsertConfigAndData(edbInfo *EdbInfo, date time.Time, value float64) (err error, errMsg string, isSendEmail bool) {
 	isSendEmail = true
 
-	tableName := GetEdbDataTableName(edbInfo.Source)
+	tableName := GetEdbDataTableName(edbInfo.Source, edbInfo.SubSource)
 	if tableName == `` {
 		err = errors.New("找不到该指标的数据表")
 		return

+ 2 - 2
models/data_manage/edb_data_lz.go

@@ -234,7 +234,7 @@ func RefreshEdbDataByLz(edbInfoId int, edbCode, startDate, endDate string) (err
 }
 
 // 全部刷新隆众数据
-func RefreshAllEdbDataByLz(edbInfoId, source int, edbCode, startDate, endDate string) (err error) {
+func RefreshAllEdbDataByLz(edbInfoId, source, subSource int, edbCode, startDate, endDate string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	to, err := o.Begin()
 	if err != nil {
@@ -275,7 +275,7 @@ func RefreshAllEdbDataByLz(edbInfoId, source int, edbCode, startDate, endDate st
 
 	//获取指标所有数据
 	dataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
+	dataTableName := GetEdbDataTableName(source, subSource)
 	sql := `SELECT * FROM %s WHERE edb_info_id=? `
 	sql = fmt.Sprintf(sql, dataTableName)
 	_, err = to.Raw(sql, edbInfoId).QueryRows(&dataList)

+ 0 - 303
models/data_manage/edb_data_manual.go

@@ -1,20 +1,10 @@
 package data_manage
 
 import (
-	"eta/eta_api/utils"
-	"fmt"
 	"github.com/beego/beego/v2/client/orm"
-	"strconv"
-	"strings"
 	"time"
 )
 
-func AddEdbDataManualBySql(sqlStr string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sqlStr).Exec()
-	return
-}
-
 func GetEdbDataManualMaxOrMinDate(edbCode string) (min_date, max_date string, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT MIN(data_time) AS min_date,MAX(data_time) AS max_date FROM edb_data_manual WHERE edb_code=? `
@@ -28,296 +18,3 @@ type ManualEdbdata struct {
 	Close      string    `orm:"column(CLOSE)" description:"值"`
 	ModifyTime time.Time `orm:"column(modify_time)" description:"修改时间"`
 }
-
-func GetEdbdataManualByTradeCode(condition string, pars []interface{}) (item []*ManualEdbdata, err error) {
-	sql := ` SELECT  * FROM edbdata WHERE 1=1 `
-	o := orm.NewOrmUsingDB("edb")
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY DT DESC `
-	_, err = o.Raw(sql, pars).QueryRows(&item)
-	return
-}
-
-func GetEdbDataManualByCode(edbCode string, size int) (items []*EdbInfoSearchData, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_data_manual WHERE edb_code=? ORDER BY data_time DESC LIMIT ? `
-	_, err = o.Raw(sql, edbCode, size).QueryRows(&items)
-	return
-}
-
-func GetEdbDataByManual(edbCode, startDate, endDate string) (searchItem *EdbInfoSearch, err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND TRADE_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	manualDataList, err := GetEdbdataManualByTradeCode(condition, pars)
-	if err != nil {
-		return
-	}
-	searchItem = new(EdbInfoSearch)
-	searchItem.EdbCode = edbCode
-	dataLen := len(manualDataList)
-
-	if dataLen > 0 {
-		var isAdd bool
-		addSql := ` INSERT INTO edb_data_manual(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-		nowStr := time.Now().Format(utils.FormatDateTime)
-		dataList := make([]*EdbInfoSearchData, 0)
-		for i := 0; i < dataLen; i++ {
-			item := manualDataList[i]
-			eDate := item.Dt
-			sValue := item.Close
-			dataTime, err := time.Parse(utils.FormatDate, eDate)
-			if err != nil {
-				return nil, err
-			}
-			timestamp := dataTime.UnixNano() / 1e6
-			timeStr := fmt.Sprintf("%d", timestamp)
-			addSql += "("
-			addSql += "0," + "'" + edbCode + "'" + "," + "'" + eDate + "'" + "," + sValue + "," + "'" + nowStr + "'" +
-				"," + "'" + nowStr + "'" + "," + "0" + "," + "'" + timeStr + "'"
-			addSql += "),"
-			isAdd = true
-		}
-		if isAdd {
-			addSql = strings.TrimRight(addSql, ",")
-			err = AddEdbDataManualBySql(addSql)
-			if err != nil {
-				utils.FileLogData.Info("AddEdbDataThsBySql Err:%s", err.Error())
-				return
-			}
-		}
-
-		size := utils.EDB_DATA_LIMIT
-		dataList, err := GetEdbDataManualByCode(edbCode, size)
-		if err != nil {
-			utils.FileLogData.Info("GetEdbDataThsByCode Err:%s", err.Error())
-			return searchItem, err
-		}
-		minDate, maxDate, err := GetEdbDataManualMaxOrMinDate(edbCode)
-		if err != nil {
-			return searchItem, err
-		}
-		searchItem.DataList = dataList
-		searchItem.StartDate = minDate
-		searchItem.EndDate = maxDate
-	}
-	if searchItem.DataList == nil {
-		searchItem.DataList = make([]*EdbInfoSearchData, 0)
-	}
-	return
-}
-
-func GetEdbDataManualByCodeAndDate(edbCode string, startDate string) (count int, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT COUNT(1) AS count FROM edb_data_manual WHERE edb_code=? AND data_time=? `
-	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
-	return
-}
-
-func ModifyEdbDataManual(edbInfoId int64, dataTime, value string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE edb_data_manual SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-	_, err = o.Raw(sql, value, edbInfoId, dataTime).Exec()
-	return
-}
-
-// 刷新手工指标数据
-func RefreshEdbDataByManual(edbInfoId int, edbCode, startDate, endDate string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	if err != nil {
-		return
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND TRADE_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	if startDate != "" {
-		condition += " AND DT>=? "
-		pars = append(pars, startDate)
-	}
-
-	if endDate != "" {
-		condition += " AND DT<=? "
-		pars = append(pars, endDate)
-	}
-
-	manualDataList, err := GetEdbdataManualByTradeCode(condition, pars)
-
-	addSql := ` INSERT INTO edb_data_manual(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	for _, v := range manualDataList {
-		item := v
-		count, err := GetEdbDataManualByCodeAndDate(v.TradeCode, v.Dt)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			return err
-		}
-		if count <= 0 {
-			nowStr := time.Now().Format(utils.FormatDateTime)
-			eDate := item.Dt
-			sValue := item.Close
-			dataTime, err := time.Parse(utils.FormatDate, eDate)
-			if err != nil {
-				return err
-			}
-			timestamp := dataTime.UnixNano() / 1e6
-			timeStr := fmt.Sprintf("%d", timestamp)
-			addSql += "("
-			addSql += edbInfoIdStr + "," + "'" + edbCode + "'" + "," + "'" + eDate + "'" + "," + sValue + "," + "'" + nowStr + "'" +
-				"," + "'" + nowStr + "'" + "," + "1" + "," + "'" + timeStr + "'"
-			addSql += "),"
-			isAdd = true
-		} else {
-			err = ModifyEdbDataManual(int64(edbInfoId), v.Dt, v.Close)
-			if err != nil {
-				return err
-			}
-		}
-	}
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			return err
-		}
-	}
-	return
-}
-
-// 刷新手工指标数据
-func RefreshAllEdbDataByManual(edbInfoId, source int, edbCode string) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	if err != nil {
-		return
-	}
-	edbInfoIdStr := strconv.Itoa(edbInfoId)
-	//计算数据
-	var condition string
-	var pars []interface{}
-
-	if edbCode != "" {
-		condition += " AND TRADE_CODE=? "
-		pars = append(pars, edbCode)
-	}
-
-	manualDataList, err := GetEdbdataManualByTradeCode(condition, pars)
-	//获取指标所有数据
-	existDataList := make([]*EdbDataBase, 0)
-	dataTableName := GetEdbDataTableName(source)
-	sql := `SELECT * FROM %s WHERE edb_info_id=? `
-	sql = fmt.Sprintf(sql, dataTableName)
-	_, err = to.Raw(sql, edbInfoId).QueryRows(&existDataList)
-	if err != nil {
-		return err
-	}
-	existDataMap := make(map[string]*EdbDataBase)
-	for _, v := range existDataList {
-		existDataMap[v.DataTime] = v
-	}
-
-	addSql := ` INSERT INTO edb_data_manual(edb_info_id,edb_code,data_time,value,create_time,modify_time,status,data_timestamp) values `
-	var isAdd bool
-	manualMap := make(map[string]*ManualEdbdata)
-	fmt.Println("manualDataList:", len(manualDataList))
-	for _, v := range manualDataList {
-		item := v
-		fmt.Println("Item:", item.Dt, item.Close, item.TradeCode, item.ModifyTime)
-		if findItem, ok := existDataMap[v.Dt]; !ok {
-			eDate := item.Dt
-			sValue := item.Close
-
-			dataTime, err := time.Parse(utils.FormatDate, eDate)
-			if err != nil {
-				return err
-			}
-			timestamp := dataTime.UnixNano() / 1e6
-			timeStr := fmt.Sprintf("%d", timestamp)
-
-			addSql += GetAddSql(edbInfoIdStr, edbCode, eDate, timeStr, sValue)
-			isAdd = true
-		} else {
-			if findItem.Value != item.Close {
-				sql := ` UPDATE %s SET value=?,modify_time=NOW() WHERE edb_info_id=? AND data_time=? `
-				sql = fmt.Sprintf(sql, dataTableName)
-				_, err = to.Raw(sql, item.Close, edbInfoId, item.Dt).Exec()
-				if err != nil {
-					return err
-				}
-			}
-		}
-		manualMap[v.Dt] = v
-	}
-	for _, v := range existDataList {
-		if _, ok := manualMap[v.DataTime]; !ok {
-			go DeleteEdbDataByIdAndSource(v.EdbDataId, utils.DATA_SOURCE_MANUAL)
-		}
-	}
-	fmt.Println("isAdd:", isAdd)
-	if isAdd {
-		addSql = strings.TrimRight(addSql, ",")
-		_, err = to.Raw(addSql).Exec()
-		if err != nil {
-			fmt.Println("RefreshAllEdbDataByManual add Err", err.Error())
-			return
-		}
-	}
-	return
-}
-
-func DeleteEdbDataByIdAndSource(edbDataId, source int) (err error) {
-	sql := ` DELETE FROM %s WHERE edb_data_id=? `
-	tableName := GetEdbDataTableName(source)
-	sql = fmt.Sprintf(sql, tableName)
-
-	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, edbDataId).Exec()
-	return
-}

+ 174 - 2
models/data_manage/edb_data_quarter.go

@@ -43,7 +43,7 @@ func AddCalculateQuarter(edbInfoId, source int, edbCode string) (err error) {
 	var pars []interface{}
 	condition += " AND edb_info_id=? "
 	pars = append(pars, edbInfoId)
-	dataList, err := GetEdbDataListAll(condition, pars, source, 0)
+	dataList, err := GetEdbDataListAll(condition, pars, source, utils.DATA_SUB_SOURCE_EDB, 0)
 	if err != nil {
 		return err
 	}
@@ -226,7 +226,7 @@ func AddCalculateQuarterV2(edbInfoId, source int, edbCode string) (err error) {
 	var pars []interface{}
 	condition += " AND edb_info_id=? "
 	pars = append(pars, edbInfoId)
-	dataList, err := GetEdbDataListAll(condition, pars, source, 0)
+	dataList, err := GetEdbDataListAll(condition, pars, source, utils.DATA_SUB_SOURCE_EDB, 0)
 	if err != nil {
 		return err
 	}
@@ -474,6 +474,8 @@ func AddCalculateQuarterV4(dataList []*EdbDataList) (result *EdbDataResult, err
 			}
 			day := currentYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
 
+			fmt.Println("day:", day, currentYearCjglDate, preYearCjglDate)
+
 			items := new(EdbDataItems)
 			items.BetweenDay = int(day) //公历日期换算成农历,需要减除的天数
 			items.Year = preYear
@@ -570,6 +572,176 @@ func AddCalculateQuarterV4(dataList []*EdbDataList) (result *EdbDataResult, err
 	return
 }
 
+// AddCalculateQuarterV6 指标季度数据计算(季节性图表)
+func AddCalculateQuarterV6(dataList []*EdbDataList) (result *EdbDataResult, err error) {
+	var errMsg string
+	defer func() {
+		if errMsg != "" {
+			fmt.Println("errMsg:", errMsg)
+		}
+	}()
+
+	endDate := dataList[len(dataList)-1].DataTime
+	endDateForm, err := time.Parse(utils.FormatDate, endDate)
+	if err != nil {
+		return result, err
+	}
+	thisMonth := int(endDateForm.Month())
+
+	result = new(EdbDataResult)
+	var yearArr []int
+	yearMap := make(map[int]int)
+	var cureentDate time.Time
+	if thisMonth < 11 {
+		for k, v := range dataList {
+			dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
+			if err != nil {
+				errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
+				return result, err
+			}
+			if k == len(dataList)-1 {
+				cureentDate = dateTime
+			}
+			year := dateTime.Year()
+			if _, ok := yearMap[year]; !ok {
+				yearArr = append(yearArr, year)
+			}
+			yearMap[year] = year
+		}
+	} else {
+		for k, v := range dataList {
+			dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
+			if err != nil {
+				errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
+				return result, err
+			}
+			if k == len(dataList)-1 {
+				cureentDate = dateTime
+			}
+			year := dateTime.Year() + 1
+			if _, ok := yearMap[year]; !ok {
+				yearArr = append(yearArr, year)
+			}
+			yearMap[year] = year
+		}
+	}
+	//排序
+	fmt.Println("yearArr:", yearArr)
+	thisYear := cureentDate.Year()
+	//thisMonth := int(cureentDate.Month())
+
+	fmt.Println("thisMonth:", thisMonth)
+	for ky, vy := range yearArr {
+		fmt.Printf("line 432:ky:%d, vy:%d, thisYear:%d, thisMonth:%d", ky, vy, thisYear, thisMonth)
+		fmt.Println("")
+		if thisMonth < 11 {
+			currentYearCjnl := strconv.Itoa(thisYear) + "-01-01"               //当前年份春节农历
+			currentYearCjgl := solarlunar.LunarToSolar(currentYearCjnl, false) //当前年份春节公历
+			currentYearCjglDate, err := time.Parse(utils.FormatDate, currentYearCjgl)
+			if err != nil {
+				errMsg = "生成当前春节失败,Err:" + err.Error()
+				return result, err
+			}
+
+			preYear := vy
+			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
+			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
+			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
+			if err != nil {
+				errMsg = "生成历史年份春节失败,Err:" + err.Error()
+				return result, err
+			}
+			day := currentYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
+
+			fmt.Println("day:", day, currentYearCjglDate, preYearCjglDate)
+
+			items := new(EdbDataItems)
+			items.BetweenDay = int(day) //公历日期换算成农历,需要减除的天数
+			items.Year = preYear
+			for _, v := range dataList {
+				dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
+				if err != nil {
+					errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
+					return result, err
+				}
+				newDate := dateTime.AddDate(0, 0, int(day))
+				timestamp := newDate.UnixNano() / 1e6
+				item := new(EdbDataList)
+				item.DataTime = newDate.Format(utils.FormatDate)
+				item.EdbInfoId = v.EdbInfoId
+				item.Value = v.Value
+				item.EdbDataId = v.EdbDataId
+				item.DataTimestamp = timestamp
+				items.Items = append(items.Items, item)
+			}
+			result.List = append(result.List, items)
+		} else {
+			nextYear := thisYear + 1
+			nextYearCjnl := strconv.Itoa(nextYear) + "-01-01"            //当前年份春节农历
+			nextYearCjgl := solarlunar.LunarToSolar(nextYearCjnl, false) //当前年份春节公历
+
+			nextYearCjglDate, err := time.Parse(utils.FormatDate, nextYearCjgl)
+			if err != nil {
+				errMsg = "生成当前春节失败,Err:" + err.Error()
+				return result, err
+			}
+			preYear := vy
+			preYearCjnl := strconv.Itoa(preYear) + "-01-01"            //之前年份春节农历
+			preYearCjgl := solarlunar.LunarToSolar(preYearCjnl, false) //之前年份春节公历
+			preYearCjglDate, err := time.Parse(utils.FormatDate, preYearCjgl)
+			if err != nil {
+				errMsg = "生成历史年份春节失败,Err:" + err.Error()
+				return result, err
+			}
+			day := nextYearCjglDate.Sub(preYearCjglDate).Hours() / float64(24)
+
+			fmt.Println("day:", day, nextYearCjglDate, preYearCjglDate)
+
+			items := new(EdbDataItems)
+			items.BetweenDay = int(day) //公历日期换算成农历,需要减除的天数
+			items.Year = preYear
+			fmt.Println("preYear:", preYear, "ky:", ky, "yearArrLen:", len(yearArr))
+			//if ky+1 < len(yearArr) {
+			for _, v := range dataList {
+				dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
+				if err != nil {
+					errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
+					return result, err
+				}
+				newDate := dateTime.AddDate(0, 0, int(day))
+				timestamp := newDate.UnixNano() / 1e6
+				item := new(EdbDataList)
+				item.DataTime = newDate.Format(utils.FormatDate)
+				item.EdbInfoId = v.EdbInfoId
+				item.Value = v.Value
+				item.EdbDataId = v.EdbDataId
+				item.DataTimestamp = timestamp
+				items.Items = append(items.Items, item)
+			}
+			result.List = append(result.List, items)
+			/*} else {
+				for _, v := range dataList {
+					dateTime, err := time.Parse(utils.FormatDate, v.DataTime)
+					if err != nil {
+						errMsg = "time.Parse Err:" + err.Error() + ";DataTime:" + v.DataTime
+						return result, err
+					}
+					timestamp := dateTime.UnixNano() / 1e6
+					item := new(EdbDataList)
+					item.DataTime = dateTime.Format(utils.FormatDate)
+					item.EdbInfoId = v.EdbInfoId
+					item.Value = v.Value
+					item.EdbDataId = v.EdbDataId
+					item.DataTimestamp = timestamp
+					items.Items = append(items.Items, item)
+				}
+				result.List = append(result.List, items)
+			}*/
+		}
+	}
+	return
+}
+
 // AddCalculateQuarterV4ByUniqueCode 指标季度数据计算(公历转农历)
 func AddCalculateQuarterV4ByUniqueCode(dataList []*EdbDataListByUniqueCode) (result *EdbDataResult, err error) {
 	var errMsg string

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно