فهرست منبع

Merge branch 'debug' of http://8.136.199.33:3000/eta_server/eta_api into bzq1/bug_season_cf

zqbao 4 ماه پیش
والد
کامیت
ced6b2dc57
100فایلهای تغییر یافته به همراه8148 افزوده شده و 1034 حذف شده
  1. 1 2
      .gitignore
  2. 10 1
      controllers/ai/ai_file.go
  3. 7 2
      controllers/data_manage/chart_info.go
  4. 5 1
      controllers/data_manage/chart_theme.go
  5. 1651 0
      controllers/data_manage/clarksons_data.go
  6. 2 1
      controllers/data_manage/correlation/correlation_chart_info.go
  7. 2 1
      controllers/data_manage/cross_variety/chart_info.go
  8. 3 3
      controllers/data_manage/data_manage_permission/data_manage_permission.go
  9. 3 3
      controllers/data_manage/data_manage_permission/data_move.go
  10. 1 1
      controllers/data_manage/data_manage_permission/message.go
  11. 162 3
      controllers/data_manage/edb_classify.go
  12. 202 4
      controllers/data_manage/edb_info.go
  13. 0 1
      controllers/data_manage/edb_info_calculate.go
  14. 1 1
      controllers/data_manage/edb_info_refresh.go
  15. 36 8
      controllers/data_manage/edb_info_relation.go
  16. 8 2
      controllers/data_manage/excel/balance_table.go
  17. 15 26
      controllers/data_manage/excel/excel_info.go
  18. 2 1
      controllers/data_manage/line_equation/line_chart_info.go
  19. 366 0
      controllers/data_manage/manual_edb.go
  20. 9 0
      controllers/data_manage/my_chart.go
  21. 30 30
      controllers/data_manage/mysteel_chemical_data.go
  22. 2 2
      controllers/data_manage/predict_edb_classify.go
  23. 177 70
      controllers/data_manage/predict_edb_info.go
  24. 0 1
      controllers/data_source/guagnzhouqihuo.go
  25. 6 2
      controllers/data_source/icpi.go
  26. 19 21
      controllers/data_stat/edb_source_stat.go
  27. 0 1
      controllers/english_report/report.go
  28. 24 3
      controllers/fe_calendar/fe_calendar_matter.go
  29. 1867 0
      controllers/material/material.go
  30. 55 4
      controllers/ppt_english.go
  31. 11 1
      controllers/ppt_english_group.go
  32. 58 4
      controllers/ppt_v2.go
  33. 11 1
      controllers/ppt_v2_group.go
  34. 1 0
      controllers/report.go
  35. 101 120
      controllers/report_chapter.go
  36. 1 0
      controllers/report_chapter_type.go
  37. 123 16
      controllers/report_v2.go
  38. 284 0
      controllers/residual_analysis/residual_analysis_controller.go
  39. 35 20
      controllers/sandbox/sandbox.go
  40. 53 26
      controllers/sys_admin.go
  41. 21 1
      controllers/sys_role.go
  42. 3 3
      controllers/sys_team.go
  43. 27 0
      controllers/target.go
  44. 51 49
      go.mod
  45. 117 257
      go.sum
  46. 1 1
      main.go
  47. 4 5
      models/bi_dashboard/bi_dashboard_detail.go
  48. 1 1
      models/bi_dashboard/bi_dashboard_grant.go
  49. 35 35
      models/business_conf.go
  50. 15 0
      models/chart_permission.go
  51. 213 0
      models/data_manage/base_from_clarksons_classify.go
  52. 81 0
      models/data_manage/base_from_clarksons_data.go
  53. 424 0
      models/data_manage/base_from_clarksons_index.go
  54. 3 2
      models/data_manage/base_from_trade_index.go
  55. 101 71
      models/data_manage/chart_info.go
  56. 1 1
      models/data_manage/data_manage_permission/classify_no_auth_record.go
  57. 26 4
      models/data_manage/data_manage_permission/edb.go
  58. 1 1
      models/data_manage/data_manage_permission/move.go
  59. 1 1
      models/data_manage/data_manage_permission/move_record.go
  60. 1 1
      models/data_manage/data_manage_permission/no_auth_record.go
  61. 2 0
      models/data_manage/edb_classify.go
  62. 17 7
      models/data_manage/edb_data_base.go
  63. 2 2
      models/data_manage/edb_data_mysteel_chemical.go
  64. 6 6
      models/data_manage/edb_data_wind.go
  65. 66 51
      models/data_manage/edb_info.go
  66. 15 15
      models/data_manage/edb_info_relation.go
  67. 2 1
      models/data_manage/excel/excel_info.go
  68. 3 0
      models/data_manage/excel/excel_sheet.go
  69. 11 0
      models/data_manage/excel/request/excel_info.go
  70. 1 0
      models/data_manage/excel/request/mixed_table.go
  71. 7 7
      models/data_manage/factor_edb_series.go
  72. 8 8
      models/data_manage/my_chart.go
  73. 4 4
      models/data_manage/mysteel_chemical_classify.go
  74. 36 36
      models/data_manage/mysteel_chemical_index.go
  75. 3 0
      models/data_manage/predict_edb_conf.go
  76. 74 0
      models/data_manage/request/clarksons_data.go
  77. 12 0
      models/data_manage/request/edb_info.go
  78. 7 6
      models/data_manage/request/mysteel_chemical_data.go
  79. 9 7
      models/data_manage/request/predict_edb_info.go
  80. 35 0
      models/data_manage/response/clarksons_data.go
  81. 3 2
      models/data_manage/smm_data.go
  82. 1 1
      models/data_manage/trade_analysis/trade_analysis.go
  83. 24 6
      models/db.go
  84. 250 0
      models/material/material.go
  85. 215 0
      models/material/material_classify.go
  86. 26 0
      models/move_interface.go
  87. 1 1
      models/ppt_english/ppt_english_grant.go
  88. 11 11
      models/ppt_english/ppt_english_group_mapping.go
  89. 2 2
      models/ppt_v2_group_mapping.go
  90. 10 1
      models/report.go
  91. 8 0
      models/report_chapter.go
  92. 1 1
      models/report_v2.go
  93. 205 0
      models/residual_analysis_model/calculate_residual_analysis_config.go
  94. 50 0
      models/residual_analysis_model/calculate_residual_analysis_config_mapping.go
  95. 40 0
      models/residual_analysis_model/edb_data_residual_analysis.go
  96. 4 0
      models/resource.go
  97. 26 26
      models/sandbox/sandbox.go
  98. 15 2
      models/smart_report/smart_report.go
  99. 1 1
      models/system/sys_user.go
  100. 464 14
      routers/commentsRouter.go

+ 1 - 2
.gitignore

@@ -3,7 +3,6 @@
 /.idea
 /routers/.DS_Store
 /rdlucklog
-/etalogs
 /conf/*.conf
 /binlog/*
 /*.pdf
@@ -19,4 +18,4 @@ eta_api.exe
 eta_api.exe~
 /static/tmpFile/*
 etalogs/
-/.vscode
+/.vscode

+ 10 - 1
controllers/ai/ai_file.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_api/models/aimod"
 	"eta/eta_api/services"
 	"eta/eta_api/services/aiser"
+	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
 	"fmt"
 	"os"
@@ -122,7 +123,6 @@ func (this *AiFileController) FileUpload() {
 		assistantId = topic.AssistantId
 		threadId = topic.ThreadId
 	}
-
 	if aiChatTopicId <= 0 { //新增
 		topic := new(aimod.AiChatTopic)
 		var filenameWithSuffix string
@@ -159,6 +159,15 @@ func (this *AiFileController) FileUpload() {
 		chatItem.OpenaiFilePath = resourceUrl
 		chatItem.CreateTime = time.Now()
 		chatItem.ModifyTime = time.Now()
+
+		bchat, err := json.Marshal(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题失败,Err:" + err.Error()
+			return
+		}
+		alarm_msg.SendAlarmMsg(string(bchat), 1)
+		alarm_msg.SendAlarmMsg(string("cur model:"+model), 1)
 		_, err = aimod.AddAiChat(chatItem)
 		if err != nil {
 			br.Msg = "获取数据失败!"

+ 7 - 2
controllers/data_manage/chart_info.go

@@ -1602,7 +1602,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
-			if v.LatestDate != "" {
+			if v.LatestDate != "" && v.LatestDate != "0000-00-00" {
 				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
 				if tErr != nil {
 					br.Msg = "获取失败"
@@ -4665,7 +4665,12 @@ func (this *ChartInfoController) ChartList() {
 		}
 	}
 	if keyWord != "" {
-		condition += ` AND  ( chart_name LIKE '%` + keyWord + `%' OR chart_name_en LIKE '%` + keyWord + `%' )`
+		keyWordArr := strings.Split(keyWord, " ")
+		if len(keyWordArr) > 0 {
+			for _, v := range keyWordArr {
+				condition += ` AND CONCAT(chart_name,chart_name_en) LIKE '%` + v + `%'`
+			}
+		}
 	}
 	if sysUserIds != "" {
 		adminIds := strings.Split(sysUserIds, ",")

+ 5 - 1
controllers/data_manage/chart_theme.go

@@ -161,6 +161,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 	chartInfo := new(data_manage.ChartInfoView)
 	// 图表额外数据参数
 	extraConfigStr := ``
+	var barConfig data_manage.BarChartInfoReq
 
 	// 开始时间,结束时间
 	var tmpStartDate, tmpEndDate string
@@ -189,6 +190,8 @@ func (c *ChartThemeController) GetThemePreviewData() {
 		chartInfo.ChartName = "散点图"
 	case 7: // 柱形图
 		edbInfoIdList = []int{1, 2, 3, 4, 5}
+		chartInfo.LeftMin = "260"
+		chartInfo.LeftMax = "430"
 		extraConfigStr = `{"EdbInfoIdList":[{"EdbInfoId":1,"Name":"指标1","NameEn":"","Source":0},{"EdbInfoId":2,"Name":"指标2","NameEn":"","Source":0},{"EdbInfoId":3,"Name":"指标3","NameEn":"","Source":0},{"EdbInfoId":4,"Name":"指标4","NameEn":"","Source":0},{"EdbInfoId":5,"Name":"指标5","NameEn":"","Source":0}],"DateList":[{"Type":2,"Date":"","Value":100,"Color":"","Name":""},{"Type":1,"Date":"","Value":0,"Color":"","Name":""}],"Sort":{"Sort":0,"DateIndex":0},"XEdbList":null,"YEdbList":null,"Unit":"千桶","UnitEn":""}`
 		chartInfo.ChartName = "柱形图"
 	case 10: // 截面散点图
@@ -280,6 +283,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 	resp.XEdbIdValue = xEdbIdValue
 	resp.YDataList = yDataList
 	resp.DataResp = dataResp
+	resp.BarChartInfo = barConfig
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"
@@ -363,7 +367,7 @@ func (c *ChartThemeController) Add() {
 }
 
 // Edit
-// @Title 新增主题
+// @Title 编辑主题
 // @Description
 // @Param	request	body request.DeleteThemeConfReq true "type json string"
 // @Success 200 Ret=200 修改成功

+ 1651 - 0
controllers/data_manage/clarksons_data.go

@@ -0,0 +1,1651 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/request"
+	"eta/eta_api/models/data_manage/response"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	etaTrialService "eta/eta_api/services/eta_trial"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/tealeg/xlsx"
+)
+
+type ClarksonsDataController struct {
+	controllers.BaseAuthController
+}
+
+// @Title 克拉克森数据分类
+// @Description 克拉克森数据分类接口
+// @Success 200 {object} data_manage.SciClassify
+// @router /clarksons/classify [get]
+func (this *ClarksonsDataController) Classify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	classifyList, err := data_manage.GetClarksonsClassifyAll()
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败, Err:" + err.Error()
+		return
+	}
+
+	initClassify := &data_manage.BaseFromClarksonsClassifyItem{
+		BaseFromClassifyId: 0,
+		ClassifyName:       "未分类",
+		ClassifyNameEn:     "Unclassified",
+		UniqueCode:         "0",
+		ParentId:           0,
+		Level:              1,
+		Sort:               0,
+		Children:           nil,
+	}
+	finalList := make([]*data_manage.BaseFromClarksonsClassifyItem, 0)
+	classifyTree := getClarksonsClassifyTree(classifyList, 0)
+	finalList = append(finalList, initClassify)
+	finalList = append(finalList, classifyTree...)
+
+	br.Msg = "查询成功"
+	br.Data = finalList
+	br.Success = true
+	br.Ret = 200
+}
+
+// AddSciClassify
+// @Title 新增分类
+// @Description 新增分类接口
+// @Param	request	body data_manage.AddBaseFromSciClassifyReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /clarksons/classify/add [post]
+func (this *ClarksonsDataController) AddClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.AddBaseFromClarksonsClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		return
+	}
+	if req.ParentId < 0 {
+		br.Msg = "操作异常"
+		return
+	}
+	ok, msg, err := data.AddClarksonsClassify(req.ClassifyName, req.ParentId)
+	if err != nil {
+		br.Msg = "添加失败"
+		br.ErrMsg = "添加失败,Err:" + err.Error()
+		return
+	}
+	if !ok {
+		if msg != "" {
+			br.Msg = msg
+			return
+		}
+		br.Msg = "添加失败"
+		return
+	}
+	br.Msg = "添加成功"
+	br.Success = true
+	br.Ret = 200
+}
+
+// DelClassify
+// @Title 新增分类
+// @Description 新增分类接口
+// @Param	request	body data_manage.AddBaseFromSciClassifyReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /clarksons/classify/del [post]
+func (this *ClarksonsDataController) DelClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.DelBaseFromClarksonsClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.BaseFromClassifyId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	err = data.DelClarksonsClassify(req.BaseFromClassifyId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// EditClassify
+// @Title 修改分类
+// @Description 修改分类接口
+// @Param	request	body data_manage.EditBaseFromMysteelChemicalClassifyReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /clarksons/classify/edit [post]
+func (this *ClarksonsDataController) EditClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.EditBaseFromClarksonsClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BaseFromClassifyId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	if req.ClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		return
+	}
+	classify, err := data_manage.GetClarksonsClassifyById(req.BaseFromClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "分类不存在"
+			return
+		}
+		br.Msg = "编辑失败"
+		br.ErrMsg = "获取分类失败,Err:" + err.Error()
+		return
+	}
+
+	if classify.ClassifyName != req.ClassifyName {
+		count, err := data_manage.GetClarksonsClassifyCountByName(req.ClassifyName)
+		if err != nil {
+			br.Msg = "编辑失败"
+			br.ErrMsg = "获取分类失败,Err:" + err.Error()
+			return
+		}
+		if count > 0 {
+			br.Msg = "分类名称已存在"
+			return
+		}
+		classify.ClassifyName = req.ClassifyName
+		classify.ModifyTime = time.Now()
+		err = classify.Update([]string{"classify_name", "modify_time"})
+		if err != nil {
+			br.Msg = "编辑失败"
+			br.ErrMsg = "编辑失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	br.Msg = "编辑成功"
+	br.Success = true
+	br.Ret = 200
+	br.IsAddLog = true
+}
+
+// MoveClassify
+// @Title 分类移动接口
+// @Description 分类移动接口
+// @Success 200 {object} data_manage.MoveBaseFromMysteelChemicalClassifyReq
+// @router /clarksons/classify/move [post]
+func (this *ClarksonsDataController) MoveClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req request.MoveBaseFromClarksonsClassifyReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BaseFromClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "分类id小于等于0"
+		br.IsSendEmail = false
+		return
+	}
+
+	err, errMsg := data.MoveClarksonsClassify(req.BaseFromClassifyId, req.ParentId, req.PrevClassifyId, req.NextClassifyId)
+	if errMsg != `` {
+		br.Msg = errMsg
+		br.ErrMsg = errMsg
+		if err != nil {
+			br.ErrMsg = err.Error()
+		} else {
+			br.IsSendEmail = false
+		}
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "移动成功"
+}
+
+// IndexList
+// @Title 克拉克森指标列表
+// @Description 克拉克森数据指标列表接口
+// @Param   BaseFromClassifyId   query   int  true       "分类id"
+// @Success 200 {object} data_manage.BaseFromMysteelChemicalIndexResp
+// @router /clarksons/index/list [get]
+func (this *ClarksonsDataController) IndexList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	classifyId, _ := this.GetInt("BaseFromClassifyId", 0)
+	indexList, err := data_manage.GetClarksonsIndexBaseInfoByClassifyId(classifyId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = indexList
+}
+
+// GetClarksonsIndexInfo
+// @Title 添加指标-根据条件获取指标信息
+// @Description 添加指标-根据条件获取指标信息
+// @Param   KeyWord   query   string  false       "关键字"
+// @Param   ClassifyIds   query   string  false       "分类id"
+// @Param   Frequencies   query   string  false       "频率"
+// @Param   PageSize   query   int  false       "每页数据条数"
+// @Param   CurrentIndex   query   int  false       "当前页页码,从1开始"
+// @Success 200 {object} data_manage.BaseFromRzdIndexPage
+// @router /clarksons/get/index/info [post]
+func (this *ClarksonsDataController) GetClarksonsIndexInfo() {
+	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 request.ClarksonsDataBatchListReq
+	if err := json.Unmarshal(this.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	keyWord := req.KeyWord
+	classifyIds := req.ClassifyIds
+	frequencies := req.Frequencies
+
+	pageSize := req.PageSize
+	currentIndex := req.CurrentIndex
+	var startSize int
+
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	var classifyIdList []string
+	var frequencyList []string
+	if classifyIds != "" {
+		classifyIdList = strings.Split(classifyIds, ",")
+	}
+	if frequencies != "" {
+		frequencyList = strings.Split(frequencies, ",")
+	}
+	indexInfoPage, err := data.GetClarksonsIndexInfo(keyWord, classifyIdList, frequencyList, currentIndex, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = indexInfoPage
+}
+
+// SearchList
+// @Title 克拉克森模糊搜索
+// @Description 克拉克森模糊搜索
+// @Param   Keyword   query   string  true       "关键字搜索"
+// @Success 200 {object} models.BaseResponse
+// @router /clarksons/search_list [get]
+func (this *ClarksonsDataController) SearchList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	//关键字
+	keyword := this.GetString("Keyword")
+	var condition string
+	var pars []interface{}
+	if keyword != "" {
+		condition += ` AND (index_code LIKE ? OR index_name LIKE ?)`
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+	} else {
+		br.Msg = "请输入指标ID/指标名称"
+		return
+	}
+
+	list, err := data_manage.GetClarksonsIndexBaseInfoByCondition(condition, pars)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = list
+}
+
+// SingleData
+// @Title 获取克拉克森据
+// @Description 获取克拉克森单条数据接口
+// @Param   BaseFromClarksonsIndexId   query   string  true       "指标唯一编码"
+// @Success 200 {object} models.BaseResponse
+// @router /clarksons/single_data [get]
+func (this *ClarksonsDataController) SingleData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	baseFromClarksonsIndexId, _ := this.GetInt("BaseFromClarksonsIndexId")
+	indexInfo, err := data_manage.GetClarksonsIndexByIndexId(baseFromClarksonsIndexId)
+	if err != nil {
+		br.Msg = "获取指标信息失败"
+		br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+		return
+	}
+	edbInfo, err := data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_CLARKSONS, indexInfo.IndexCode)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取指标数据失败"
+		br.ErrMsg = "获取指标库数据失败,Err:" + err.Error()
+		return
+	}
+	var edbInfoId int
+	if edbInfo != nil {
+		edbInfoId = edbInfo.EdbInfoId
+	}
+	dataList, err := data_manage.GetClarksonsDataByIndexId(baseFromClarksonsIndexId)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	var ret response.ClarksonsSingleDataResp
+	ret.ClassifyId = indexInfo.ClassifyId
+	ret.BaseFromClarksonsIndexId = indexInfo.BaseFromClarksonsIndexId
+	ret.IndexCode = indexInfo.IndexCode
+	ret.EdbInfoId = edbInfoId
+	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
+	ret.Data = dataList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = ret
+}
+
+// MoveClarksonsData
+// @Title 克拉克森指标移动接口
+// @Description 克拉克森指标移动接口
+// @Success 200 {object} request.MoveBaseFromClarksonsReq
+// @router /clarksons/move [post]
+func (this *ClarksonsDataController) MoveClarksonsData() {
+	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 request.MoveBaseFromClarksonsReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.BaseFromClarksonsIndexId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "指标id小于等于0"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.BaseFromClassifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		br.IsSendEmail = false
+		return
+	}
+
+	err, errMsg := data.MoveClarksonsData(req.BaseFromClarksonsIndexId, req.BaseFromClassifyId, req.PrevBaseFromClarksonsIndexId, req.NextBaseFromClarksonsIndexId)
+	if errMsg != `` {
+		br.Msg = errMsg
+		br.ErrMsg = errMsg
+		if err != nil {
+			br.ErrMsg = err.Error()
+		} else {
+			br.IsSendEmail = false
+		}
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "移动成功"
+}
+
+// ResetClarksonsIndex
+// @Title 指标数据清除分类
+// @Description 指标数据清除分类
+// @Param	request	body data_manage.DelBaseFromSciReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /clarksons/reset [post]
+//func (this *ClarksonsDataController) ResetClarksonsIndex() {
+//	br := new(models.BaseResponse).Init()
+//	defer func() {
+//		this.Data["json"] = br
+//		this.ServeJSON()
+//	}()
+//	var req request.ResetBaseFromClarksonsReq
+//	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+//	if err != nil {
+//		br.Msg = "参数解析异常!"
+//		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+//		return
+//	}
+//
+//	if req.BaseFromClarksonsIndexId < 0 {
+//		br.Msg = "参数错误"
+//		br.IsSendEmail = false
+//		return
+//	}
+//
+//	err = data.ResetClarksonsIndex(req.BaseFromClarksonsIndexId)
+//	if err != nil {
+//		br.Msg = "移动失败"
+//		br.ErrMsg = "移动失败,Err:" + err.Error()
+//		return
+//	}
+//
+//	br.Ret = 200
+//	br.Msg = "操作成功"
+//	br.Success = true
+//	br.IsAddLog = true
+//}
+
+// AddEdbInfo
+// @Title 新增指标接口
+// @Description 新增指标接口
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /clarksons/edb_info/add [post]
+//func (this *ClarksonsDataController) AddEdbInfo() {
+//	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_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.AddEdbInfoReq
+//	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+//	if err != nil {
+//		br.Msg = "参数解析异常!"
+//		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+//		return
+//	}
+//
+//	req.EdbName = strings.Trim(req.EdbName, " ")
+//	req.EdbCode = strings.Trim(req.EdbCode, " ")
+//
+//	if req.EdbCode == "" {
+//		br.Msg = "指标ID不能为空"
+//		return
+//	}
+//
+//	if req.EdbName == "" {
+//		br.Msg = "指标名称不能为空"
+//		return
+//	}
+//
+//	if req.Frequency == "" {
+//		br.Msg = "频率不能为空"
+//		return
+//	}
+//
+//	if req.Unit == "" {
+//		br.Msg = "单位不能为空"
+//		return
+//	}
+//
+//	if req.ClassifyId <= 0 {
+//		br.Msg = "请选择分类"
+//		return
+//	}
+//
+//	_, err = data_manage.GetClarksonsIndexByIndexCode(req.EdbCode)
+//	if err != nil {
+//		if err.Error() == utils.ErrNoRow() {
+//			br.Msg = "指标不存在"
+//			return
+//		}
+//		br.Msg = "获取失败"
+//		br.ErrMsg = "获取失败,Err:" + err.Error()
+//		return
+//	}
+//	source := utils.DATA_SOURCE_CLARKSONS
+//	// 指标入库
+//	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, this.Lang)
+//	if err != nil {
+//		br.Msg = "保存失败"
+//		if errMsg != `` {
+//			br.Msg = errMsg
+//		}
+//		br.ErrMsg = err.Error()
+//		br.IsSendEmail = isSendEmail
+//		return
+//	}
+//
+//	// 试用平台更新用户累计新增指标数
+//	adminItem, e := system.GetSysAdminById(sysUser.AdminId)
+//	if e != nil {
+//		br.Msg = "操作失败"
+//		br.ErrMsg = "获取系统用户数据失败,Err:" + e.Error()
+//		return
+//	}
+//	if utils.BusinessCode == utils.BusinessCodeSandbox && adminItem.DepartmentName == "ETA试用客户" {
+//		go func() {
+//			var r etaTrialService.EtaTrialUserReq
+//			r.Mobile = adminItem.Mobile
+//			_, _ = etaTrialService.UpdateUserIndexNum(r)
+//		}()
+//	}
+//
+//	//新增操作日志
+//	{
+//		// 添加钢联指标更新日志
+//		if edbInfo.Source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+//			go data_stat.AddEdbInfoUpdateLog(edbInfo.EdbInfoId, 1, "", sysUser, 2)
+//		}
+//
+//		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)
+//	}
+//
+//	// 更新es
+//	go data.AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+//
+//	resp := new(data_manage.AddEdbInfoResp)
+//	resp.EdbInfoId = edbInfo.EdbInfoId
+//	resp.UniqueCode = edbInfo.UniqueCode
+//	br.Ret = 200
+//	br.Success = true
+//	br.Msg = "保存成功"
+//	br.Data = resp
+//	br.IsAddLog = true
+//}
+
+// AddCheck
+// @Title 新增校验
+// @Description 新增校验
+// @Param	request	body request.BusinessDataBatchAddCheckReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /clarksons/edb_info/add_check [post]
+func (this *ClarksonsDataController) AddCheck() {
+	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 *request.ClarksonsDataBatchAddCheckReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	codeMax := 30
+	codeLen := len(req.IndexCodes)
+	if len(req.IndexCodes) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	if codeLen > codeMax {
+		br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMax)
+		return
+	}
+	// 获取指标库已有指标
+	existsEdb, e := data_manage.GetEdbCodesBySource(utils.DATA_SOURCE_CLARKSONS)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取自有数据已添加的指标失败, Err: " + e.Error()
+		return
+	}
+	existMap := make(map[string]*data_manage.EdbInfo)
+	for _, v := range existsEdb {
+		existMap[v.EdbCode] = v
+	}
+
+	// 查询选中的指标
+	cond := fmt.Sprintf(` AND index_code IN (%s)`, utils.GetOrmInReplace(codeLen))
+	pars := make([]interface{}, 0)
+	pars = append(pars, req.IndexCodes)
+	list, err := data_manage.GetClarksonsIndexAndEdbInfoByCondition(cond, pars)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取克拉克森原始指标列表失败, Err: " + err.Error()
+		return
+	}
+
+	resp := make([]*data_manage.BaseFromClarksonsIndexView, 0)
+	for _, v := range list {
+		if v.EdbInfoId > 0 {
+			v.EdbExist = 1
+		}
+		resp = append(resp, v)
+	}
+
+	br.Data = resp
+	br.Msg = "校验成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// NameCheck
+// @Title 重名校验
+// @Description 批量新增
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /clarksons/edb_info/name_check [post]
+func (c *ClarksonsDataController) NameCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		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.NameCheckEdbInfoReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	codeMax := 30
+	codeLen := len(req)
+	if codeLen > codeMax {
+		br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMax)
+		return
+	}
+
+	type NameCheckResult struct {
+		EdbCode string
+		EdbName string
+		Exist   bool
+	}
+	indexNames := make([]string, 0)
+	resp := make([]*NameCheckResult, 0)
+	for _, v := range req {
+		v.EdbCode = strings.TrimSpace(v.EdbCode)
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不可为空"
+			return
+		}
+		v.EdbName = strings.TrimSpace(v.EdbName)
+		if v.EdbName == "" {
+			br.Msg = "请输入指标名称"
+			return
+		}
+		indexNames = append(indexNames, v.EdbName)
+		resp = append(resp, &NameCheckResult{
+			EdbCode: v.EdbCode,
+			EdbName: v.EdbName,
+		})
+		dataItems, err := data_manage.GetEdbDataAllByEdbCode(v.EdbCode, utils.DATA_SOURCE_CLARKSONS, 0, utils.EDB_DATA_LIMIT)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取克拉克森已存在信息失败,Err:" + err.Error()
+			return
+		}
+		if len(dataItems) <= 0 {
+			respItem, err := data.AddEdbData(utils.DATA_SOURCE_CLARKSONS, v.EdbCode, v.Frequency)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取失败,Err:" + err.Error()
+				return
+			}
+			if respItem.Ret != 200 {
+				br.Msg = "未搜索到该指标"
+				br.ErrMsg = respItem.ErrMsg + ";EdbCode:" + v.EdbCode
+				return
+			}
+		}
+	}
+
+	// 重名校验
+	edbList, e := data_manage.GetEdbInfoByNameArr(indexNames, utils.EDB_INFO_TYPE)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取重名指标失败, Err: " + e.Error()
+		return
+	}
+	nameExists := make(map[string]bool)
+	for _, v := range edbList {
+		nameExists[v.EdbName] = true
+	}
+	if len(nameExists) > 0 {
+		for _, v := range resp {
+			v.Exist = nameExists[v.EdbName]
+		}
+	}
+
+	br.Data = resp
+	br.Msg = "校验成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// BatchAdd
+// @Title 批量新增
+// @Description 批量新增
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /clarksons/edb_info/batch_add [post]
+func (this *ClarksonsDataController) BatchAdd() {
+	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
+	}
+
+	deleteCache := true
+	cacheKey := "CACHE_EDB_INFO_BATCH_ADD_CLARKSONS_" + 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.AddEdbInfoReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	if len(req) > 30 {
+		br.Msg = "批量添加指标数量不得超过30个"
+		return
+	}
+	for _, v := range req {
+		v.EdbCode = strings.TrimSpace(v.EdbCode)
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不可为空"
+			return
+		}
+		v.EdbName = strings.TrimSpace(v.EdbName)
+		if v.EdbName == "" {
+			br.Msg = "请输入指标名称"
+			return
+		}
+		v.Frequency = strings.TrimSpace(v.Frequency)
+		if v.Frequency == "" {
+			br.Msg = "请选择频度"
+			return
+		}
+		v.Unit = strings.TrimSpace(v.Unit)
+		if v.Unit == "" {
+			br.Msg = "请输入单位"
+			return
+		}
+		if v.ClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			return
+		}
+	}
+
+	// 限定同一时间最多批量新增30个指标
+	for _, v := range req {
+		var r data.ClarksonsIndexSource2EdbReq
+		r.EdbCode = v.EdbCode
+		r.EdbName = v.EdbName
+		r.Frequency = v.Frequency
+		r.Unit = v.Unit
+		r.ClassifyId = v.ClassifyId
+		r.AdminId = sysUser.AdminId
+		r.AdminRealName = sysUser.RealName
+
+		edbInfo, errMsg, skip, e := data.ClarksonsIndexSource2Edb(r, this.Lang)
+		if e != nil {
+			br.Msg = "操作失败"
+			if errMsg != "" {
+				br.Msg = errMsg
+			}
+			br.ErrMsg = e.Error()
+			return
+		}
+		if skip {
+			continue
+		}
+
+		// 试用平台更新用户累计新增指标数
+		if utils.BusinessCode == utils.BusinessCodeSandbox {
+			go func() {
+				adminItem, e := system.GetSysAdminById(sysUser.AdminId)
+				if e != nil {
+					tips := fmt.Sprintf("试用平台更新用户累计新增指标数-获取用户失败, Err: " + e.Error())
+					utils.FileLog.Info(tips)
+					return
+				}
+				if adminItem.DepartmentName != "ETA试用客户" {
+					return
+				}
+				var ur etaTrialService.EtaTrialUserReq
+				ur.Mobile = adminItem.Mobile
+				_, _ = etaTrialService.UpdateUserIndexNum(ur)
+			}()
+		}
+
+		// 新增操作日志
+		{
+			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)
+		}
+	}
+
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// BatchDelete
+// @Title 批量删除
+// @Description 批量删除
+// @Param	request	body []*request.DelBaseFromClarksonsReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /clarksons/edb_info/batch_delete [post]
+func (this *ClarksonsDataController) BatchDelete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req []*request.DelBaseFromClarksonsReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	if len(req) > 30 {
+		br.Msg = "批量添加指标数量不得超过30个"
+		return
+	}
+	var deleteIds []int
+	for _, v := range req {
+		if v.BaseFromClarksonsIndexId <= 0 {
+			continue
+		}
+		deleteIds = append(deleteIds, v.BaseFromClarksonsIndexId)
+	}
+	existList, err := data.BatchDelClarksonsData(deleteIds)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	br.Data = existList
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// BatchEdit
+// @Title 批量编辑
+// @Description 批量编辑
+// @Param	request	body []*request.DelBaseFromClarksonsReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /clarksons/edb_info/batch_edit [post]
+func (this *ClarksonsDataController) BatchEdit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req []*request.EditBaseFromClarksonsReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	indexIds := make([]int, 0)
+	classifyIds := make([]int, 0)
+	indexIdToclassifyId := make(map[int]int)
+	for _, v := range req {
+		if v.BaseFromClarksonsIndexId <= 0 {
+			continue
+		}
+		if v.BaseFromClassifyId <= 0 {
+			continue
+		}
+		indexIds = append(indexIds, v.BaseFromClarksonsIndexId)
+		classifyIds = append(classifyIds, v.BaseFromClassifyId)
+		indexIdToclassifyId[v.BaseFromClarksonsIndexId] = v.BaseFromClassifyId
+	}
+	if len(indexIds) == 0 {
+		br.Msg = "请选择指标或指定正确的分类"
+		return
+	}
+	indexList, err := data_manage.GetClarksonsIndexListByIndexIds(indexIds)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "获取指标失败,Err:" + err.Error()
+		return
+	}
+	classifySort, err := data_manage.GetClarksonsClassifyMaxSortByClassifyIds(classifyIds)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "获取分类最大排序失败,Err:" + err.Error()
+		return
+	}
+	classifySortMap := make(map[int]int)
+	for _, v := range classifySort {
+		classifySortMap[v.BaseFromClassifyId] = v.MaxSort
+	}
+	classifyList, err := data_manage.GetClarksonsClassifyListByIds(classifyIds)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "获取分类失败,Err:" + err.Error()
+		return
+	}
+	existClassifyList := make(map[int]struct{})
+	for _, v := range classifyList {
+		existClassifyList[v.BaseFromClassifyId] = struct{}{}
+	}
+	//编辑指标
+	updateIndexList := make([]*data_manage.BaseFromClarksonsIndex, 0)
+	for _, v := range indexList {
+		tmpClassifyId := indexIdToclassifyId[v.BaseFromClarksonsIndexId]
+		if _, ok := existClassifyList[tmpClassifyId]; ok {
+			v.ClassifyId = tmpClassifyId
+			v.Sort = classifySortMap[tmpClassifyId] + 1
+			classifySortMap[tmpClassifyId] += 1
+			updateIndexList = append(updateIndexList, v)
+		}
+	}
+	err = data_manage.BatchModifyClarksonsIndexClassify(updateIndexList)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑指标失败,Err:" + err.Error()
+		return
+	}
+
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+
+}
+
+// EditClarksons
+// @Title 编辑克拉克森指标
+// @Description 编辑克拉克森指标接口
+// @Param	request	body data_manage.AddEdbClassifyReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /clarksons/edit [post]
+func (this *ClarksonsDataController) EditClarksons() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.EditBaseFromClarksonsReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BaseFromClarksonsIndexId <= 0 {
+		br.Msg = "请选择指标"
+		br.IsSendEmail = false
+		return
+	}
+	if req.BaseFromClassifyId <= 0 {
+		br.Msg = "请选择分类"
+		br.IsSendEmail = false
+		return
+	}
+
+	//编辑指标
+	sciIndexInfo, errMsg, err := data.EditClarksonsIndex(req.BaseFromClarksonsIndexId, req.BaseFromClassifyId)
+	if errMsg != `` {
+		br.Msg = errMsg
+		return
+	}
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑指标失败,Err:" + err.Error()
+		return
+	}
+
+	resp := response.EditClarksonsIndexInfoResp{
+		BaseFromClarksonsIndexId: sciIndexInfo.BaseFromClarksonsIndexId,
+		IndexCode:                sciIndexInfo.IndexCode,
+	}
+	br.Data = resp
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// DeleteClarksonsData
+// @Title 删除指标
+// @Description 删除指标接口
+// @Param	request	body data_manage.DelBaseFromSciReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /clarksons/del [post]
+func (this *ClarksonsDataController) DeleteClarksonsData() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req request.DelBaseFromClarksonsReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.BaseFromClarksonsIndexId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	err, errMsg := data.DelClarksonsData(req.BaseFromClarksonsIndexId)
+	if errMsg != `` {
+		br.Msg = errMsg
+		br.ErrMsg = errMsg
+		if err != nil {
+			br.ErrMsg = errMsg + ";Err:" + err.Error()
+		} else {
+			br.IsSendEmail = false
+		}
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// ExportClarksonsList
+// @Title 导出Sci数据
+// @Description 导出Sci数据
+// @Param   BaseFromClassifyId   query   int  true       "关键字搜索"
+// @Param   IndexCode   query   string  true       "指标编码"
+// @Success 200  导出成功
+// @router /export/clarksonsList [get]
+func (this *ClarksonsDataController) ExportClarksonsList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	classifyId, _ := this.GetInt("BaseFromClassifyId")
+	indexCode := this.GetString("IndexCode")
+	if classifyId < 0 {
+		br.Msg = "请选择分类"
+		return
+	}
+	secNameList := make([]*data_manage.BaseFromClarksonsIndex, 0)
+	dir, _ := os.Executable()
+	exPath := filepath.Dir(dir)
+	downLoadnFilePath := exPath + "/" + time.Now().Format(utils.FormatDateTimeUnSpace) + ".xlsx"
+	xlsxFile := xlsx.NewFile()
+
+	var condition string
+	var pars []interface{}
+	if classifyId > 0 {
+		childClassify, err := data_manage.GetChildClarksonsClassifyListById(classifyId)
+		if err != nil {
+			br.Msg = "下载失败"
+			br.ErrMsg = "获取分类失败,Err:" + err.Error()
+			return
+		}
+		if len(childClassify) > 0 {
+			condition += `AND classify_id IN (` + utils.GetOrmInReplace(len(childClassify)) + `)`
+			for _, child := range childClassify {
+				pars = append(pars, child.BaseFromClassifyId)
+			}
+		} else {
+			condition += ` AND classify_id=?`
+			pars = append(pars, classifyId)
+		}
+	} else {
+		condition += ` AND classify_id=?`
+		pars = append(pars, classifyId)
+	}
+	if indexCode != "" {
+		condition += ` AND index_code=? `
+		pars = append(pars, indexCode)
+	}
+	frequencies, err := data_manage.GetClarksonsFrequencyByCondition(condition, pars)
+	if err != nil {
+		fmt.Println("GetSciFrequency err:", err.Error())
+		utils.FileLog.Info("GetSciFrequency err:" + err.Error())
+		return
+	}
+	for _, frequency := range frequencies {
+		//获取指标
+		secNameList, err = data_manage.GetClarksonsIndexByConditionAndFrequency(condition, *frequency, pars)
+		if err != nil {
+			fmt.Println("获取数据失败,Err:" + err.Error())
+			return
+		}
+		if len(secNameList) <= 0 {
+			fmt.Println("secNameList长度为0")
+			return
+		}
+		sheetNew, err := xlsxFile.AddSheet(*frequency)
+		if err != nil {
+			fmt.Println("新增Sheet失败", err.Error())
+			return
+		}
+		secNameRow := sheetNew.AddRow()
+		frequencyRow := sheetNew.AddRow()
+		unitRow := sheetNew.AddRow()
+		lastModifyDateRow := sheetNew.AddRow()
+
+		var indexIdList []int
+		for _, sv := range secNameList {
+			indexIdList = append(indexIdList, sv.BaseFromClarksonsIndexId)
+		}
+		dataTimeList, err := data_manage.GetClarksonsDataDataTimeByIndexId(indexIdList)
+		if err != nil {
+			fmt.Println("获取数据时间失败", err.Error())
+			return
+		}
+
+		// 添加excel左侧指标日期
+		setRowIndex := 4
+		for rk, dv := range dataTimeList {
+			rowIndex := setRowIndex + rk
+			row := sheetNew.Row(rowIndex)
+			displayDate, _ := time.Parse(utils.FormatDate, dv)
+			displayDateCell := row.AddCell()
+			style := new(xlsx.Style)
+			style.ApplyAlignment = true
+			style.Alignment.WrapText = true
+			displayDateCell.SetStyle(style)
+			displayDateCell.SetDate(displayDate)
+
+		}
+		for k, sv := range secNameList {
+			//获取数据
+			dataList, err := data_manage.GetClarksonsIndexDataByCode(sv.IndexCode)
+			if err != nil {
+				br.Msg = "获取数据失败"
+				br.ErrMsg = "获取数据失败,Err:" + err.Error()
+				return
+			}
+			if k == 0 {
+				secNameRow.AddCell().SetValue("指标名称")
+				frequencyRow.AddCell().SetValue("频率")
+				unitRow.AddCell().SetValue("单位")
+				lastModifyDateRow.AddCell().SetValue("更新时间")
+				min := k * 3
+				sheetNew.SetColWidth(min, min, 15)
+			}
+			if len(dataList) == 0 {
+				continue
+			}
+			secNameRow.AddCell().SetValue(sv.IndexName)
+			frequencyRow.AddCell().SetValue(sv.Frequency)
+			unitRow.AddCell().SetValue(sv.Unit)
+
+			lastModifyDateRow.AddCell().SetValue(sv.ModifyTime.Format(utils.FormatDate))
+			dataInfoMap := make(map[string]*data_manage.BaseFromClarksonsData)
+			for _, v := range dataList {
+				dataInfoMap[v.DataTime] = v
+			}
+
+			for rk, dtv := range dataTimeList {
+				rowIndex := setRowIndex + rk
+				row := sheetNew.Row(rowIndex)
+				displayDateCell := row.AddCell()
+				tmpData, ok := dataInfoMap[dtv]
+				if ok {
+					displayDateCell.SetValue(tmpData.Value)
+				}
+			}
+		}
+	}
+
+	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 indexCode != "" && len(secNameList) == 1 {
+		fileName = secNameList[0].IndexName
+	}
+	fileName += time.Now().Format("2006.01.02") + `.xlsx` //文件名称
+	this.Ctx.Output.Download(downLoadnFilePath, fileName)
+	defer func() {
+		os.Remove(downLoadnFilePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+}
+
+// getClarksonsClassifyTree 返回卓创红旗的树形结构
+func getClarksonsClassifyTree(items []*data_manage.BaseFromClarksonsClassifyItem, parentId int) []*data_manage.BaseFromClarksonsClassifyItem {
+	res := make([]*data_manage.BaseFromClarksonsClassifyItem, 0)
+	for _, item := range items {
+		if item.ParentId == parentId {
+			t := new(data_manage.BaseFromClarksonsClassifyItem)
+			t.BaseFromClassifyId = item.BaseFromClassifyId
+			t.ClassifyName = item.ClassifyName
+			t.ParentId = item.ParentId
+			t.Level = item.Level
+			t.Sort = item.Sort
+			t.ModifyTime = item.ModifyTime
+			t.CreateTime = item.CreateTime
+			t.ClassifyNameEn = item.ClassifyNameEn
+			if item.UniqueCode == "" {
+				t.UniqueCode = strconv.Itoa(item.BaseFromClassifyId)
+			}
+			t.Children = getClarksonsClassifyTree(items, item.BaseFromClassifyId)
+			res = append(res, t)
+		}
+	}
+	return res
+}
+
+// @Title 获取克拉克森数据
+// @Description 获取克拉克森数据接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   BaseFromSci99ClassifyId   query   int  true       "分类id"
+// @Param   KeyWord   query   string  true       "关键词"
+// @Success 200 {object} data_source.BaseFromSci99IndexView
+// @router /clarksons/index/data [get]
+func (this *ClarksonsDataController) ClarksonsData() {
+	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)
+
+	baseFromClarksonsClassifyId, _ := this.GetInt("BaseFromClarksonsClassifyId")
+	if baseFromClarksonsClassifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	keyword := this.GetString("KeyWord")
+
+	//获取指标
+	var condition string
+	var pars []interface{}
+
+	if baseFromClarksonsClassifyId > 0 {
+		condition += ` AND classify_id=? `
+		pars = append(pars, baseFromClarksonsClassifyId)
+	}
+
+	if keyword != "" {
+		condition += ` AND (index_code =? OR index_name LIKE ?)  `
+		pars = append(pars, keyword)
+		pars = append(pars, "%"+keyword+"%")
+	}
+
+
+	sci99List, err := data_manage.GetClarksonsIndex(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	resultList := make([]*data_manage.BaseFromClarksonsIndexList, 0)
+	for _, v := range sci99List {
+		product := new(data_manage.BaseFromClarksonsIndexList)
+		product.BaseFromClarksonsIndexId = v.BaseFromClarksonsIndexId
+		product.ClassifyId = v.ClassifyId
+		product.IndexCode = v.IndexCode
+		product.IndexName = v.IndexName
+		product.Frequency = v.Frequency
+		product.Unit = v.Unit
+		product.ModifyTime = v.ModifyTime
+
+		modifyTime, err := data_manage.GetClarksonsIndexLatestDate(v.IndexCode)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取更新时间失败"
+			br.ErrMsg = "获取更新时间失败,Err:" + err.Error()
+			return
+		}
+		product.ModifyTime = modifyTime
+
+		total, err := data_manage.GetClarksonsIndexDataCount(v.IndexCode)
+		page := paging.GetPaging(currentIndex, pageSize, total)
+		dataList, err := data_manage.GetClarksonsIndexData(v.IndexCode, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		if dataList == nil {
+			dataList = make([]*data_manage.BaseFromClarksonsData, 0)
+		}
+		product.DataList = dataList
+		product.Paging = page
+		resultList = append(resultList, product)
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resultList
+}
+
+// IndexPageList
+// @Title 克拉克森指标列表
+// @Description 克拉克森数据指标列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ClassifyId   query   int  true       "分类id"
+// @Param   IsListAll   query   int  true       "是否展示全部"
+// @Success 200 {object} data_manage.BaseFromMysteelChemicalIndexResp
+// @router /clarksons/index/page/list [get]
+func (this *ClarksonsDataController) IndexPageList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	classifyId, _ := this.GetInt("ClassifyId", 0)
+	pageSize, _ := this.GetInt("PageSize")
+	currrentIndex, _ := this.GetInt("CurrentIndex")
+	isListAll, _ := this.GetBool("IsListAll")
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currrentIndex <= 0 {
+		currrentIndex = 1
+	}
+	startSize = utils.StartIndex(currrentIndex, pageSize)
+	var total int
+	var indexList []*data_manage.BaseFromClarksonsIndexView
+	if isListAll {
+		tmpTotal, err := data_manage.GetClarksonsIndexCount()
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+		total = tmpTotal
+		tmpIndexList, err := data_manage.GetClarksonsIndexByPage(startSize, pageSize)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+		indexList = tmpIndexList
+	} else {
+		var classifyIds []int
+		if classifyId > 0 {
+			tmpClassifyIds, err := data_manage.GetClarksonsChildClassifyIdsById(classifyId)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+				return
+			}
+			if len(tmpClassifyIds) > 0 {
+				classifyIds = append(classifyIds, tmpClassifyIds...)
+			}
+		}
+		classifyIds = append(classifyIds, classifyId)
+		tmpTotal, err := data_manage.GetClarksonsIndexCountByClassifyId(classifyIds)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+		total = tmpTotal
+		tmpIndexList, err := data_manage.GetClarksonsIndexByClassifyId(classifyIds, startSize, pageSize)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取指标信息失败,Err:" + err.Error()
+			return
+		}
+		indexList = tmpIndexList
+	}
+
+	page := paging.GetPaging(currrentIndex, pageSize, total)
+	resp := new(response.ClarksonsIndexPageListResp)
+	resp.List = indexList
+	resp.Paging = page
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 2 - 1
controllers/data_manage/correlation/correlation_chart_info.go

@@ -13,11 +13,12 @@ import (
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // CorrelationChartInfoController 相关性图表管理

+ 2 - 1
controllers/data_manage/cross_variety/chart_info.go

@@ -15,10 +15,11 @@ import (
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // ChartInfoController

+ 3 - 3
controllers/data_manage/data_manage_permission/data_manage_permission.go

@@ -203,7 +203,7 @@ func (c *DataMangePermissionController) SetEdbChartClassifyPermission() {
 // GetEdbChartPermission
 // @Title 指标/图表/表格权限设置接口
 // @Description 指标/图表/表格权限设置接口
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :目前作用于ETA表格,2024-3-26 14:12:09"
 // @Param   DataId   query   int  false       "资产id"
 // @Success 200 {object} data_manage.ChartListResp
@@ -262,7 +262,7 @@ func (c *DataMangePermissionController) GetEdbChartPermission() {
 // GetEdbChartClassifyPermission
 // @Title 获取指标/图表/表格分类权限设置接口
 // @Description 获取指标/图表/表格分类权限设置接口
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :目前作用于ETA表格,2024-3-26 14:12:09"
 // @Param   UserId   query   int  false       "用户id"
 // @Success 200 {object} data_manage.ChartListResp
@@ -336,7 +336,7 @@ func (c *DataMangePermissionController) GetEdbChartClassifyPermission() {
 // GetEdbChartNoPermission
 // @Title 根据资产id获取其分类没有权限的用户id列表接口
 // @Description 根据资产id获取其分类没有权限的用户id列表接口
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :目前作用于ETA表格,2024-3-26 14:12:09"
 // @Param   DataId   query   int  false       "资产id"
 // @Success 200 {object} data_manage.ChartListResp

+ 3 - 3
controllers/data_manage/data_manage_permission/data_move.go

@@ -13,7 +13,7 @@ import (
 // EdbChartClassifyList
 // @Title 获取指标/图表分类列表数据接口
 // @Description 获取指标/图表分类列表数据接口
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :ETA表格中的各种表格类型,以及图表的来源(这个是后续的扩展方向)"
 // @Success 200 {object} data_manage.ChartListResp
 // @router /edb_chart/classify [get]
@@ -63,7 +63,7 @@ func (c *DataMangePermissionController) EdbChartClassifyList() {
 // SecretEdbChartClassifyList
 // @Title 获取涉密的指标/图表分类列表数据接口
 // @Description 获取指标/图表分类列表数据接口
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :ETA表格中的各种表格类型,以及图表的来源(这个是后续的扩展方向)"
 // @Success 200 {object} data_manage.ChartListResp
 // @router /edb_chart/classify/secret [get]
@@ -133,7 +133,7 @@ func removeNodesWithNoJoinPermissionAndEmptyChildRecursively(nodes []*data_manag
 // @Description 获取指标/图表创建人列表数据接口
 // @Param   PageSize   query   int  true       "每页数据条数"
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :目前作用于ETA表格,2024-3-26 14:12:09"
 // @Param   Keyword   query   string  false       "关键字,code或者名称"
 // @Param   Classify   query   string  false       "分类id"

+ 1 - 1
controllers/data_manage/data_manage_permission/message.go

@@ -172,7 +172,7 @@ func (c *DataMangePermissionController) MessageRead() {
 // @Param   MessageId			query	int		true	"消息ID"
 // @Param   PageSize   query   int  true       "每页数据条数"
 // @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格"
 // @Param   SubSource   query   int  false       "子来源 :目前作用于ETA表格,2024-3-26 14:12:09"
 // @Success 200 {object} data_manage_permission.MessageDetailListResp
 // @router /message/detail [get]

+ 162 - 3
controllers/data_manage/edb_classify.go

@@ -9,7 +9,10 @@ import (
 	"eta/eta_api/services/data"
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"sort"
+	"strconv"
+	"strings"
 )
 
 // EdbClassifyController 数据管理-分类模块
@@ -288,7 +291,7 @@ func (this *EdbClassifyController) EditEdbClassify() {
 		return
 	}
 
-	err, errMsg := data.EditEdbClassify(req.ClassifyId, req.ClassifyName, this.Lang, this.SysUser)
+	err, errMsg := data.EditEdbClassify(req.ClassifyId, req.ParentId, req.ClassifyName, this.Lang, this.SysUser)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -1109,7 +1112,7 @@ func (this *EdbClassifyController) ClassifyTree() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
-
+	level, _ := this.GetInt(`Level`)
 	allList, err := data_manage.GetNormalEdbClassifyAll()
 	if err != nil && err.Error() != utils.ErrNoRow() {
 		br.Msg = "获取失败"
@@ -1135,7 +1138,7 @@ func (this *EdbClassifyController) ClassifyTree() {
 			button := data.GetEdbClassifyOpButton(this.SysUser, v.SysUserId, v.HaveOperaAuth)
 			allList[k].Button = button
 		}
-		nodeAll = data.GetClassifyTreeRecursive(allList, 0)
+		nodeAll = data.GetClassifyTreeRecursive(allList, 0, level)
 		//根据sort值排序
 		sortList = nodeAll
 		sort.Sort(sortList)
@@ -1221,3 +1224,159 @@ func (this *EdbClassifyController) ClassifyTree() {
 //	br.Success = true
 //	br.Msg = "移动成功"
 //}
+
+// EdbInfoList
+// @Title 批量编辑指标列表接口
+// @Description 批量编辑指标列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   EdbInfoId   query   int  true       "指标id"
+// @Param   KeyWord   query   string  false       "搜索关键词:指标ID/指标名称"
+// @Success 200 {object} data_manage.EdbInfoListResp
+// @router /classify/edb/list [get]
+func (this *EdbInfoController) ClassifyEdbInfoList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	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)
+
+	subClassify, _ := this.GetBool("SubClassify")
+	sources := this.GetString("Sources")
+	keyWord := this.GetString("KeyWord")
+	sysUserIds := this.GetString("SysUserIds")
+	classifyIdsStr := this.GetString("ClassifyIds")
+	classifyIds := strings.Split(classifyIdsStr, ",")
+
+
+	var condition string
+	var pars []interface{}
+
+	// 已授权分类id
+	permissionClassifyIdList, err := data_manage_permission.GetUserEdbClassifyPermissionList(this.SysUser.AdminId, 0)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+		return
+	}
+	classifyIdsArr := make([]int, 0)
+	for _, v := range classifyIds {
+		if v != `` {
+			id, _ := strconv.Atoi(v)
+			classifyIdsArr = append(classifyIdsArr, id)
+		}
+	}
+
+	if len(permissionClassifyIdList) > 0 {
+		classifyIdsArr = utils.IntersectInt(permissionClassifyIdList, classifyIdsArr)
+	}
+
+	condition += " AND edb_info_type = 0 "
+	if len(classifyIdsArr) > 0 {
+		if !subClassify {
+			condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(classifyIdsArr)) + ") "
+			pars = append(pars, classifyIdsArr)
+		} else {
+			classifyAll, err := data_manage.GetNormalEdbClassifyAll()
+			if err != nil && err.Error() != utils.ErrNoRow() {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取数据失败,Err:" + err.Error()
+				return
+			}
+			finalClassifyIds := make([]int, 0)
+			parents := data.GetEdbClassifyChildrenRecursiveByParentIds(classifyAll, classifyIds)
+			sort.Slice(parents, func(i, j int) bool {
+				return parents[i].Level < parents[i].Level
+			})
+			for _, v := range parents {
+				finalClassifyIds = append(finalClassifyIds, v.ClassifyId)
+			}
+
+			condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(finalClassifyIds)) + ") "
+			pars = append(pars, finalClassifyIds)
+		}
+	}
+	if keyWord != "" {
+		keyWordArr := strings.Split(keyWord, " ")
+		if len(keyWordArr) > 0 {
+			for _, v := range keyWordArr {
+				condition += ` AND edb_name LIKE '%` + v + `%' `
+			}
+		}
+	}
+	if sources != "" {
+		condition += " AND source IN(" + utils.GetOrmInReplace(len(strings.Split(sources, ","))) + ") "
+		pars = append(pars, strings.Split(sources, ","))
+	}
+	if sysUserIds != "" {
+		adminIds := strings.Split(sysUserIds, ",")
+		if len(adminIds) == 0 {
+			br.Msg = "请选择正确的创建人"
+			return
+		}
+		adminIdsSlice := make([]int, 0)
+		for _, adminId := range adminIds {
+			adminIdInt, e := strconv.Atoi(adminId)
+			if e != nil {
+				br.Msg = "请选择正确的创建人"
+				return
+			}
+			adminIdsSlice = append(adminIdsSlice, adminIdInt)
+		}
+		condition += "  AND sys_user_id in (" + utils.GetOrmInReplace(len(adminIds)) + ") "
+		pars = append(pars, adminIdsSlice)
+	}
+
+	// 获取当前账号的不可见指标
+	obj := data_manage.EdbInfoNoPermissionAdmin{}
+	confList, err := obj.GetAllListByAdminId(this.SysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+		return
+	}
+	noPermissionEdbInfoIds := make([]int, 0)
+	for _, v := range confList {
+		noPermissionEdbInfoIds = append(noPermissionEdbInfoIds, v.EdbInfoId)
+	}
+	if len(noPermissionEdbInfoIds) > 0 {
+		condition += " AND edb_info_id NOT IN(" + utils.GetOrmInReplace(len(noPermissionEdbInfoIds)) + ") "
+		pars = append(pars, noPermissionEdbInfoIds)
+	}
+
+	count, err := data_manage.GetEdbInfoByConditionCount(condition, pars)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	page := paging.GetPaging(currentIndex, pageSize, count)
+
+	list, err := data_manage.GetEdbInfoListByCondition(condition, pars, startSize, pageSize, "")
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+
+	resp := new(data_manage.EdbInfoFilterDataResp)
+	resp.List = list
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 202 - 4
controllers/data_manage/edb_info.go

@@ -21,6 +21,7 @@ import (
 	etaTrialService "eta/eta_api/services/eta_trial"
 	"eta/eta_api/utils"
 	"fmt"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -1250,7 +1251,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				}
 				isAdd = true
 			}
-		} else if source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL { //钢联化工
+		} else if source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL { //上海钢联
 			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
@@ -2281,6 +2282,8 @@ func (this *EdbInfoController) EdbInfoList() {
 	button.AddButton = false
 	edbInfoItem.Button = button
 	edbInfoItem.DataList = make([]*data_manage.EdbData, 0)
+	edbInfoItem.EndValue = utils.FormatFloatPoint(edbInfoItem.EndValue, 4)
+	edbInfoItem.LatestValue = utils.FormatFloatPoint(edbInfoItem.LatestValue, 4)
 
 	// 如果有数据权限,那么就去获取指标数据
 	if edbInfoItem.HaveOperaAuth {
@@ -2290,6 +2293,9 @@ func (this *EdbInfoController) EdbInfoList() {
 			br.ErrMsg = "获取指标数据总数失败,Err:" + err.Error()
 			return
 		}
+		for _, v := range dataList {
+			v.Value = utils.FormatFloatPoint(v.Value, 4)
+		}
 		page = paging.GetPaging(currentIndex, pageSize, dataCount)
 		edbInfoItem.DataList = dataList
 	}
@@ -2401,7 +2407,7 @@ func (this *EdbInfoController) EdbInfoAdd() {
 	//	return
 	//}
 
-	// 兼容钢联与钢联化工数据
+	// 兼容钢联与上海钢联数据
 	if utils.InArrayByInt([]int{utils.DATA_SOURCE_GL, utils.DATA_SOURCE_MYSTEEL_CHEMICAL}, source) {
 		// 如果是钢联的话,那么就先判断是不是存在钢联化工
 		tmpInfo, err := data_manage.GetBaseFromMysteelChemicalIndexByCode(req.EdbCode)
@@ -3891,6 +3897,10 @@ func (this *ChartInfoController) EdbInfoData() {
 		}
 		fullEdb.HaveOperaAuth = haveOperaAuth
 	}
+	fullEdb.MinValue = utils.FormatFloatPoint(fullEdb.MinValue, 4)
+	fullEdb.MaxValue = utils.FormatFloatPoint(fullEdb.MaxValue, 4)
+	fullEdb.EndValue = utils.FormatFloatPoint(fullEdb.EndValue, 4)
+	fullEdb.LatestValue = utils.FormatFloatPoint(fullEdb.LatestValue, 4)
 	resp.EdbInfo = fullEdb
 
 	resp.DataList = make([]*data_manage.EdbDataList, 0)
@@ -3907,7 +3917,9 @@ func (this *ChartInfoController) EdbInfoData() {
 			br.ErrMsg = "获取失败,Err:" + err.Error()
 			return
 		}
-
+		for _, v := range dataList {
+			v.Value = utils.FormatFloatPoint(v.Value, 4)
+		}
 		resp.DataList = dataList
 	}
 	br.Ret = 200
@@ -5223,7 +5235,7 @@ func (this *EdbInfoController) GetEdbBeforeAndAfterDateData() {
 // EdbChartAdminList
 // @Title 获取创建人员分组
 // @Description 获取创建人员分组
-// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库"
+// @Param   Source   query   int  false       "来源 :1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库"
 // @Success 200 {object} company.DepartmentGroupSellersResp
 // @router /edb_chart/adminList [get]
 func (this *EdbInfoController) EdbChartAdminList() {
@@ -6719,3 +6731,189 @@ func (this *EdbInfoController) ChartImageSetBySvg() {
 	br.Success = true
 	br.Msg = "保存成功"
 }
+
+// ModifyChartList
+// @Title 批量修改图表
+// @Description 批量修改图表
+// @Param   SysUserIds   query   string  true       "根据创建人查询"
+// @Param   ChartClassifyIds   query   string  true       "图片分类id"
+// @Success 200 {object} models.ChartClassifyListResp
+// @router /modify/edbList [post]
+func (this *EdbInfoController) ModifyEdbList() {
+	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 request.ModifyEdbListReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	classifyIds := strings.Split(req.EdbClassifyIds, ",")
+
+
+	if !req.SelectAll && req.EdbInfoIds == "" {
+		br.Msg = "请选择图表"
+		return
+	}
+	if req.ClassifyId < 0 {
+		br.Msg = "请选择新分类"
+		return
+	}
+
+	var condition string
+	var pars []interface{}
+	edbInfoIds := make([]int, 0)
+
+	if req.SelectAll {
+		// 已授权分类id
+		permissionClassifyIdList, err := data_manage_permission.GetUserEdbClassifyPermissionList(this.SysUser.AdminId, 0)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+			return
+		}
+		classifyIdsArr := make([]int, 0)
+		for _, v := range classifyIds {
+			if v != `` {
+				id, _ := strconv.Atoi(v)
+				classifyIdsArr = append(classifyIdsArr, id)
+			}
+		}
+
+		if len(permissionClassifyIdList) > 0 {
+			classifyIdsArr = utils.IntersectInt(permissionClassifyIdList, classifyIdsArr)
+		}
+
+		condition += " AND edb_info_type = 0 "
+		if len(classifyIdsArr) > 0 {
+			if !req.SubClassify {
+				condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(classifyIdsArr)) + ") "
+				pars = append(pars, classifyIdsArr)
+			} else {
+				classifyAll, err := data_manage.GetNormalEdbClassifyAll()
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取数据失败,Err:" + err.Error()
+					return
+				}
+				finalClassifyIds := make([]int, 0)
+				parents := data.GetEdbClassifyChildrenRecursiveByParentIds(classifyAll, classifyIds)
+				sort.Slice(parents, func(i, j int) bool {
+					return parents[i].Level < parents[i].Level
+				})
+				for _, v := range parents {
+					finalClassifyIds = append(finalClassifyIds, v.ClassifyId)
+				}
+
+				condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(finalClassifyIds)) + ") "
+				pars = append(pars, finalClassifyIds)
+			}
+		}
+		if req.KeyWord != "" {
+			condition += ` AND edb_name LIKE '%` + req.KeyWord + `%' `
+		}
+		if req.Sources != "" {
+			condition += " AND source IN(" + utils.GetOrmInReplace(len(strings.Split(req.Sources, ","))) + ") "
+			pars = append(pars, strings.Split(req.Sources, ","))
+		}
+		if req.SysUserIds != "" {
+			adminIds := strings.Split(req.SysUserIds, ",")
+			if len(adminIds) == 0 {
+				br.Msg = "请选择正确的创建人"
+				return
+			}
+			adminIdsSlice := make([]int, 0)
+			for _, adminId := range adminIds {
+				adminIdInt, e := strconv.Atoi(adminId)
+				if e != nil {
+					br.Msg = "请选择正确的创建人"
+					return
+				}
+				adminIdsSlice = append(adminIdsSlice, adminIdInt)
+			}
+			condition += "  AND sys_user_id in (" + utils.GetOrmInReplace(len(adminIds)) + ") "
+			pars = append(pars, adminIdsSlice)
+		}
+		// 获取当前账号的不可见指标
+		obj := data_manage.EdbInfoNoPermissionAdmin{}
+		confList, err := obj.GetAllListByAdminId(this.SysUser.AdminId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取不可见指标配置数据失败,Err:" + err.Error()
+			return
+		}
+		noPermissionEdbInfoIds := make([]int, 0)
+		for _, v := range confList {
+			noPermissionEdbInfoIds = append(noPermissionEdbInfoIds, v.EdbInfoId)
+		}
+		if len(noPermissionEdbInfoIds) > 0 {
+			condition += " AND edb_info_id NOT IN(" + utils.GetOrmInReplace(len(noPermissionEdbInfoIds)) + ") "
+			pars = append(pars, noPermissionEdbInfoIds)
+		}
+
+		count, err := data_manage.GetEdbInfoByConditionCount(condition, pars)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if count > 100 {
+			br.Msg = "最多选择100个"
+			return
+		}
+
+		list, err := data_manage.GetEdbInfoListByCondition(condition, pars, 0, 0, "")
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+
+
+		for _, v := range list {
+			edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+		}
+	} else {
+		edbIds := strings.Split(req.EdbInfoIds, ",")
+		if len(edbIds) == 0 {
+			br.Msg = "请选择图表"
+			return
+		}
+		for _, id := range edbIds {
+			tmp, e := strconv.Atoi(id)
+			if e != nil {
+				br.Msg = "请选择正确的分类"
+				return
+			}
+			edbInfoIds = append(edbInfoIds, tmp)
+		}
+		if len(edbInfoIds) > 100 {
+			br.Msg = "最多只能选择100个图表"
+			return
+		}
+	}
+
+	err = data_manage.UpdateEdbClassifyIdByChartInfoId(edbInfoIds, req.ClassifyId)
+	if err != nil {
+		br.Msg = "更新失败"
+		br.ErrMsg = "更新图表分类失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 0 - 1
controllers/data_manage/edb_info_calculate.go

@@ -231,7 +231,6 @@ func (this *ChartInfoController) CalculateDetail() {
 		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
-
 	fullEdb := new(data_manage.EdbInfoFullClassify)
 	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfo.ClassifyId)
 	if err != nil {

+ 1 - 1
controllers/data_manage/edb_info_refresh.go

@@ -789,7 +789,7 @@ func (c *EdbInfoController) SaveRelationEdbRefreshStatus() {
 	}
 
 	switch req.Source {
-	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联化工
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 上海钢联
 		err = data_manage.ModifyMysteelChemicalUpdateStatusByEdbInfoIds(edbIdList, isStop, edbCodeList, calculateEdbIdList)
 	default:
 		err = data_manage.EdbInfoUpdateStatusByEdbInfoId(edbIdList, isStop, calculateEdbIdList)

+ 36 - 8
controllers/data_manage/edb_info_relation.go

@@ -21,7 +21,7 @@ type EdbInfoRelationController struct {
 // RelationEdbList
 // @Title 获取被引用的指标列表接口
 // @Description 获取被引用的指标列表接口
-// @Param   Source   query   int  true       "来源:2:wind,34:钢联化工"
+// @Param   Source   query   int  true       "来源:2:wind,34:上海钢联"
 // @Param   ClassifyId   query   string  false             "分类ID,支持多选,用英文,隔开"
 // @Param   SysUserId   query   string  false       "创建人,支持多选,用英文,隔开"
 // @Param   Frequency   query   string  false       "频度,支持多选,用英文,隔开"
@@ -144,6 +144,9 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 	// 查询事件日历
 	eventInfoIds := make([]int, 0)
 
+	// 预测指标
+	predictEdbIds := make([]int, 0)
+
 	for _, v := range relationList {
 		switch v.ReferObjectType {
 		case utils.EDB_RELATION_SANDBOX:
@@ -154,9 +157,11 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			chartInfoIds = append(chartInfoIds, v.ReferObjectId)
 		case utils.EDB_RELATION_TABLE:
 			tableInfoIds = append(tableInfoIds, v.ReferObjectId)
+		case utils.EDB_RELATION_PREDICT_EDB:
+			predictEdbIds = append(predictEdbIds, v.ReferObjectId)
 		}
 	}
-	objectNameMap := make(map[int]string)
+	objectNameMap := make(map[string]string)
 	if len(sandboxIds) > 0 {
 		sandboxList, err := sandbox.GetSandboxNameByIds(sandboxIds)
 		if err != nil && err.Error() != utils.ErrNoRow() {
@@ -165,7 +170,8 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			return
 		}
 		for _, v := range sandboxList {
-			objectNameMap[v.SandboxId] = v.Name
+			name := fmt.Sprintf("%d_%d", utils.EDB_RELATION_SANDBOX, v.SandboxId)
+			objectNameMap[name] = v.Name
 		}
 	}
 
@@ -182,7 +188,8 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			return
 		}
 		for _, v := range eventList {
-			objectNameMap[v.FeCalendarMatterId] = fmt.Sprintf("%s, %s", v.MatterDate, v.ChartPermissionName)
+			name := fmt.Sprintf("%d_%d", utils.EDB_RELATION_CALENDAR, v.FeCalendarMatterId)
+			objectNameMap[name] = fmt.Sprintf("%s, %s", v.MatterDate, v.ChartPermissionName)
 		}
 	}
 
@@ -195,7 +202,8 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			return
 		}
 		for _, v := range chartList {
-			objectNameMap[v.ChartInfoId] = v.ChartName
+			name := fmt.Sprintf("%d_%d", utils.EDB_RELATION_CHART, v.ChartInfoId)
+			objectNameMap[name] = v.ChartName
 		}
 	}
 
@@ -233,16 +241,32 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			}
 		}
 		for _, v := range tableList {
+			name := fmt.Sprintf("%d_%d", utils.EDB_RELATION_TABLE, v.ExcelInfoId)
 			if v.ParentId > 0 {
 				parentName := excelParentName[v.ParentId]
-				objectNameMap[v.ExcelInfoId] = fmt.Sprintf("%s_%s", parentName, v.ExcelName)
+				objectNameMap[name] = fmt.Sprintf("%s_%s", parentName, v.ExcelName)
 			} else {
-				objectNameMap[v.ExcelInfoId] = v.ExcelName
+				objectNameMap[name] = v.ExcelName
 			}
 		}
 	}
+
+	// 查询预测指标名称
+	if len(predictEdbIds) > 0 {
+		predictList, err := data_manage.GetEdbInfoByIdList(predictEdbIds)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取预测指标信息失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range predictList {
+			name := fmt.Sprintf("%d_%d", utils.EDB_RELATION_PREDICT_EDB, v.EdbInfoId)
+			objectNameMap[name] = v.EdbName
+		}
+	}
 	for _, v := range relationList {
-		referObjectName, _ := objectNameMap[v.ReferObjectId]
+		name := fmt.Sprintf("%d_%d", v.ReferObjectType, v.ReferObjectId)
+		referObjectName, _ := objectNameMap[name]
 		tmp := &data_manage.EdbInfoRelationDetail{
 			EdbInfoRelationId:  v.EdbInfoRelationId,
 			EdbInfoId:          v.EdbInfoId,
@@ -271,6 +295,8 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 				tmp.ReferObjectTypeName = "跨品种分析"
 			case utils.CHART_SOURCE_FUTURE_GOOD, utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
 				tmp.ReferObjectTypeName = "商品价格曲线"
+			case utils.CHART_SOURCE_RANGE_ANALYSIS:
+				tmp.ReferObjectTypeName = "区间分析"
 			}
 		case utils.EDB_RELATION_TABLE:
 			switch v.ReferObjectSubType {
@@ -281,6 +307,8 @@ func (c *EdbInfoRelationController) RelationEdbListDetail() {
 			case utils.BALANCE_TABLE:
 				tmp.ReferObjectTypeName = "平衡表"
 			}
+		case utils.EDB_RELATION_PREDICT_EDB:
+			tmp.ReferObjectTypeName = "预测指标"
 		}
 		list = append(list, tmp)
 	}

+ 8 - 2
controllers/data_manage/excel/balance_table.go

@@ -17,13 +17,14 @@ import (
 	excel2 "eta/eta_api/services/excel"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/tealeg/xlsx"
 	"io/ioutil"
 	"os"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/tealeg/xlsx"
 )
 
 // GetChildTable
@@ -1419,7 +1420,12 @@ func downloadBalanceTable(excelInfo *excel.ExcelInfo, lang string) (savePath, zi
 				err = fmt.Errorf("转换成table失败,Err:" + err.Error())
 				return
 			}
-
+			tableData, err = excel2.HandleRuleToTableCell(childExcelInfo.ExcelInfoId, tableData)
+			if err != nil {
+				errMsg = "获取失败"
+				err = fmt.Errorf("处理条件格式管理规则失败,Err:%w", err)
+				return
+			}
 			// 将单个sheet的数据写入到excel
 			err = tableData.WriteExcelSheetData(xlsxFile, childExcelInfo.ExcelName)
 			if err != nil {

+ 15 - 26
controllers/data_manage/excel/excel_info.go

@@ -3,6 +3,7 @@ package excel
 import (
 	"archive/zip"
 	"encoding/json"
+	"errors"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
@@ -25,7 +26,8 @@ import (
 
 	"github.com/rdlucklib/rdluck_tools/paging"
 	"github.com/shopspring/decimal"
-	"github.com/yidane/formula"
+
+	"github.com/dengsgo/math-engine/engine"
 )
 
 // ExcelInfoController ETA表格管理
@@ -1621,7 +1623,7 @@ func (c *ExcelInfoController) GetExcelTableData() {
 		}
 		excelSource = strings.Join(sourceNameList, ",")
 		excelSourceEn = strings.Join(sourceNameEnList, ",")
-	case utils.MIXED_TABLE:
+	case utils.MIXED_TABLE, utils.BALANCE_TABLE:
 		var result request.MixedTableReq
 		err = json.Unmarshal([]byte(excelInfo.Content), &result)
 		if err != nil {
@@ -1779,30 +1781,11 @@ func (c *ExcelInfoController) Calculate() {
 		return
 	}
 
-	expression := formula.NewExpression(formulaFormStr)
-	calResult, err := expression.Evaluate()
+	calFloat, err := engine.ParseAndExec(formulaFormStr)
+	//calVal, err := calResult.Float64()
 	if err != nil {
-		br.Msg = "计算失败"
-		br.ErrMsg = "计算失败:Err:" + err.Error() + ";formulaStr:" + formulaFormStr
-		// 分母为0的报错
-		if strings.Contains(err.Error(), "divide by zero") {
-			br.Msg = "分母不能为0"
-			br.ErrMsg = "分母不能为空,计算公式:" + formulaFormStr
-			br.IsSendEmail = false
-		}
-		return
-	}
-	// 如果计算结果是NAN,那么就提示报错
-	if calResult.IsNan() {
-		br.Msg = "计算失败"
-		br.ErrMsg = "计算失败:计算结果是:NAN;formulaStr:" + formulaFormStr
-		return
-	}
-	// 计算结果格式化
-	calFloat, e := calResult.Float64()
-	if e != nil {
-		br.Msg = "计算失败"
-		br.ErrMsg = "计算失败, Err: " + e.Error()
+		err = errors.New("计算失败:获取计算值失败 Err:" + err.Error() + ";formulaStr:" + formulaFormStr)
+		fmt.Println(err)
 		return
 	}
 
@@ -2095,7 +2078,6 @@ func (c *ExcelInfoController) GetBatchEdbData() {
 					dataList[i], dataList[j] = dataList[j], dataList[i]
 				}
 			}
-
 			sourceNameList, sourceNameEnList, err := excel2.GetEdbSourceByEdbInfoIdList([]int{v})
 			if err != nil {
 				br.Msg = "自定义表格数据获取失败"
@@ -2391,6 +2373,7 @@ func (c *ExcelInfoController) GetHistoryDateData() {
 				br.ErrMsg = fmt.Sprint("获取失败,Err:", err.Error())
 				return
 			}
+
 			result = append(result, response.TableDataItem{
 				EdbInfoId: v,
 				Decimal:   req.Decimal[k],
@@ -2653,6 +2636,12 @@ func (c *ExcelInfoController) Download() {
 			br.ErrMsg = "转换成table失败,Err:" + err.Error()
 			return
 		}
+		tableData, err = excel.HandleRuleToTableCell(excelInfo.ExcelInfoId, tableData)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "处理条件格式管理规则失败,Err:" + err.Error()
+			return
+		}
 	case utils.BALANCE_TABLE: // 混合表格
 		savePath, fileName, uploadDir, err, errMsg := downloadBalanceTable(excelInfo, c.Lang)
 		if err != nil {

+ 2 - 1
controllers/data_manage/line_equation/line_chart_info.go

@@ -14,10 +14,11 @@ import (
 	"eta/eta_api/services/data/line_equation"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // LineEquationChartInfoController 拟合方程图表管理

+ 366 - 0
controllers/data_manage/manual_edb.go

@@ -1616,3 +1616,369 @@ func (c *ManualEdbController) RecordList() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// BatchSaveExcelData
+// @Title 批量保存手工数据
+// @Description 批量保存手工数据
+// @Param  request	body []models.ManualEdbExcelStyleEditReq true "type json string"
+// @Success 200
+// @router /target/edb/excel_style/batch_save [post]
+func (c *ManualEdbController) BatchSaveExcelData() {
+	br := new(models.BaseResponse).Init()
+	var err error
+	errs := make([]string, 0)
+	defer func() {
+		if len(errs) > 0 {
+			utils.FileLog.Info("编辑EXCEL数据 新增或修改数据失败,Err:" + strings.Join(errs, "\n"))
+		}
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请重新登录"
+		return
+	}
+
+	var req []data_manage.ManualEdbExcelStyleEditReq
+	err = json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	countReq := len(req)
+	if countReq <= 0 {
+		br.Msg = "无数据!"
+		br.ErrMsg = "无数据!"
+		br.IsSendEmail = false
+		return
+	}
+	if countReq <= 0 {
+		br.Msg = "超出上限,导入失败!"
+		br.ErrMsg = "超出上限,导入失败!"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 当前来说,所有指标都是同一个分类,所以取的第一个的分类id,后面如果可以做不通分类的配置的话,那就需要做微调
+	editClassifyIdList := make([]int, 0)
+	tmpClassifyIdMap := make(map[int]bool)
+	for _, item := range req {
+		classifyId := item.ClassifyId
+		if classifyId <= 0 {
+			br.Msg = "品种填写异常!"
+			br.ErrMsg = "品种填写异常!"
+			return
+		}
+		if _, ok := tmpClassifyIdMap[classifyId]; ok {
+			continue
+		}
+
+		editClassifyIdList = append(editClassifyIdList, classifyId)
+		tmpClassifyIdMap[classifyId] = true
+	}
+
+	//超管账号可以查看分类下的所有频度数据
+	userId := sysUser.AdminId
+	if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN {
+		userId = 0
+	}
+
+	//获取账户所拥有权限的分类id集合
+	classifyIdList, err := data.GetUserManualClassifyIdList(userId)
+	if err != nil {
+		br.Msg = "获取分类数据失败"
+		br.Msg = "获取拥有的分类数据失败,Err:" + err.Error()
+		return
+	}
+	for _, classifyId := range editClassifyIdList {
+		if !utils.InArrayByInt(classifyIdList, classifyId) {
+			br.Msg = "无权访问"
+			br.ErrMsg = "无权访问"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	// 指标map
+	targetMap := make(map[string]*models.Edbinfo)
+	addEdbTradeMap := make(map[string]bool)
+	updateEdbTradeMap := make(map[string]bool)
+	updateDataTradeMap := make(map[string]bool)
+	defer func() {
+		go func(addEdbTradeMap, updateEdbTradeMap, updateDataTradeMap map[string]bool) {
+			addRecordList := make([]*models.EdbinfoOpRecord, 0)
+			for tradeCode := range addEdbTradeMap {
+				addRecordList = append(addRecordList, &models.EdbinfoOpRecord{
+					TradeCode:  tradeCode,
+					Remark:     "创建指标",
+					UserId:     sysUser.AdminId,
+					UserName:   sysUser.RealName,
+					CreateTime: time.Now(),
+				})
+			}
+			for tradeCode := range updateEdbTradeMap {
+				addRecordList = append(addRecordList, &models.EdbinfoOpRecord{
+					TradeCode:  tradeCode,
+					Remark:     "编辑指标",
+					UserId:     sysUser.AdminId,
+					UserName:   sysUser.RealName,
+					CreateTime: time.Now(),
+				})
+			}
+			for tradeCode := range updateDataTradeMap {
+				addRecordList = append(addRecordList, &models.EdbinfoOpRecord{
+					TradeCode:  tradeCode,
+					Remark:     "更新数据",
+					UserId:     sysUser.AdminId,
+					UserName:   sysUser.RealName,
+					CreateTime: time.Now(),
+				})
+			}
+			if len(addRecordList) > 0 {
+				obj := models.EdbinfoOpRecord{}
+				_ = obj.MulCreate(addRecordList)
+			}
+
+			//将该指标的code加入到 “手工数据导入后刷新” 缓存
+			if utils.Re == nil {
+				for tradeCode := range updateDataTradeMap {
+					// 更新手工数据的最大最小值
+					data.ModifyManualEdbMaxMinDate(tradeCode)
+					//将该指标的code加入到 “手工数据导入后刷新” 缓存
+					err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, tradeCode)
+					if err != nil {
+						fmt.Println("CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+					}
+				}
+
+			}
+		}(addEdbTradeMap, updateEdbTradeMap, updateDataTradeMap)
+	}()
+
+	for _, item := range req {
+		if item.Unit == `` {
+			br.Msg = "单位填写异常!"
+			br.ErrMsg = "单位填写异常!"
+			return
+		}
+		if item.Frequency == `` {
+			br.Msg = "频度填写异常!"
+			br.ErrMsg = "频度填写异常!"
+			return
+		}
+		if item.ClassifyId <= 0 {
+			br.Msg = "品种填写异常!"
+			br.ErrMsg = "品种填写异常!"
+			return
+		}
+
+		// 是否新增指标
+		var isAddEdb bool
+
+		secName := strings.TrimSpace(item.EdbName)
+		frequency := strings.TrimSpace(item.Frequency)
+		unit := strings.TrimSpace(item.Unit)
+
+		manualEdbInfo, ok := targetMap[item.EdbName]
+		if !ok {
+			manualEdbInfo, err = models.GetTargetBySecName(secName)
+			if err != nil {
+				//如果是找不到该指标,那么新增指标
+				if err.Error() == utils.ErrNoRow() {
+					tmpErr := data.AddEdbInfo(secName, unit, frequency, "", sysUser.Mobile, item.ClassifyId, sysUser.AdminId, sysUser.RealName)
+					if tmpErr != nil {
+						utils.FileLogData.Error("AddEdbInfo err :%s", tmpErr.Error())
+						continue
+					}
+					isAddEdb = true
+					tmpTarget, tmpErr := models.GetTargetBySecName(secName)
+					manualEdbInfo = tmpTarget
+					targetMap[secName] = manualEdbInfo
+
+					// 指标新增
+					addEdbTradeMap[manualEdbInfo.TradeCode] = true
+				} else {
+					fmt.Println("导入数据 获取指标:Err:" + err.Error())
+				}
+			} else {
+				targetMap[secName] = manualEdbInfo
+
+			}
+		}
+
+		// 没有该分类品种权限的话,那么就过滤
+		if !utils.InArrayByInt(classifyIdList, manualEdbInfo.ClassifyId) {
+			continue
+		}
+
+		dateValueMap := make(map[string]string)
+		//取到所有数据
+		for _, dateValue := range item.Data {
+			// 检验时间格式
+			_, err := time.Parse(utils.FormatDate, dateValue.Date)
+			if err != nil {
+				continue
+			}
+			dateValueMap[dateValue.Date] = strconv.FormatFloat(dateValue.Value, 'f', -1, 64)
+		}
+
+		//操作指标,新增指标及数据等
+		{
+
+			// 如果不是新增指标,那么指标基础信息变更
+			if !isAddEdb {
+				updateCols := make([]string, 0)
+
+				if manualEdbInfo.SecName != secName {
+					// 校验是否存在相同指标名称
+					var condition string
+					var pars []interface{}
+					condition += " AND SEC_NAME=? AND left(TRADE_CODE,1)='W' AND REMARK='手动' AND TRADE_CODE != ? "
+					pars = append(pars, secName, manualEdbInfo.TradeCode)
+					count, err := models.GetManualEdbCountByCondition(condition, pars)
+					if err != nil {
+						br.Msg = `指标保存失败`
+						br.ErrMsg = `获取同名指标信息异常,ERR:` + err.Error()
+						return
+					}
+					if count > 0 {
+						br.Msg = `已存在同名指标`
+						br.ErrMsg = `已存在同名指标`
+						br.IsSendEmail = false
+						return
+					}
+
+					updateCols = append(updateCols, "SecName")
+					manualEdbInfo.SecName = secName
+				}
+
+				if manualEdbInfo.ClassifyId != item.ClassifyId {
+					updateCols = append(updateCols, "ClassifyId")
+					manualEdbInfo.ClassifyId = item.ClassifyId
+				}
+
+				if manualEdbInfo.Frequency != frequency {
+					updateCols = append(updateCols, "Frequency")
+					manualEdbInfo.Frequency = frequency
+				}
+
+				if manualEdbInfo.Unit != unit {
+					updateCols = append(updateCols, "Unit")
+					manualEdbInfo.Unit = unit
+				}
+
+				if len(updateCols) > 0 {
+					manualEdbInfo.ModifyTime = time.Now().Format(utils.FormatDateTime)
+					updateCols = append(updateCols, "ModifyTime")
+					err = manualEdbInfo.Update(updateCols)
+					if err != nil {
+						br.Msg = `指标保存失败`
+						br.ErrMsg = `指标保存失败,ERR:` + err.Error()
+						return
+					}
+
+					updateEdbTradeMap[manualEdbInfo.TradeCode] = true
+				}
+			}
+
+			// 当前已经存在的指标明细数据
+			targetDataList, tmpErr := models.GetTargetsDataList(manualEdbInfo.TradeCode)
+			if tmpErr != nil {
+				err = tmpErr
+			}
+			existDataMap := make(map[string]string)
+			deleteDataMap := make(map[string]string)
+			for _, tmpData := range targetDataList {
+				existDataMap[tmpData.Dt] = tmpData.Close
+				deleteDataMap[tmpData.Dt] = tmpData.Dt
+			}
+
+			var isUpdateData bool
+			addDataList := make([]*models.Edbdata, 0)
+
+			for createDate, closeVal := range dateValueMap {
+				if createDate == "" || closeVal == "" {
+					continue
+				}
+				//判断数据是否已经存在
+				tmpVal, ok3 := existDataMap[createDate]
+				// 不存在,那么后面进行插入
+				if !ok3 {
+					addDataList = append(addDataList, &models.Edbdata{
+						TradeCode:  manualEdbInfo.TradeCode,
+						Dt:         createDate,
+						Close:      closeVal,
+						ModifyTime: time.Now(),
+					})
+					continue
+				}
+
+				delete(deleteDataMap, createDate)
+
+				// 库里面的数据
+				tmpValDecimal, tmpErr := decimal.NewFromString(tmpVal)
+				if tmpErr != nil {
+					fmt.Println("tmpVal Parse err:", tmpErr.Error())
+					err = tmpErr
+					continue
+				}
+				// 用户填写的数据
+				closeValDecimal, tmpErr := decimal.NewFromString(closeVal)
+				if tmpErr != nil {
+					fmt.Println("closeVal Parse err:", tmpErr.Error())
+					err = tmpErr
+					continue
+				}
+				if !tmpValDecimal.Equal(closeValDecimal) {
+					isUpdateData = true
+					fmt.Println("更新数值")
+					err = models.ModifyTargetsDataByImport(manualEdbInfo.TradeCode, createDate, closeVal)
+					if err != nil {
+						fmt.Println("ModifyTargetsDataByImport err:", err.Error())
+						errs = append(errs, err.Error())
+						//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 修改数据失败:Err:"+err.Error(), utils.EmailSendToUsers)
+					}
+				}
+			}
+
+			// 新增明细数据
+			if len(addDataList) > 0 {
+				isUpdateData = true
+				err = models.OnlyMultiAddEdbdata(addDataList)
+				if err != nil {
+					fmt.Println("MultiAddEdbdata err:", err.Error())
+					errs = append(errs, err.Error())
+				}
+			}
+
+			// 删除不需要的日期数据
+			num := len(deleteDataMap)
+			if num > 0 {
+				isUpdateData = true
+				deleteDateList := make([]string, 0)
+				for date := range deleteDataMap {
+					deleteDateList = append(deleteDateList, date)
+				}
+
+				err = models.DelEdbdataByCodeAndDateList(manualEdbInfo.TradeCode, deleteDateList)
+				if err != nil {
+					fmt.Println("DelEdbdataByCodeAndDateList err:", err.Error())
+					errs = append(errs, err.Error())
+				}
+			}
+
+			// 更新数据
+			if isUpdateData {
+				updateDataTradeMap[manualEdbInfo.TradeCode] = true
+			}
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}

+ 9 - 0
controllers/data_manage/my_chart.go

@@ -1249,6 +1249,7 @@ func (this *MyChartController) MyChartList() {
 
 	myChartId, _ := this.GetInt("MyChartId")
 	isShared, _ := this.GetBool("IsShared")
+	keyword := this.GetString("Keyword")
 
 	var total int
 	page := paging.GetPaging(currentIndex, pageSize, total)
@@ -1285,6 +1286,14 @@ func (this *MyChartController) MyChartList() {
 			chartAdminId = myClassify.AdminId
 		}
 	}
+	if keyword != "" {
+		if this.Lang == utils.LANG_EN {
+			condition += " AND (b.chart_name_en like ?) "
+		} else {
+			condition += " AND (b.chart_name like ?) "
+		}
+		pars = append(pars, "%"+keyword+"%")
+	}
 
 	condition += " AND (a.admin_id = ? OR d.is_public = 1)"
 	pars = append(pars, chartAdminId)

+ 30 - 30
controllers/data_manage/mysteel_chemical_data.go

@@ -25,8 +25,8 @@ import (
 )
 
 // MysteelChemicalClassify
-// @Title 钢联化工数据分类
-// @Description 钢联化工分类接口
+// @Title 上海钢联数据分类
+// @Description 上海钢联分类接口
 // @Success 200 {object} data_manage.BaseFromMysteelChemicalClassifyItems
 // @router /mysteel_chemical/classify [get]
 func (this *EdbInfoController) MysteelChemicalClassify() {
@@ -90,8 +90,8 @@ func (this *EdbInfoController) MysteelChemicalClassify() {
 }
 
 // MysteelChemicalIndexList
-// @Title 钢联化工数据指标列表
-// @Description 钢联化工数据指标列表接口
+// @Title 上海钢联数据指标列表
+// @Description 上海钢联数据指标列表接口
 // @Success 200 {object} data_manage.BaseFromMysteelChemicalIndexResp
 // @router /mysteel_chemical/index/list [get]
 func (this *EdbInfoController) MysteelChemicalIndexList() {
@@ -181,7 +181,7 @@ func (this *EdbClassifyController) AddMysteelChemicalClassify() {
 		for _, v := range secondClassifyList {
 			_, _, tmpErrMsg := data.AddMysteelChemicalClassify(v, mysteelChemicalClassifyInfo.BaseFromMysteelChemicalClassifyId, mysteelChemicalClassifyInfo.Level, this.SysUser.AdminId, this.SysUser.RealName, this.Lang)
 			if tmpErrMsg != `` {
-				go alarm_msg.SendAlarmMsg("钢联化工-添加一级分类时,默认添加二级分类失败,一级分类名称:"+req.ClassifyName+",二级分类名称:"+v+", Err:"+tmpErrMsg, 3)
+				go alarm_msg.SendAlarmMsg("上海钢联-添加一级分类时,默认添加二级分类失败,一级分类名称:"+req.ClassifyName+",二级分类名称:"+v+", Err:"+tmpErrMsg, 3)
 				return
 			}
 		}
@@ -343,8 +343,8 @@ func (this *EdbClassifyController) DeleteMysteelChemicalClassify() {
 }
 
 // MysteelChemicalSearch
-// @Title 钢联化工指标查询
-// @Description 钢联化工指标查询
+// @Title 上海钢联指标查询
+// @Description 上海钢联指标查询
 // @Param   BaseFromMysteelChemicalClassifyId   query   int  true       "分类id"
 // @Param   Keyword   query   string  true       "名称关键词"
 // @Success 200 {object} data_manage.LzFrequency
@@ -416,10 +416,10 @@ func (this *EdbInfoController) MysteelChemicalSearch() {
 }
 
 // MysteelChemicalFrequency
-// @Title 钢联化工数据频度
-// @Description 钢联化工数据频度接口
+// @Title 上海钢联数据频度
+// @Description 上海钢联数据频度接口
 // @Param   BaseFromMysteelChemicalClassifyId   query   int  true       "分类id"
-// @Param   BaseFromMysteelChemicalIndexId   query   int  true       "钢联化工指标id"
+// @Param   BaseFromMysteelChemicalIndexId   query   int  true       "上海钢联指标id"
 // @Param   Keyword   query   string  true       "名称关键词"
 // @Success 200 {object} data_manage.LzFrequency
 // @router /mysteel_chemical/frequency [get]
@@ -495,10 +495,10 @@ func (this *EdbInfoController) MysteelChemicalFrequency() {
 }
 
 // MysteelChemicalData
-// @Title 获取钢联化工数据
-// @Description 获取钢联化工数据
+// @Title 获取上海钢联数据
+// @Description 获取上海钢联数据
 // @Param   BaseFromMysteelChemicalClassifyId   query   int  true       "分类id"
-// @Param   BaseFromMysteelChemicalIndexId   query   int  true       "钢联化工指标id"
+// @Param   BaseFromMysteelChemicalIndexId   query   int  true       "上海钢联指标id"
 // @Param   Frequency   query   string  true       "频度名称"
 // @Param   Keyword   query   string  true       "名称关键词"
 // @Param   PageSize   query   int  true       "每页数据条数"
@@ -615,10 +615,10 @@ func (this *EdbInfoController) MysteelChemicalData() {
 }
 
 // MysteelChemicalExport
-// @Title 导出钢联化工数据
-// @Description 导出钢联化工数据
+// @Title 导出上海钢联数据
+// @Description 导出上海钢联数据
 // @Param   BaseFromMysteelChemicalClassifyId   query   int  true       "分类"
-// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "钢联化工指标id"
+// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "上海钢联指标id"
 // @Param   Keyword   query   string  true       "名称关键词"
 // @Success 200  导出成功
 // @router /mysteel_chemical/export/dataList [get]
@@ -827,8 +827,8 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 }
 
 // AddMysteelChemical
-// @Title 新增钢联化工指标
-// @Description 新增钢联化工指标接口
+// @Title 新增上海钢联指标
+// @Description 新增上海钢联指标接口
 // @Param	request	body data_manage.AddEdbClassifyReq true "type json string"
 // @Success 200 Ret=200 保存成功
 // @router /mysteel_chemical/add [post]
@@ -853,7 +853,7 @@ func (this *EdbClassifyController) AddMysteelChemical() {
 		br.ErrMsg = "获取业务配置失败,Err:" + err.Error()
 		return
 	}
-	// 判断钢联化工的数据刷新方式
+	// 判断上海钢联的数据刷新方式
 	if conf["MySteelDataMethod"] == "api" {
 		if len(req.List) > 150 {
 			br.Msg = "添加指标失败,指标数量不能超过150条"
@@ -862,7 +862,7 @@ func (this *EdbClassifyController) AddMysteelChemical() {
 		ok, errMsg, err := data.HealthCheckMysteelChemicalApi()
 		if err != nil {
 			br.Msg = "添加指标失败"
-			br.ErrMsg = "钢联化工数据接口异常,Err:" + err.Error()
+			br.ErrMsg = "上海钢联数据接口异常,Err:" + err.Error()
 			return
 		}
 		if !ok {
@@ -1010,8 +1010,8 @@ func sortEdbFrequency(frequencyList []string) (newFrequencyList []string) {
 }
 
 // EditMysteelChemical
-// @Title 编辑钢联化工指标
-// @Description 新增钢联化工指标接口
+// @Title 编辑上海钢联指标
+// @Description 新增上海钢联指标接口
 // @Param	request	body data_manage.AddEdbClassifyReq true "type json string"
 // @Success 200 Ret=200 保存成功
 // @router /mysteel_chemical/edit [post]
@@ -1168,9 +1168,9 @@ func (this *EdbClassifyController) MoveMysteelChemical() {
 }
 
 // MysteelChemicalDetail
-// @Title 钢联化工指标详情
-// @Description 钢联化工指标详情接口
-// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "钢联化工指标id"
+// @Title 上海钢联指标详情
+// @Description 上海钢联指标详情接口
+// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "上海钢联指标id"
 // @Success 200 {object} data_manage.BaseFromMysteelChemicalClassifyItems
 // @router /mysteel_chemical/detail [get]
 func (this *EdbInfoController) MysteelChemicalDetail() {
@@ -1211,9 +1211,9 @@ func (this *EdbInfoController) MysteelChemicalDetail() {
 }
 
 // MysteelChemicalDetail
-// @Title 钢联化工指标详情
-// @Description 钢联化工指标详情接口
-// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "钢联化工指标id"
+// @Title 上海钢联指标详情
+// @Description 上海钢联指标详情接口
+// @Param   BaseFromMysteelChemicalIndexId   query   string  true       "上海钢联指标id"
 // @Success 200 {object} data_manage.BaseFromMysteelChemicalClassifyItems
 // @router /mysteel_chemical/refresh [get]
 func (this *EdbInfoController) MysteelChemicalRefresh() {
@@ -1746,8 +1746,8 @@ func (c *EdbInfoController) AddCheck() {
 }
 
 // MysteelChemicalSearch
-// @Title 钢联化工指标查询
-// @Description 钢联化工指标查询
+// @Title 上海钢联指标查询
+// @Description 上海钢联指标查询
 // @Param   BaseFromMysteelChemicalClassifyIds   query   string  true       "分类id"
 // @Param   Keyword   query   string  true       "名称关键词"
 // @Success 200 {object} data_manage.LzFrequency

+ 2 - 2
controllers/data_manage/predict_edb_classify.go

@@ -259,7 +259,7 @@ func (this *PredictEdbClassifyController) Edit() {
 		return
 	}
 
-	err, errMsg := data.EditEdbClassify(req.ClassifyId, req.ClassifyName, this.Lang, this.SysUser)
+	err, errMsg := data.EditEdbClassify(req.ClassifyId, req.ParentId, req.ClassifyName, this.Lang, this.SysUser)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -869,7 +869,7 @@ func (this *PredictEdbClassifyController) ClassifyTree() {
 			button := data.GetPredictEdbClassifyOpButton(this.SysUser, v.SysUserId, v.HaveOperaAuth)
 			allList[k].Button = button
 		}
-		nodeAll = data.GetClassifyTreeRecursive(allList, 0)
+		nodeAll = data.GetClassifyTreeRecursive(allList, 0, 0)
 		//根据sort值排序
 		sortList = nodeAll
 		sort.Sort(sortList)

+ 177 - 70
controllers/data_manage/predict_edb_info.go

@@ -427,31 +427,56 @@ func (this *PredictEdbInfoController) Add() {
 	ruleList := make([]request.RuleConfig, 0)
 	{
 		ruleMap := make(map[string]request.RuleConfig)
+		ruleEndNumSortMap := make(map[int]request.RuleConfig)
 		dateIntList := make([]int64, 0)
+		endNumList := make([]int, 0)
 		for _, v := range req.RuleList {
-			confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
-			if err != nil {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
-				br.IsSendEmail = false
-				return
+			if req.EndDateType == 0 {
+				confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
+				if err != nil {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
+					br.IsSendEmail = false
+					return
+				}
+				dateIntList = append(dateIntList, confEndDate.Unix())
+				ruleMap[v.EndDate] = v
+			} else {
+				if _, ok := ruleEndNumSortMap[v.EndNum]; ok {
+					br.Msg = "所选期数不能和其他时间段相同"
+					return
+				}
+				endNumList = append(endNumList, v.EndNum)
+				ruleEndNumSortMap[v.EndNum] = v
 			}
-			dateIntList = append(dateIntList, confEndDate.Unix())
-			ruleMap[v.EndDate] = v
-		}
-		sort.Slice(dateIntList, func(i, j int) bool {
-			return dateIntList[i] < dateIntList[j]
-		})
-		for _, dateInt := range dateIntList {
-			currDateTime := time.Unix(dateInt, 0)
-			item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
-			if !ok {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择"
-				br.IsSendEmail = false
-				return
+		}
+		if req.EndDateType == 0 {
+			sort.Slice(dateIntList, func(i, j int) bool {
+				return dateIntList[i] < dateIntList[j]
+			})
+			for _, dateInt := range dateIntList {
+				currDateTime := time.Unix(dateInt, 0)
+				item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
+			}
+		} else {
+			sort.Ints(endNumList)
+			for _, endNum := range endNumList {
+				item, ok := ruleEndNumSortMap[endNum]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
 			}
-			ruleList = append(ruleList, item)
 		}
 	}
 	req.RuleList = ruleList
@@ -479,6 +504,19 @@ func (this *PredictEdbInfoController) Add() {
 	}
 	resp := respItem.Data
 
+	edbInfoIdArr := make([]int, 0)
+	//查询相关的指标
+	edbMappingList, err := data_manage.GetAllCalculateByEdbInfoIdV2(resp.EdbInfoId)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取引用的指标信息失败,Err:" + err.Error()
+		return
+	}
+	for _, v := range edbMappingList {
+		edbInfoIdArr = append(edbInfoIdArr, v.FromEdbInfoId)
+	}
+	// 添加指标引用记录
+	_ = data.SavePredictEdbInfoRelation(edbInfoIdArr, resp.EdbInfoId)
 	//添加es
 	data.AddOrEditEdbInfoToEs(resp.EdbInfoId)
 
@@ -603,31 +641,56 @@ func (this *PredictEdbInfoController) Edit() {
 	ruleList := make([]request.RuleConfig, 0)
 	{
 		ruleMap := make(map[string]request.RuleConfig)
+		ruleEndNumSortMap := make(map[int]request.RuleConfig)
 		dateIntList := make([]int64, 0)
+		endNumList := make([]int, 0)
 		for _, v := range req.RuleList {
-			confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
-			if err != nil {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
-				br.IsSendEmail = false
-				return
+			if req.EndDateType == 0 {
+				confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
+				if err != nil {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
+					br.IsSendEmail = false
+					return
+				}
+				dateIntList = append(dateIntList, confEndDate.Unix())
+				ruleMap[v.EndDate] = v
+			} else {
+				if _, ok := ruleEndNumSortMap[v.EndNum]; ok {
+					br.Msg = "所选期数不能和其他时间段相同"
+					return
+				}
+				endNumList = append(endNumList, v.EndNum)
+				ruleEndNumSortMap[v.EndNum] = v
 			}
-			dateIntList = append(dateIntList, confEndDate.Unix())
-			ruleMap[v.EndDate] = v
-		}
-		sort.Slice(dateIntList, func(i, j int) bool {
-			return dateIntList[i] < dateIntList[j]
-		})
-		for _, dateInt := range dateIntList {
-			currDateTime := time.Unix(dateInt, 0)
-			item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
-			if !ok {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择"
-				br.IsSendEmail = false
-				return
+		}
+		if req.EndDateType == 0 {
+			sort.Slice(dateIntList, func(i, j int) bool {
+				return dateIntList[i] < dateIntList[j]
+			})
+			for _, dateInt := range dateIntList {
+				currDateTime := time.Unix(dateInt, 0)
+				item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
+			}
+		} else {
+			sort.Ints(endNumList)
+			for _, endNum := range endNumList {
+				item, ok := ruleEndNumSortMap[endNum]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
 			}
-			ruleList = append(ruleList, item)
 		}
 	}
 	req.RuleList = ruleList
@@ -681,6 +744,19 @@ func (this *PredictEdbInfoController) Edit() {
 	}
 	resp := respItem.Data
 
+	edbInfoIdArr := make([]int, 0)
+	//查询相关的指标
+	edbMappingList, err := data_manage.GetAllCalculateByEdbInfoIdV2(resp.EdbInfoId)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取引用的指标信息失败,Err:" + err.Error()
+		return
+	}
+	for _, v := range edbMappingList {
+		edbInfoIdArr = append(edbInfoIdArr, v.FromEdbInfoId)
+	}
+	// 添加指标引用记录
+	_ = data.SavePredictEdbInfoRelation(edbInfoIdArr, resp.EdbInfoId)
 	//修改es
 	data.AddOrEditEdbInfoToEs(resp.EdbInfoId)
 
@@ -901,6 +977,7 @@ func (this *PredictEdbInfoController) Detail() {
 				ModifyTime:       v.ModifyTime,
 				CreateTime:       v.CreateTime,
 				CalculateList:    tmpPredictEdbConfCalculateMappingDetail,
+				EndNum:           v.EndNum,
 			}
 			predictEdbConfList = append(predictEdbConfList, tmp)
 		}
@@ -1523,31 +1600,56 @@ func (this *PredictEdbInfoController) ChartDataList() {
 	ruleList := make([]request.RuleConfig, 0)
 	{
 		ruleMap := make(map[string]request.RuleConfig)
+		ruleEndNumSortMap := make(map[int]request.RuleConfig)
 		dateIntList := make([]int64, 0)
+		endNumList := make([]int, 0)
 		for _, v := range req.RuleList {
-			confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
-			if err != nil {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
-				br.IsSendEmail = false
-				return
+			if req.EndDateType == 0 {
+				confEndDate, err := time.Parse(utils.FormatDate, v.EndDate)
+				if err != nil {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
+					br.IsSendEmail = false
+					return
+				}
+				dateIntList = append(dateIntList, confEndDate.Unix())
+				ruleMap[v.EndDate] = v
+			} else {
+				if _, ok := ruleEndNumSortMap[v.EndNum]; ok {
+					br.Msg = "所选期数不能和其他时间段相同"
+					return
+				}
+				endNumList = append(endNumList, v.EndNum)
+				ruleEndNumSortMap[v.EndNum] = v
 			}
-			dateIntList = append(dateIntList, confEndDate.Unix())
-			ruleMap[v.EndDate] = v
-		}
-		sort.Slice(dateIntList, func(i, j int) bool {
-			return dateIntList[i] < dateIntList[j]
-		})
-		for _, dateInt := range dateIntList {
-			currDateTime := time.Unix(dateInt, 0)
-			item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
-			if !ok {
-				br.Msg = "配置项中时间异常,请重新选择"
-				br.ErrMsg = "配置项中时间异常,请重新选择"
-				br.IsSendEmail = false
-				return
+		}
+		if req.EndDateType == 0 {
+			sort.Slice(dateIntList, func(i, j int) bool {
+				return dateIntList[i] < dateIntList[j]
+			})
+			for _, dateInt := range dateIntList {
+				currDateTime := time.Unix(dateInt, 0)
+				item, ok := ruleMap[currDateTime.Format(utils.FormatDate)]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
+			}
+		} else {
+			sort.Ints(endNumList)
+			for _, endNum := range endNumList {
+				item, ok := ruleEndNumSortMap[endNum]
+				if !ok {
+					br.Msg = "配置项中时间异常,请重新选择"
+					br.ErrMsg = "配置项中时间异常,请重新选择"
+					br.IsSendEmail = false
+					return
+				}
+				ruleList = append(ruleList, item)
 			}
-			ruleList = append(ruleList, item)
 		}
 	}
 
@@ -1556,13 +1658,17 @@ func (this *PredictEdbInfoController) ChartDataList() {
 
 	endDateStr := `` //数据的结束日期
 	for _, v := range ruleList {
-		endDateStr = v.EndDate //预测指标的结束日期
-		confEndDate, err := time.ParseInLocation(utils.FormatDate, v.EndDate, time.Local)
-		if err != nil {
-			br.Msg = "配置项中时间异常,请重新选择"
-			br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
-			return
+		var confEndDate time.Time
+		if v.EndDate != "" {
+			endDateStr = v.EndDate //预测指标的结束日期
+			confEndDate, err = time.ParseInLocation(utils.FormatDate, v.EndDate, time.Local)
+			if err != nil {
+				br.Msg = "配置项中时间异常,请重新选择"
+				br.ErrMsg = "配置项中时间异常,请重新选择,err:" + err.Error()
+				return
+			}
 		}
+
 		// 没有数据,自己瞎测试
 		//switch v.RuleType {
 		//case 3: //3:同比
@@ -1623,6 +1729,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 			FixedValue:       0,
 			Value:            v.Value,
 			EndDate:          confEndDate,
+			EndNum:           v.EndNum,
 			ModifyTime:       time.Now(),
 			CreateTime:       time.Now(),
 			DataList:         tmpDataList,
@@ -1696,7 +1803,7 @@ func (this *PredictEdbInfoController) ChartDataList() {
 		// 获取预测数据
 		var predictMinValue, predictMaxValue float64
 
-		predictDataList, predictMinValue, predictMaxValue, err, errMsg := data.GetChartPredictEdbInfoDataListByConfList(predictEdbConfAndDataList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, sourceEdbInfoItem.Frequency, req.DataDateType, allDataList)
+		predictDataList, predictMinValue, predictMaxValue, err, errMsg := data.GetChartPredictEdbInfoDataListByConfList(predictEdbConfAndDataList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, req.EndDateType, sourceEdbInfoItem.Frequency, req.DataDateType, allDataList)
 		if err != nil {
 			br.Msg = "获取预测指标数据失败"
 			if errMsg != `` {

+ 0 - 1
controllers/data_source/guagnzhouqihuo.go

@@ -13,7 +13,6 @@ import (
 	"time"
 )
 
-// 广州期货交易所
 type DataSourceController struct {
 	controllers.BaseAuthController
 }

+ 6 - 2
controllers/data_source/icpi.go

@@ -1,6 +1,7 @@
 package data_source
 
 import (
+	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_source"
 	"eta/eta_api/utils"
@@ -13,13 +14,16 @@ import (
 )
 
 // 消费者价格指数
+type DataSourceIcpiController struct {
+	controllers.BaseAuthController
+}
 
 // ComTradeCountryList
 // @Title 获取居民消费价格指数分类
 // @Description 获取居民消费价格指数分类
 // @Success 200 {object} []data_manage.ComTradeCountryItem
 // @router /icpi/classify/list [get]
-func (this *DataSourceController) IcpiClassifyList() {
+func (this *DataSourceIcpiController) IcpiClassifyList() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
 		this.Data["json"] = br
@@ -54,7 +58,7 @@ func (this *DataSourceController) IcpiClassifyList() {
 // @Param   KeyWord   query   string  true       "关键词"
 // @Success 200 {object} data_source.BaseFromIcpiIndexView
 // @router /icpi/index/data [get]
-func (this *DataSourceController) IcpiData() {
+func (this *DataSourceIcpiController) IcpiData() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
 		this.Data["json"] = br

+ 19 - 21
controllers/data_stat/edb_source_stat.go

@@ -804,24 +804,26 @@ func (this *EdbSourceStatController) EdbUpdateFailedList() {
 
 	terminalCode := this.GetString("TerminalCode", "")
 	createTime := this.GetString("CreateTime", "")
+	condition := " and source = ? and terminal_code = ?"
+	var pars []interface{}
+	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, terminalCode)
 
-	if terminalCode == "" {
-		br.Msg = "请选择对应的终端信息"
-		return
-	}
-	terminalInfo, err := data_manage.GetEdbTerminalByTerminalCode(terminalCode)
-	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
-			br.Msg = "终端不存在"
+	terminalName := ""
+	terminalDir := ""
+	if terminalCode != "" {
+		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
 		}
-		br.Msg = "查询终端信息出错"
-		br.ErrMsg = "查询终端信息出错 Err:" + err.Error()
-		return
+		terminalName = terminalInfo.Name
+		terminalDir = terminalInfo.DirPath
 	}
-	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)
@@ -856,9 +858,9 @@ func (this *EdbSourceStatController) EdbUpdateFailedList() {
 	}
 	resp := data_stat.GetEdbUpdateFailedResp{
 		List:             list,
-		Name:             terminalInfo.Name,
+		Name:             terminalName,
 		TerminalCode:     terminalCode,
-		DirPath:          terminalInfo.DirPath,
+		DirPath:          terminalDir,
 		UpdateSuccessNum: successNum,
 		UpdateFailedNum:  failedNum,
 	}
@@ -909,16 +911,12 @@ func (this *EdbSourceStatController) EdbUpdateFailedDetailList() {
 		return
 	}
 
-	if terminalCode == "" {
-		br.Msg = "请选择对应的终端信息"
-		return
-	}
 	if frequency == "" {
 		br.Msg = "请选择对应的频度"
 		return
 	}
 
-	condition := " and source = ? and terminal_code = ? and frequency=? and data_update_failed_reason=? and data_update_result = 2"
+	condition := " and source = ? AND terminal_code = ? and frequency=? and data_update_failed_reason=? and data_update_result = 2"
 	var pars []interface{}
 	pars = append(pars, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, terminalCode, frequency, sourceUpdateFailedReason)
 

+ 0 - 1
controllers/english_report/report.go

@@ -486,7 +486,6 @@ func (this *EnglishReportController) ListReport() {
 
 	var authOk bool
 	adminMap := make(map[int]string, 0) // 编辑中的研究员姓名
-
 	total, e := models.GetEnglishReportListCount(condition, pars, companyType)
 	if e != nil {
 		br.Msg = "获取失败"

+ 24 - 3
controllers/fe_calendar/fe_calendar_matter.go

@@ -351,7 +351,8 @@ func (this *FeCalendarMatterController) PermissionList() {
 		br.ErrMsg = "获取品种列表失败, Err: " + e.Error()
 		return
 	}
-	resp := make([]*models.SimpleChartPermission, 0)
+	var resp models.FaCalendarPermissionResp
+	list := make([]*models.SimpleChartPermission, 0)
 	parentPermissions := make(map[int][]*models.SimpleChartPermission, 0)
 	for _, v := range permissions {
 		if v.ParentId > 0 {
@@ -361,12 +362,32 @@ func (this *FeCalendarMatterController) PermissionList() {
 			parentPermissions[v.ParentId] = append(parentPermissions[v.ParentId], models.FormatChartPermission2Simple(v))
 			continue
 		}
-		resp = append(resp, models.FormatChartPermission2Simple(v))
+		list = append(list, models.FormatChartPermission2Simple(v))
 	}
-	for _, v := range resp {
+	for _, v := range list {
 		v.Children = parentPermissions[v.ChartPermissionId]
 	}
+	lastEditPermissionId := 0
+	lastEditPermissionName := ""
+	// 查询最近被编辑过的品种ID
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	cond := ""
+	pars := make([]interface{}, 0)
+	order := fmt.Sprintf(`%s Desc`, fe_calendar.FeCalendarMatterCols.ModifyTime)
+	matter, e := matterOb.GetItemByCondition(cond, pars, order)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取事项列表失败, Err: " + e.Error()
+		return
+	}
+	if e == nil {
+		lastEditPermissionId = matter.ChartPermissionId
+		lastEditPermissionName = matter.ChartPermissionName
+	}
 
+	resp.CheckedPermissionId = lastEditPermissionId
+	resp.CheckedPermissionName = lastEditPermissionName
+	resp.List = list
 	br.Data = resp
 	br.Ret = 200
 	br.Success = true

+ 1867 - 0
controllers/material/material.go

@@ -0,0 +1,1867 @@
+package material
+
+import (
+	"archive/zip"
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/material"
+	"eta/eta_api/services"
+	materialService "eta/eta_api/services/material"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/h2non/filetype"
+	"github.com/rdlucklib/rdluck_tools/http"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"io/ioutil"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// MaterialController 逻辑导图
+type MaterialController struct {
+	controllers.BaseAuthController
+}
+
+// AddMaterialClassify
+// @Title 新增素材库分类
+// @Description 新增材库分类接口
+// @Param	request	body data_manage.AddChartClassifyReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /classify/add [post]
+func (this *MaterialController) AddMaterialClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req material.AddMaterialClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		br.IsSendEmail = false
+		return
+	}
+	if req.ParentId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	level := 1
+	levelPath := ""
+	if req.ParentId > 0 {
+		//查找父级分类
+		parentClassify, e := material.GetMaterialClassifyById(req.ParentId)
+		if e != nil {
+			br.Msg = "获取父级分类失败"
+			br.ErrMsg = "获取父级分类失败,Err:" + e.Error()
+			return
+		}
+		level = parentClassify.Level + 1
+		levelPath = parentClassify.LevelPath
+	}
+	var count int
+	switch this.Lang {
+	case utils.LANG_EN:
+		count, err = material.GetMaterialClassifyNameEnCount(req.ClassifyName, req.ParentId)
+	default:
+		count, err = material.GetMaterialClassifyNameCount(req.ClassifyName, req.ParentId)
+	}
+
+	if err != nil {
+		br.Msg = "判断名称是否已存在失败"
+		br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "分类名称已存在,请重新输入"
+		br.IsSendEmail = false
+		return
+	}
+
+	//获取该层级下最大的排序数
+	classify := new(material.MaterialClassify)
+	maxSort, _ := material.GetMaterialClassifyMaxSort(req.ParentId)
+	classify.ParentId = req.ParentId
+	classify.ClassifyName = req.ClassifyName
+	classify.ClassifyNameEn = req.ClassifyName
+	classify.CreateTime = time.Now()
+	classify.ModifyTime = time.Now()
+	classify.SysUserId = this.SysUser.AdminId
+	classify.SysUserRealName = this.SysUser.RealName
+	classify.Level = level
+	classify.Sort = maxSort + 1
+	classifyId, e := material.AddMaterialClassify(classify)
+	if e != nil {
+		br.Msg = "保存分类失败"
+		br.ErrMsg = "保存分类失败,Err:" + e.Error()
+		return
+	}
+	if req.ParentId > 0 {
+		levelPath = fmt.Sprintf("%s,%d", levelPath, classifyId)
+	} else {
+		levelPath = fmt.Sprintf("%d", classifyId)
+	}
+	classify.ClassifyId = int(classifyId)
+	classify.LevelPath = levelPath
+	e = classify.Update([]string{"LevelPath"})
+	if e != nil {
+		br.Msg = "保存分类失败"
+		br.ErrMsg = "保存分类失败,Err:" + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+}
+
+// EditMaterialClassify
+// @Title 修改素材库分类
+// @Description 修改素材库分类接口
+// @Param	request	body data_manage.EditChartClassifyReq true "type json string"
+// @Success 200 Ret=200 修改成功
+// @router /classify/edit [post]
+func (this *MaterialController) EditMaterialClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req material.EditMaterialClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ClassifyName == "" {
+		br.Msg = "请输入分类名称"
+		br.IsSendEmail = false
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 只允许修改分类名称
+	item, err := material.GetMaterialClassifyById(req.ClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "分类不存在"
+			return
+		}
+		br.Msg = "保存失败"
+		br.Msg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	var count int
+	updateStr := make([]string, 0)
+	switch this.Lang {
+	case utils.LANG_EN:
+		count, err = material.GetMaterialClassifyNameEnNotSelfCount(req.ClassifyId, req.ClassifyName, item.ParentId)
+		item.ClassifyNameEn = req.ClassifyName
+		updateStr = append(updateStr, "ClassifyNameEn")
+	default:
+		count, err = material.GetMaterialClassifyNameNotSelfCount(req.ClassifyId, req.ClassifyName, item.ParentId)
+		item.ClassifyName = req.ClassifyName
+		updateStr = append(updateStr, "ClassifyName")
+	}
+
+	if err != nil {
+		br.Msg = "判断名称是否已存在失败"
+		br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "分类名称已存在,请重新输入"
+		br.IsSendEmail = false
+		return
+	}
+
+	item.ModifyTime = time.Now()
+	updateStr = append(updateStr, "ModifyTime")
+	err = item.Update(updateStr)
+	if err != nil {
+		br.Msg = "保存分类失败"
+		br.ErrMsg = "保存分类失败,Err:" + err.Error()
+		return
+	}
+	//todo 测试更新子集的levelPath
+	/*levelPath := ""
+	oldLevelPath := item.LevelPath
+	if item.ParentId > 0 {
+		//查找父级分类
+		parentClassify, e := material.GetMaterialClassifyById(item.ParentId)
+		if e != nil {
+			br.Msg = "获取父级分类失败"
+			br.ErrMsg = "获取父级分类失败,Err:" + e.Error()
+			return
+		}
+		levelPath = fmt.Sprintf("%s,%d", parentClassify.LevelPath, item.ClassifyId)
+		tmpList, e := material.GetMaterialClassifyByLevelPath(oldLevelPath)
+		if e != nil {
+			br.Msg = "保存分类失败"
+			br.ErrMsg = "保存分类失败,Err:" + e.Error()
+			return
+		}
+		// 把原先的父级levePath,替换成最新的父级序列
+		for _, tmp := range tmpList {
+			tmp.LevelPath = strings.Replace(tmp.LevelPath, oldLevelPath, levelPath, -1)
+			tmp.ModifyTime = time.Now()
+			e = tmp.Update([]string{"LevelPath", "ModifyTime"})
+			if e != nil {
+				br.Msg = "保存分类失败"
+				br.ErrMsg = "保存分类失败,Err:" + e.Error()
+				return
+			}
+		}
+	} else {
+		// 只有更改了父级才需要更新levelPath
+	}*/
+
+	br.Ret = 200
+	br.Msg = "保存成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// DeleteMaterialClassifyCheck
+// @Title 删除素材库检测接口
+// @Description 删除素材库检测接口
+// @Param	request	body data_manage.ChartClassifyDeleteCheckResp true "type json string"
+// @Success 200 Ret=200 检测成功
+// @router /classify/del/check [post]
+func (this *MaterialController) DeleteMaterialClassifyCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req material.MaterialClassifyDeleteCheckReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+	var deleteStatus int
+	var tipsMsg string
+	//删除分类
+	// 查询当前的分类
+	classifyInfo, err := material.GetMaterialClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "分类不存在"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	classifyIds := strings.Split(classifyInfo.LevelPath, ",")
+	if len(classifyIds) > 0 {
+		//判断素材库分类下,是否含有素材库
+		count, e := material.GetMaterialInfoCountByClassifyIds(classifyIds)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有指标失败,Err:" + e.Error()
+			return
+		}
+
+		if count > 0 {
+			deleteStatus = 1
+			tipsMsg = "该分类下关联素材库不可删除"
+		} else {
+			if len(classifyIds) > 1 {
+				deleteStatus = 2
+				tipsMsg = "确认删除当前目录及包含的子目录吗"
+			}
+		}
+	}
+
+	if deleteStatus == 0 {
+		tipsMsg = "可删除,进行删除操作"
+	}
+
+	resp := new(material.MaterialClassifyDeleteCheckResp)
+	resp.DeleteStatus = deleteStatus
+	resp.TipsMsg = tipsMsg
+	br.Ret = 200
+	br.Msg = "检测成功"
+	br.Success = true
+	br.Data = resp
+}
+
+// DeleteMaterialClassify
+// @Title 删除素材库分类/素材库
+// @Description 删除素材库分类/素材库接口
+// @Param	request	body data_manage.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /classify/del [post]
+func (this *MaterialController) DeleteMaterialClassify() {
+	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 material.DeleteMaterialClassifyReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyId < 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 查询当前的分类
+	classifyInfo, err := material.GetMaterialClassifyById(req.ClassifyId)
+	if err != nil {
+		br.Msg = "分类不存在"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+		return
+	}
+	classifyIds := strings.Split(classifyInfo.LevelPath, ",")
+	if len(classifyIds) > 0 {
+		//判断素材库分类下,是否含有素材库
+		count, e := material.GetMaterialInfoCountByClassifyIds(classifyIds)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "分类下是否含有指标失败,Err:" + e.Error()
+			return
+		}
+
+		if count > 0 {
+			br.Msg = "该目录下存在关联指标,不可删除"
+			br.IsSendEmail = false
+			return
+		}
+
+		err = material.DeleteMaterialClassify(classifyIds)
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	//删除素材库
+	/*if req.MaterialId > 0 {
+		materialInfo, err := material.GetMaterialById(req.MaterialId)
+		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 materialInfo == nil {
+			br.Msg = "素材库已删除,请刷新页面"
+			return
+		}
+		err = materialService.DeleteMaterial(req.MaterialId)
+		if err != nil {
+			br.Msg = err.Error()
+			return
+		}
+	}*/
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// ClassifyMove
+// @Title 素材库分类移动接口
+// @Description 素材库分类移动接口
+// @Success 200 {object} data_manage.MoveChartClassifyReq
+// @router /classify/move [post]
+func (this *MaterialController) ClassifyMove() {
+	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 material.MoveMaterialClassifyReq
+	err := json.Unmarshal(this.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
+	}
+	//判断分类是否存在
+	materialClassifyInfo, err := material.GetMaterialClassifyById(req.ClassifyId)
+	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 materialClassifyInfo.ParentId != req.ParentClassifyId {
+		count, err := material.GetMaterialClassifyNameNotSelfCount(materialClassifyInfo.ClassifyId, materialClassifyInfo.ClassifyName, req.ParentClassifyId)
+		if err != nil {
+			br.Msg = "判断名称是否已存在失败"
+			br.ErrMsg = "判断名称是否已存在失败,Err:" + err.Error()
+			return
+		}
+		if count > 0 {
+			br.Msg = "移动失败,分类名称已存在"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	err, errMsg := materialService.MoveMaterialClassify(materialClassifyInfo, &req)
+	if err != nil {
+		br.Msg = errMsg
+		if errMsg == "" {
+			br.Msg = "移动失败"
+		}
+		br.ErrMsg = err.Error()
+	}
+
+	// todo权限校验
+	//移动的是分类
+	//判断上级id是否一致,如果不一致的话,那么需要移动该分类层级
+	/*updateCol := make([]string, 0)
+	if MaterialClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId != 0 {
+		parentChartClassifyInfo, err := material.GetMaterialClassifyById(req.ParentClassifyId)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
+			return
+		}
+		MaterialClassifyInfo.ParentId = parentChartClassifyInfo.ClassifyId
+		MaterialClassifyInfo.Level = parentChartClassifyInfo.Level + 1
+		MaterialClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+	} else if MaterialClassifyInfo.ParentId != req.ParentClassifyId && req.ParentClassifyId == 0 {
+		//改为一级分类
+		MaterialClassifyInfo.ParentId = req.ParentClassifyId
+		MaterialClassifyInfo.Level = 1
+		MaterialClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "ParentId", "Level", "ModifyTime")
+	}
+
+	//如果有传入 上一个兄弟节点分类id
+	if req.PrevId > 0 {
+		if req.PrevType == 1 {
+			//上一个节点是分类
+			//上一个兄弟节点
+			prevClassify, err := material.GetMaterialClassifyById(req.PrevId)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+				return
+			}
+
+			//如果是移动在两个兄弟节点之间
+			if req.NextId > 0 {
+				if req.NextType == 1 {
+					//上一个节点是分类 下一个节点是分类的情况
+					//下一个兄弟节点
+					nextClassify, err := material.GetMaterialClassifyById(req.NextId)
+					if err != nil {
+						br.Msg = "移动失败"
+						br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+						return
+					}
+					//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+					if prevClassify.Sort == nextClassify.Sort || prevClassify.Sort == MaterialClassifyInfo.Sort {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 2`
+						_ = material.UpdateMaterialClassifySortByParentId(prevClassify.ParentId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr)
+						_ = material.UpdateMaterialSortByClassifyId(prevClassify.ClassifyId, prevClassify.Sort, 0, updateSortStr)
+					} else {
+						//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+						if nextClassify.Sort-prevClassify.Sort == 1 {
+							//变更兄弟节点的排序
+							updateSortStr := `sort + 1`
+							_ = material.UpdateMaterialClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.Sort, updateSortStr)
+							_ = material.UpdateMaterialSortByClassifyId(prevClassify.ClassifyId, prevClassify.Sort, 0, updateSortStr)
+						}
+					}
+				} else {
+					//上一个节点是分类 下一个节点是素材库的情况
+					//下一个兄弟节点
+					nextChartInfo, err := material.GetMaterialById(req.NextId)
+					if err != nil {
+						br.Msg = "移动失败"
+						br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+						return
+					}
+					//如果上一个兄弟(分类)与下一个兄弟(素材库)的排序权重是一致的,那么需要将下一个兄弟(素材库)(以及下个兄弟(素材库)的同样排序权重)的排序权重+2,自己变成上一个兄弟(分类)的排序权重+1
+					if prevClassify.Sort == nextChartInfo.Sort || prevClassify.Sort == MaterialClassifyInfo.Sort {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 2`
+						_ = material.UpdateMaterialClassifySortByParentId(prevClassify.ParentId, prevClassify.ClassifyId, prevClassify.Sort, updateSortStr)
+						_ = material.UpdateMaterialSortByClassifyId(prevClassify.ClassifyId, prevClassify.Sort, 0, updateSortStr)
+					} else {
+						//如果下一个兄弟(素材库)的排序权重正好是上个兄弟节点(分类)的下一层,那么需要再加一层了
+						if nextChartInfo.Sort-prevClassify.Sort == 1 {
+							//变更兄弟节点的排序
+							updateSortStr := `sort + 1`
+							_ = material.UpdateMaterialClassifySortByParentId(prevClassify.ParentId, 0, prevClassify.ClassifyId, updateSortStr)
+							_ = material.UpdateMaterialSortByClassifyId(prevClassify.ClassifyId, prevClassify.Sort, 0, updateSortStr)
+						}
+					}
+				}
+
+			}
+
+			MaterialClassifyInfo.Sort = prevClassify.Sort + 1
+			MaterialClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+
+		} else {
+			//上一个节点是素材库
+			prevMaterial, err := material.GetMaterialById(req.PrevId)
+			if err != nil {
+				br.Msg = "移动失败"
+				br.ErrMsg = "获取上一个兄弟节点分类信息失败,Err:" + err.Error()
+				return
+			}
+
+			//如果是移动在两个兄弟节点之间
+			if req.NextId > 0 {
+				if req.NextType == 1 {
+					//上一个节点是素材库 下一个节点是分类的情况
+					//下一个兄弟节点
+					nextClassify, err := material.GetMaterialClassifyById(req.NextId)
+					if err != nil {
+						br.Msg = "移动失败"
+						br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+						return
+					}
+					//如果上一个兄弟(素材库)与下一个兄弟(分类)的排序权重是一致的,那么需要将下一个兄弟(分类)(以及下个兄弟(分类)的同样排序权重)的排序权重+2,自己变成上一个兄弟(素材库)的排序权重+1
+					if prevMaterial.Sort == nextClassify.Sort || prevMaterial.Sort == MaterialClassifyInfo.Sort {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 2`
+						_ = material.UpdateMaterialClassifySortByParentId(prevMaterial.ClassifyId, 0, prevMaterial.Sort, updateSortStr)
+						_ = material.UpdateMaterialSortByClassifyId(prevMaterial.ClassifyId, prevMaterial.Sort, prevMaterial.MaterialId, updateSortStr)
+					} else {
+						//如果下一个兄弟(分类)的排序权重正好是上个兄弟(素材库)节点的下一层,那么需要再加一层了
+						if nextClassify.Sort-prevMaterial.Sort == 1 {
+							//变更兄弟节点的排序
+							updateSortStr := `sort + 1`
+							_ = material.UpdateMaterialClassifySortByParentId(prevMaterial.ClassifyId, 0, prevMaterial.Sort, updateSortStr)
+							_ = material.UpdateMaterialSortByClassifyId(prevMaterial.ClassifyId, prevMaterial.Sort, prevMaterial.MaterialId, updateSortStr)
+						}
+					}
+				} else {
+					//上一个节点是素材库 下一个节点是素材库的情况
+					//下一个兄弟节点
+					nextChartInfo, err := material.GetMaterialById(req.NextId)
+					if err != nil {
+						br.Msg = "移动失败"
+						br.ErrMsg = "获取下一个兄弟节点分类信息失败,Err:" + err.Error()
+						return
+					}
+					//如果上一个兄弟(素材库)与下一个兄弟(分类)的排序权重是一致的,那么需要将下一个兄弟(分类)(以及下个兄弟(分类)的同样排序权重)的排序权重+2,自己变成上一个兄弟(素材库)的排序权重+1
+					if prevMaterial.Sort == nextChartInfo.Sort || prevMaterial.Sort == MaterialClassifyInfo.Sort {
+						//变更兄弟节点的排序
+						updateSortStr := `sort + 2`
+						_ = material.UpdateMaterialClassifySortByParentId(prevMaterial.ClassifyId, 0, prevMaterial.Sort, updateSortStr)
+						_ = material.UpdateMaterialSortByClassifyId(prevMaterial.ClassifyId, prevMaterial.Sort, prevMaterial.MaterialId, updateSortStr)
+					} else {
+						//如果下一个兄弟(分类)的排序权重正好是上个兄弟(素材库)节点的下一层,那么需要再加一层了
+						if nextChartInfo.Sort-prevMaterial.Sort == 1 {
+							//变更兄弟节点的排序
+							updateSortStr := `sort + 1`
+							_ = material.UpdateMaterialClassifySortByParentId(prevMaterial.ClassifyId, 0, prevMaterial.Sort, updateSortStr)
+							_ = material.UpdateMaterialSortByClassifyId(prevMaterial.ClassifyId, prevMaterial.Sort, prevMaterial.MaterialId, updateSortStr)
+						}
+					}
+				}
+
+			}
+			MaterialClassifyInfo.Sort = prevMaterial.Sort + 1
+			MaterialClassifyInfo.ModifyTime = time.Now()
+			updateCol = append(updateCol, "Sort", "ModifyTime")
+
+		}
+
+	} else {
+		firstClassify, err := material.GetFirstMaterialClassifyByParentId(MaterialClassifyInfo.ParentId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "移动失败"
+			br.ErrMsg = "获取获取当前父级分类下的排序第一条的分类信息失败,Err:" + err.Error()
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstClassify != nil && firstClassify.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = material.UpdateMaterialClassifySortByParentId(firstClassify.ParentId, firstClassify.ClassifyId-1, 0, updateSortStr)
+		}
+
+		MaterialClassifyInfo.Sort = 0 //那就是排在第一位
+		MaterialClassifyInfo.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = MaterialClassifyInfo.Update(updateCol)
+		if err != nil {
+			br.Msg = "移动失败"
+			br.ErrMsg = "修改失败,Err:" + err.Error()
+			return
+		}
+		// todo 记录整个层级的分类ID
+	}*/
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "移动成功"
+}
+
+// List
+// @Title 素材列表接口
+// @Description 素材列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ClassifyId   query   int  true       "分类id"
+// @Param   Keyword   query   string  true       "搜索关键词"
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Success 200 {object} data_manage.ChartListResp
+// @router /list [get]
+func (this *MaterialController) List() {
+	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")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	keyword := this.GetString("Keyword")
+	keyword = strings.Trim(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)
+
+	var condition string
+	var pars []interface{}
+
+	classifyIds := make([]string, 0)
+	childClassifyMap := make(map[int]*material.MaterialClassify)
+	if classifyId > 0 {
+		classifyIds = append(classifyIds, strconv.Itoa(classifyId))
+		// 查询当前的分类
+		classifyInfo, err := material.GetMaterialClassifyById(classifyId)
+		if err != nil {
+			br.Msg = "分类不存在"
+			br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+			return
+		}
+		// 获取所有子分类
+		childList, e := material.GetMaterialClassifyByLevelPath(classifyInfo.LevelPath)
+		if e != nil {
+			err = fmt.Errorf("保存分类失败,Err:" + e.Error())
+			return
+		}
+		// 把原先的父级levePath,替换成最新的父级序列
+		classifyIdMap := make(map[string]struct{})
+		for _, tmp := range childList {
+			childClassifyMap[tmp.ClassifyId] = tmp
+			//获取字符串前缀的位置
+			after, _ := strings.CutPrefix(tmp.LevelPath, classifyInfo.LevelPath)
+			fmt.Println("after", after)
+			// 拼接字符串
+			if after != "" {
+				ids := strings.Split(after, ",")
+				for _, v := range ids {
+					if _, ok := classifyIdMap[v]; !ok {
+						classifyIds = append(classifyIds, v)
+						classifyIdMap[v] = struct{}{}
+					}
+				}
+			}
+		}
+	}
+
+	if len(classifyIds) > 0 {
+		condition += " AND classify_id IN(" + utils.GetOrmInReplace(len(classifyIds)) + ") "
+		pars = append(pars, classifyIds)
+	}
+
+	if keyword != "" {
+		// 将关键词按照空格拆分,并处理查询
+		keywordList := strings.Split(keyword, " ")
+		switch this.Lang {
+		case utils.LANG_EN:
+			if len(keywordList) == 1 {
+				condition += ` AND  ( material_name_en LIKE '%` + keyword + `%' )`
+			} else {
+				condition += ` AND  (`
+				for _, key := range keywordList {
+					condition += ` material_name_en LIKE '%` + key + `%' AND`
+				}
+				condition = strings.TrimSuffix(condition, "AND")
+				condition += ` )`
+			}
+		default:
+			if len(keywordList) == 1 {
+				condition += ` AND  ( material_name LIKE '%` + keyword + `%' )`
+			} else {
+				condition += ` AND  (`
+				for _, key := range keywordList {
+					condition += ` material_name LIKE '%` + key + `%' AND`
+				}
+				condition = strings.TrimSuffix(condition, "AND")
+				condition += ` )`
+			}
+		}
+	}
+
+	//只看我的
+	isShowMe, _ := this.GetBool("IsShowMe")
+	if isShowMe {
+		condition += ` AND sys_user_id = ? `
+		pars = append(pars, sysUser.AdminId)
+	}
+
+	//获取图表信息
+	list, err := material.GetMaterialListPageByCondition(condition, pars, startSize, pageSize)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Success = true
+		br.Msg = "获取素材库信息失败"
+		br.ErrMsg = "获取素材库信息失败,Err:" + err.Error()
+		return
+	}
+
+	resp := new(material.MaterialListResp)
+	if list == nil || len(list) <= 0 || (err != nil && err.Error() == utils.ErrNoRow()) {
+		items := make([]*material.MaterialListItems, 0)
+		resp.Paging = page
+		resp.List = items
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+
+	dataCount, err := material.GetMaterialListCountByCondition(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
+}
+
+// SaveAsMaterial
+// @Title 将图表等封面上传至素材库
+// @Description 将图表等封面上传至素材库
+// @Param	request	body material.AddAndEditSandbox true "type json string"
+// @Success 200 {object} material.Material
+// @router /saveAs [post]
+func (this *MaterialController) SaveAsMaterial() {
+	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 material.SaveAsMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.MaterialName == "" {
+		br.Msg = "缺少素材库名称"
+		return
+	}
+	var exist *material.Material
+	switch this.Lang {
+	case utils.LANG_EN:
+		exist, err = material.GetMaterialByNameEn(req.MaterialName)
+	default:
+		// 判断名称是否重复
+		exist, err = material.GetMaterialByName(req.MaterialName)
+	}
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	if err == nil && exist.MaterialId > 0 {
+		br.Msg = "图片名称已存在"
+		return
+	}
+	err, errMsg := materialService.AddToMaterial(req, sysUser.AdminId, sysUser.RealName)
+	if err != nil {
+		br.Msg = "保存失败!"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	msg := "保存成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// MyChartSaveAsMaterial
+// @Title 将我的图表等封面上传至素材库
+// @Description 将图表等封面上传至素材库
+// @Param	request	body material.AddAndEditSandbox true "type json string"
+// @Success 200 {object} material.Material
+// @router /my_chart/saveAs [post]
+func (this *MaterialController) MyChartSaveAsMaterial() {
+	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 material.MyChartSaveAsMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	materialNames := make([]string, 0)
+	namesMap := make(map[string]struct{})
+	for _, v := range req.MaterialList {
+		if v.ClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			return
+		}
+		if v.MaterialName == "" {
+			br.Msg = "请填写图片名称"
+			return
+		}
+		if v.ChartInfoId <= 0 {
+			br.Msg = "请选择图表"
+			return
+		}
+		if v.MyChartId <= 0 {
+			br.Msg = "请选择我的图表"
+			return
+		}
+		if _, ok := namesMap[v.MaterialName]; ok {
+			br.Msg = "图片名称不能重复"
+			return
+		}
+		namesMap[v.MaterialName] = struct{}{}
+		materialNames = append(materialNames, v.MaterialName)
+	}
+	if len(materialNames) == 0 {
+		br.Msg = "请填写图片名称"
+		return
+	}
+	existList := make([]*material.Material, 0)
+	existNameMap := make(map[string]struct{})
+	switch this.Lang {
+	case utils.LANG_EN:
+		existList, err = material.GetMaterialByNameEns(materialNames)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if len(existList) > 0 {
+			for _, v := range existList {
+				existNameMap[v.MaterialNameEn] = struct{}{}
+			}
+		}
+	default:
+		// 判断文件名是否已存在
+		existList, err = material.GetMaterialByNames(materialNames)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if len(existList) > 0 {
+			for _, v := range existList {
+				existNameMap[v.MaterialName] = struct{}{}
+			}
+		}
+	}
+	if len(existList) > 0 {
+		br.Msg = "图片名称已存在"
+		respData := materialService.GetMyChartExistMaterialNameListMsg(existNameMap, req.MaterialList)
+		br.Data = respData
+		return
+	}
+	if len(req.MaterialList) > 30 {
+		br.Msg = "最多支持选择30个图表"
+		return
+	}
+
+	err, errMsg := materialService.MyChartAddToMaterial(req, sysUser.AdminId, sysUser.RealName)
+	if err != nil {
+		br.Msg = "保存失败!"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	msg := "保存成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// Delete
+// @Title 删除素材库
+// @Description 删除素材库接口
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /del [post]
+func (this *MaterialController) Delete() {
+	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 material.DeleteMaterial
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.MaterialId <= 0 {
+		br.Msg = "缺少素材库编号"
+		return
+	}
+
+	//删除素材库
+	err = material.DeleteByMaterialIds([]int{req.MaterialId})
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "操作失败,Err:" + err.Error()
+		return
+	}
+
+	msg := "删除成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// BatchDelete
+// @Title 批量删除素材库
+// @Description 删除素材库接口
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /batch/del [post]
+func (this *MaterialController) BatchDelete() {
+	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 material.BatchDeleteMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	deleteMaterialIds := make([]int, 0)
+	if req.IsSelectAll {
+		classifyId := req.ClassifyId
+		keyword := req.Keyword
+		isShowMe := req.IsShowMe
+		//获取图表信息
+		list, e, msg := materialService.GetBatchSelectedMaterialList(classifyId, keyword, isShowMe, sysUser, this.Lang)
+		if e != nil {
+			br.Msg = "获取素材库信息失败"
+			if msg != "" {
+				br.Msg = msg
+			}
+			br.ErrMsg = "获取素材库信息失败,Err:" + e.Error()
+			return
+		}
+		notSelectIds := make(map[int]struct{})
+		if len(req.MaterialIds) >= 0 {
+			for _, v := range req.MaterialIds {
+				notSelectIds[v] = struct{}{}
+			}
+		}
+		for _, v := range list {
+			if _, ok := notSelectIds[v.MaterialId]; !ok {
+				deleteMaterialIds = append(deleteMaterialIds, v.MaterialId)
+			}
+		}
+	} else {
+		deleteMaterialIds = req.MaterialIds
+	}
+
+	if len(deleteMaterialIds) <= 0 {
+		br.Msg = "请选择删除的素材"
+		return
+	}
+
+	//删除素材库
+	err = material.DeleteByMaterialIds(deleteMaterialIds)
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+
+	msg := "删除成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// GetMaterialVersionDetail
+// @Title 获取素材库版本数据详情(已保存的)
+// @Description 获取素材库版本数据详情接口(已保存的)
+// @Param   SandboxVersionCode   query   string  true       "素材库版本code"
+// @Success 200 {object} material.MaterialVersion
+// @router /detail [get]
+func (this *MaterialController) GetMaterialDetail() {
+	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
+	}
+
+	sandboxId, _ := this.GetInt("SandboxId")
+	if sandboxId == 0 {
+		br.Msg = "缺少素材库Id"
+		return
+	}
+
+	//获取素材库数据详情(已保存的)
+	materialInfo, err := material.GetMaterialById(sandboxId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	msg := "获取成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+	br.Data = materialInfo
+}
+
+// MaterialClassifyList
+// @Title 获取所有素材库分类接口-不包含素材库
+// @Description 获取所有素材库分类接口-不包含素材库
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
+// @Success 200 {object} data_manage.ChartClassifyListResp
+// @router /classify/list [get]
+func (this *MaterialController) MaterialClassifyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	resp := new(material.MaterialClassifyListResp)
+
+	rootList, err := material.GetMaterialClassifyByParentId(0)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	classifyAll, err := material.GetMaterialClassifyAll()
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+
+	nodeAll := make([]*material.MaterialClassifyItems, 0)
+	for k := range rootList {
+		rootNode := rootList[k]
+		materialService.MaterialClassifyItemsMakeTree(this.SysUser, classifyAll, rootNode)
+		nodeAll = append(nodeAll, rootNode)
+	}
+
+	resp.AllNodes = nodeAll
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// BatchAdd
+// @Title 批量新增素材
+// @Description 新增/编辑保存素材库接口
+// @Param	request	body material.AddAndEditSandbox true "type json string"
+// @Success 200 {object} material.Material
+// @router /batch/add [post]
+func (this *MaterialController) BatchAdd() {
+	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 material.BatchAddMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	classifyId := req.ClassifyId
+	if classifyId <= 0 {
+		br.Msg = "请选择分类"
+		return
+	}
+	materialNames := make([]string, 0)
+	namesMap := make(map[string]struct{})
+	for _, v := range req.MaterialList {
+		if v.MaterialName == "" {
+			br.Msg = "请填写图片名称"
+			return
+		}
+		if v.ImgUrl == "" {
+			br.Msg = "请上传图片"
+			return
+		}
+		if _, ok := namesMap[v.MaterialName]; ok {
+			br.Msg = "图片名称不能重复"
+			return
+		}
+		namesMap[v.MaterialName] = struct{}{}
+		materialNames = append(materialNames, v.MaterialName)
+	}
+	if len(materialNames) == 0 {
+		br.Msg = "请填写图片名称"
+		return
+	}
+	existList := make([]*material.Material, 0)
+	switch this.Lang {
+	case utils.LANG_EN:
+		existList, err = material.GetMaterialByNameEns(materialNames)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if len(existList) > 0 {
+			msg := "图片名称:"
+			for _, v := range existList {
+				msg += v.MaterialNameEn + " "
+			}
+			br.Msg = fmt.Sprintf("%s 已存在", msg)
+			return
+		}
+	default:
+		// 判断文件名是否已存在
+		existList, err = material.GetMaterialByNames(materialNames)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		if len(existList) > 0 {
+			msg := "图片名称:"
+			for _, v := range existList {
+				msg += v.MaterialName + " "
+			}
+			br.Msg = fmt.Sprintf("%s 已存在", msg)
+			return
+		}
+	}
+	err = materialService.BatchAddMaterial(req.MaterialList, classifyId, sysUser.AdminId, sysUser.RealName)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+	msg := "添加成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// Upload
+// @Title 上传素材
+// @Description 上传素材接口
+// @Param	request	body material.AddAndEditSandbox true "type json string"
+// @Success 200 {object} material.Material
+// @router /upload [post]
+func (this *MaterialController) Upload() {
+	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
+	}
+
+	f, h, err := this.GetFile("file")
+	if err != nil {
+		br.Msg = "获取资源信息失败"
+		br.ErrMsg = "获取资源信息失败,Err:" + err.Error()
+		return
+	}
+	defer f.Close() //关闭上传文件
+
+	// 不依赖于文件扩展名检查文件格式
+	fileData, e := ioutil.ReadAll(f)
+	if e != nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "读取文件失败, Err: " + e.Error()
+		return
+	}
+	pass := filetype.IsImage(fileData)
+	if !pass {
+		br.Msg = "文件格式有误"
+		br.ErrMsg = "文件格式有误"
+		return
+	}
+	ext := path.Ext(h.Filename)
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	fileName := randStr + ext
+
+	// 上传到阿里云
+	ossDir := utils.RESOURCE_DIR + "material_dir/"
+	savePath := ossDir + time.Now().Format("200601/20060102/") + fileName
+	// 上传文件
+	resourceUrl, err := services.CommonUploadToOssAndFileName(h, fileName, savePath)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	resp := new(models.UploadImgResp)
+	resp.ResourceUrl = resourceUrl
+
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+}
+
+// BatchChangeClassify
+// @Title 批量更换分类
+// @Description 批量更换分类
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /batch/changeClassify [post]
+func (this *MaterialController) BatchChangeClassify() {
+	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 material.BatchChangeClassifyMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.NewClassifyId <= 0 {
+		br.Msg = "请选择新的分类"
+		return
+	}
+	updateMaterialIds := make([]int, 0)
+	if req.IsSelectAll {
+		classifyId := req.ClassifyId
+		keyword := req.Keyword
+		isShowMe := req.IsShowMe
+		//获取图表信息
+		list, e, msg := materialService.GetBatchSelectedMaterialList(classifyId, keyword, isShowMe, sysUser, this.Lang)
+		if e != nil {
+			br.Msg = "获取素材库信息失败"
+			if msg != "" {
+				br.Msg = msg
+			}
+			br.ErrMsg = "获取素材库信息失败,Err:" + e.Error()
+			return
+		}
+		notSelectIds := make(map[int]struct{})
+		if len(req.MaterialIds) >= 0 {
+			for _, v := range req.MaterialIds {
+				notSelectIds[v] = struct{}{}
+			}
+		}
+		for _, v := range list {
+			if _, ok := notSelectIds[v.MaterialId]; !ok {
+				updateMaterialIds = append(updateMaterialIds, v.MaterialId)
+			}
+		}
+	} else {
+		updateMaterialIds = req.MaterialIds
+	}
+
+	if len(updateMaterialIds) <= 0 {
+		br.Msg = "请选择变更的素材"
+		return
+	}
+
+	// 判断新分类是否存在
+	_, err = material.GetMaterialClassifyById(req.NewClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "分类不存在"
+			return
+		}
+		br.Msg = "获取分类信息失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+	}
+	//更换分类素材库
+	err = material.UpdateClassifyByMaterialIds(updateMaterialIds, req.NewClassifyId, time.Now())
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+
+	msg := "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// ChangeClassify
+// @Title 更换分类
+// @Description 批量更换分类
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /changeClassify [post]
+func (this *MaterialController) ChangeClassify() {
+	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 material.ChangeClassifyMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.MaterialId <= 0 {
+		br.Msg = "缺少素材库编号"
+		return
+	}
+	if req.NewClassifyId <= 0 {
+		br.Msg = "请选择新的分类"
+		return
+	}
+
+	// 判断素材是否存在
+	info, err := material.GetMaterialById(req.MaterialId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "素材不存在"
+			return
+		}
+		br.Msg = "获取素材库信息失败"
+		br.ErrMsg = "获取素材库信息失败,Err:" + err.Error()
+		return
+	}
+
+	if req.NewClassifyId == info.ClassifyId {
+		br.Msg = "请选择不同的分类"
+		return
+	}
+
+	// 判断新分类是否存在
+	_, err = material.GetMaterialClassifyById(req.NewClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "分类不存在"
+			return
+		}
+		br.Msg = "获取分类信息失败"
+		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
+	}
+	info.ClassifyId = req.NewClassifyId
+	info.ModifyTime = time.Now()
+
+	//更换分类素材库
+	err = info.Update([]string{"ClassifyId", "ModifyTime"})
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+
+	msg := "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// Rename
+// @Title 素材重命名
+// @Description 素材重命名
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /rename [post]
+func (this *MaterialController) Rename() {
+	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 material.RenameMaterialReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.MaterialId <= 0 {
+		br.Msg = "缺少素材库编号"
+		return
+	}
+	if req.MaterialName == "" {
+		br.Msg = "缺少素材库名称"
+		return
+	}
+	// 判断素材是否存在
+	info, err := material.GetMaterialById(req.MaterialId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "素材不存在"
+			return
+		}
+		br.Msg = "获取素材库信息失败"
+		br.ErrMsg = "获取素材库信息失败,Err:" + err.Error()
+		return
+	}
+	var exist *material.Material
+	updateStr := make([]string, 0)
+	switch this.Lang {
+	case utils.LANG_EN:
+		// 判断名称是否重复
+		if info.MaterialNameEn == req.MaterialName {
+			br.Msg = "名称未修改"
+			return
+		}
+		exist, err = material.GetMaterialByNameEn(req.MaterialName)
+		info.MaterialNameEn = req.MaterialName
+		updateStr = append(updateStr, "MaterialNameEn")
+	default:
+		// 判断名称是否重复
+		if info.MaterialName == req.MaterialName {
+			br.Msg = "名称未修改"
+			return
+		}
+		exist, err = material.GetMaterialByName(req.MaterialName)
+		info.MaterialName = req.MaterialName
+		updateStr = append(updateStr, "MaterialName")
+	}
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取数据失败,Err:" + err.Error()
+		return
+	}
+	if err == nil && exist.MaterialId > 0 {
+		br.Msg = "图片名称已存在"
+		return
+	}
+	info.ModifyTime = time.Now()
+	updateStr = append(updateStr, "ModifyTime")
+	//更换分类素材库
+	err = info.Update(updateStr)
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+
+	msg := "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// BatchDownload
+// @Title 批量下载素材
+// @Description 批量下载素材
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /batch/download [get]
+func (this *MaterialController) BatchDownload() {
+	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 material.BatchDeleteMaterialReq
+	materialIdStr := this.GetString("MaterialIds")
+	isSelectAll, _ := this.GetBool("IsSelectAll")
+	classifyId, _ := this.GetInt("ClassifyId")
+	keyword := this.GetString("Keyword")
+	isShowMe, _ := this.GetBool("IsShowMe")
+
+	downMaterialList := make([]*material.MaterialListItems, 0)
+	materialIds := strings.Split(materialIdStr, ",")
+	var err error
+	if isSelectAll {
+		//获取图表信息
+		list, e, msg := materialService.GetBatchSelectedMaterialList(classifyId, keyword, isShowMe, sysUser, this.Lang)
+		if e != nil {
+			br.Msg = "获取素材库信息失败"
+			if msg != "" {
+				br.Msg = msg
+			}
+			br.ErrMsg = "获取素材库信息失败,Err:" + e.Error()
+			return
+		}
+		notSelectIds := make(map[int]struct{})
+		if len(materialIds) >= 0 {
+			//转成数组
+			for _, v := range materialIds {
+				id, _ := strconv.Atoi(v)
+				notSelectIds[id] = struct{}{}
+			}
+		}
+		for _, v := range list {
+			if _, ok := notSelectIds[v.MaterialId]; !ok {
+				downMaterialList = append(downMaterialList, v)
+			}
+		}
+	} else {
+		if len(materialIds) > 0 {
+			// 批量查询指标数据
+			materialIdsInt := make([]int, 0)
+			for _, v := range materialIds {
+				id, _ := strconv.Atoi(v)
+				materialIdsInt = append(materialIdsInt, id)
+			}
+			downMaterialList, err = material.GetMaterialByIds(materialIdsInt)
+			if err != nil {
+				br.Msg = "获取素材库信息失败"
+				br.ErrMsg = "获取素材库信息失败,Err:" + err.Error()
+				return
+			}
+		}
+	}
+
+	if len(downMaterialList) <= 0 {
+		br.Msg = "请选择要下载的素材"
+		return
+	}
+	// 创建zip
+	zipName := time.Now().Format(utils.FormatDateTimeUnSpace) + utils.GetRandString(5) + ".zip"
+	savePath := zipName
+	zipFile, err := os.Create(zipName)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "生成压缩文件失败, Err: " + err.Error()
+		return
+	}
+	zipWriter := zip.NewWriter(zipFile)
+	// 生成zip过程中报错关闭
+	defer func() {
+		if err != nil {
+			_ = zipWriter.Close()
+			_ = zipFile.Close()
+		}
+		_ = os.Remove(savePath)
+	}()
+
+	// 获取资源, 写入zip
+	zipFileName := ""
+	for i := range downMaterialList {
+		if downMaterialList[i].MaterialName == "" || downMaterialList[i].ImgUrl == "" {
+			continue
+		}
+		fmt.Printf("开始压缩第%d个文件\n", i+1)
+		dotIndex := strings.LastIndex(downMaterialList[i].ImgUrl, ".")
+
+		// 如果找不到点,或者点是文件名的第一个字符(不合法情况),则返回空字符串
+		if dotIndex == -1 || dotIndex == 0 {
+			continue
+		}
+
+		fileExt := downMaterialList[i].ImgUrl[dotIndex+1:]
+		ioWriter, err := zipWriter.Create(fmt.Sprintf("%s.%s", downMaterialList[i].MaterialName, fileExt))
+		if err != nil {
+			if os.IsPermission(err) {
+				br.Msg = "操作失败"
+				br.ErrMsg = "打包权限不足, Err: " + err.Error()
+				return
+			}
+			br.Msg = "操作失败"
+			br.ErrMsg = "压缩出错, Err: " + err.Error()
+			return
+		}
+
+		var content []byte
+		content, err = http.Get(downMaterialList[i].ImgUrl)
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "资源获取失败, Err: " + err.Error()
+			return
+		}
+		_, err = ioWriter.Write(content)
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "压缩文件写入失败, Err: " + err.Error()
+			return
+		}
+		if zipFileName == "" {
+			zipFileName = downMaterialList[i].MaterialName
+		}
+		fmt.Printf("第%d个文件写入成功\n", i+1)
+	}
+	// 生成zip后关闭,否则下载文件会损坏
+	_ = zipWriter.Close()
+	_ = zipFile.Close()
+
+	this.Ctx.Output.Download(savePath, fmt.Sprintf("%s.zip", zipFileName))
+
+	msg := "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.Msg = msg
+}
+
+// Download
+// @Title 下载素材
+// @Description 下载素材
+// @Param	request	body material.DeleteSandbox true "type json string"
+// @Success 200 标记成功
+// @router /download [get]
+func (this *MaterialController) Download() {
+	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
+	}
+	materialId, _ := this.GetInt("MaterialId")
+	if materialId <= 0 {
+		br.Msg = "缺少素材库编号"
+		return
+	}
+	// 判断素材是否存在
+	info, err := material.GetMaterialById(materialId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "素材不存在"
+			return
+		}
+		br.Msg = "获取素材库信息失败"
+		br.ErrMsg = "获取素材库信息失败,Err:" + err.Error()
+		return
+	}
+	if info.ImgUrl == "" {
+		br.Msg = "素材地址为空"
+		return
+	}
+
+	fileName := info.MaterialName
+	// 查找文件名中最后一个点的位置
+	dotIndex := strings.LastIndex(info.ImgUrl, ".")
+
+	// 如果找不到点,或者点是文件名的第一个字符(不合法情况),则返回空字符串
+	if dotIndex == -1 || dotIndex == 0 {
+		br.Msg = "素材地址错误"
+		return
+	}
+
+	fileName += "." + info.ImgUrl[dotIndex+1:] // 添加扩展名到文件名
+	// 获取路径中的文件名
+	urlFileName := path.Base(info.ImgUrl)
+	uploadDir := utils.STATIC_DIR + "hongze/" + time.Now().Format("20060102")
+	if e := os.MkdirAll(uploadDir, utils.DIR_MOD); e != nil {
+		br.Msg = "存储目录创建失败"
+		br.ErrMsg = "存储目录创建失败, Err:" + e.Error()
+		return
+	}
+	var content []byte
+	content, err = http.Get(info.ImgUrl)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "资源获取失败, Err: " + err.Error()
+		return
+	}
+	filePath := uploadDir + "/" + urlFileName
+	ioWriter, err := os.Create(filePath)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "文件创建失败, Err: " + err.Error()
+		return
+	}
+	n, err := ioWriter.Write(content)
+	fmt.Println("n", n)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "压缩文件写入失败, Err: " + err.Error()
+		return
+	}
+	this.Ctx.Output.Download(filePath, fileName)
+
+	defer func() {
+		_ = os.Remove(filePath)
+	}()
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "success"
+}

+ 55 - 4
controllers/ppt_english.go

@@ -92,6 +92,16 @@ func (this *PptEnglishController) ListPpt() {
 		} else {
 			list[i].IsAuth = false
 		}
+		if list[i].PptPage == 0 {
+			var pptContent []services.PPTContent
+			er := json.Unmarshal([]byte(list[i].Content), &pptContent)
+			if er != nil {
+				br.Msg = "content参数解析失败"
+				br.ErrMsg = "content参数解析失败, Err:" + er.Error()
+				return
+			}
+			list[i].PptPage = len(pptContent)
+		}
 	}
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(ppt_english.PptEnglishListResp)
@@ -126,6 +136,13 @@ func (this *PptEnglishController) AddPpt() {
 		br.Msg = "标题不能为空"
 		return
 	}
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
 
 	var newId int64
 	var msg string
@@ -190,9 +207,9 @@ func (this *PptEnglishController) AddPpt() {
 		pptInfo.Content = req.Content
 		pptInfo.CoverContent = req.CoverContent
 		pptInfo.ModifyTime = time.Now()
+		pptInfo.PptPage = len(pptContent)
 		pptInfo.TitleSetting = req.TitleSetting
-		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "TitleSetting"})
-
+		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page", "TitleSetting"})
 		msg = "保存成功"
 	}
 	resp := ppt_english.AddPptEnglishResp{
@@ -223,6 +240,15 @@ func (this *PptEnglishController) EditPpt() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	if req.FirstPage.Title == "" {
 		br.Msg = "标题不能为空"
 		return
@@ -270,8 +296,10 @@ func (this *PptEnglishController) EditPpt() {
 	pptInfo.Content = req.Content
 	pptInfo.CoverContent = req.CoverContent
 	pptInfo.ModifyTime = time.Now()
+	pptInfo.PptPage = len(pptContent)
+
 	pptInfo.TitleSetting = req.TitleSetting
-	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "TitleSetting"})
+	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page", "TitleSetting"})
 	if err != nil {
 		br.Msg = "编辑失败"
 		br.ErrMsg = "编辑失败,Err:" + err.Error()
@@ -500,6 +528,29 @@ func (this *PptEnglishController) Publish() {
 		br.ErrMsg = "发布失败,Err:" + err.Error()
 		return
 	}
+
+	pptMap, err := ppt_english.GetPptMappingByPptId(int64(req.PptId))
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := ppt_english.GetPptMappingListByGroupIdDesc(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPptEnglish(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	//添加发布记录
 	{
 		record := new(ppt_english.PptEnglishPublishRecord)
@@ -667,6 +718,7 @@ func (this *PptEnglishController) SaveLog() {
 		br.Msg = "标题不能为空"
 		return
 	}
+
 	var pageContent []services.PPTContent
 	err = json.Unmarshal([]byte(req.Content), &pageContent)
 	if err != nil {
@@ -674,7 +726,6 @@ func (this *PptEnglishController) SaveLog() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
-
 	// 获取ppt
 	item, err := ppt_english.GetPptEnglishByTitleAndId(req.FirstPage.Title, this.SysUser.AdminId)
 	if err != nil && err.Error() != utils.ErrNoRow() {

+ 11 - 1
controllers/ppt_english_group.go

@@ -321,7 +321,17 @@ func (this *PptEnglishGroupController) MoveGroupPpt() {
 		br.Msg = "请输入目录ID"
 		return
 	}
-	err = ppt.MoveGroupPptEnglish(req.GroupId, req.GroupPptId, req.PrevGroupPptId, req.NextGroupPptId, this.SysUser.AdminId)
+	// 由于是倒序, 所以需要颠倒NextGroupPptId和PrevGroupPptId的位置
+	err = ppt.MoveGroupPptEnglish(req.GroupId, req.GroupPptId, req.NextGroupPptId, req.PrevGroupPptId, this.SysUser.AdminId)
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+	// 增加人为移动的标识
+	mappingInfo := &ppt_english.PptEnglishGroupMapping{}
+	mappingInfo.GroupPptId = req.GroupPptId
+	mappingInfo.IsMoved = true
+	err = mappingInfo.Update([]string{"is_moved"})
 	if err != nil {
 		br.Msg = err.Error()
 		return

+ 58 - 4
controllers/ppt_v2.go

@@ -92,6 +92,16 @@ func (this *PptV2Controller) ListPpt() {
 		} else {
 			list[i].IsAuth = false
 		}
+		if list[i].PptPage == 0 {
+			var pptContent []services.PPTContent
+			er := json.Unmarshal([]byte(list[i].Content), &pptContent)
+			if er != nil {
+				br.Msg = "content参数解析失败"
+				br.ErrMsg = "content参数解析失败, Err:" + er.Error()
+				return
+			}
+			list[i].PptPage = len(pptContent)
+		}
 	}
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(models.PptV2ListResp)
@@ -127,6 +137,14 @@ func (this *PptV2Controller) AddPpt() {
 		return
 	}
 
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	var newId int64
 	var msg string
 	if req.PptId <= 0 {
@@ -159,6 +177,7 @@ func (this *PptV2Controller) AddPpt() {
 			AdminId:       this.SysUser.AdminId,
 			AdminRealName: this.SysUser.RealName,
 			PptVersion:    2,
+			PptPage:       len(pptContent),
 			TitleSetting:  req.TitleSetting,
 		}
 		newId, err = models.AddPptV2(pptInfo)
@@ -191,9 +210,9 @@ func (this *PptV2Controller) AddPpt() {
 		pptInfo.Content = req.Content
 		pptInfo.CoverContent = req.CoverContent
 		pptInfo.ModifyTime = time.Now()
+		pptInfo.PptPage = len(pptContent)
 		pptInfo.TitleSetting = req.TitleSetting
-		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "TitleSetting"})
-
+		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page", "TitleSetting"})
 		msg = "保存成功"
 	}
 	resp := models.AddPptResp{
@@ -228,6 +247,15 @@ func (this *PptV2Controller) EditPpt() {
 		br.Msg = "标题不能为空"
 		return
 	}
+
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	item, err := models.GetPptV2ByTitleAndId(req.FirstPage.Title, this.SysUser.AdminId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
 		br.Msg = "获取数据异常!"
@@ -271,8 +299,10 @@ func (this *PptV2Controller) EditPpt() {
 	pptInfo.Content = req.Content
 	pptInfo.CoverContent = req.CoverContent
 	pptInfo.ModifyTime = time.Now()
+	pptInfo.PptPage = len(pptContent)
+
 	pptInfo.TitleSetting = req.TitleSetting
-	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "TitleSetting"})
+	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page", "TitleSetting"})
 	if err != nil {
 		br.Msg = "编辑失败"
 		br.ErrMsg = "编辑失败,Err:" + err.Error()
@@ -500,6 +530,29 @@ func (this *PptV2Controller) Publish() {
 		br.ErrMsg = "发布失败,Err:" + err.Error()
 		return
 	}
+
+	pptMap, err := models.GetPptMappingByPptId(int64(req.PptId))
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := models.GetPptMappingListByGroupId(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPpt(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	//添加发布记录
 	{
 		record := new(models.PptV2PublishRecord)
@@ -688,7 +741,8 @@ func (this *PptV2Controller) SaveLog() {
 	pptItem.ModifyTime = time.Now()
 	pptItem.TitleSetting = req.TitleSetting
 	pptItem.PptPage = len(pptContent)
-	err = pptItem.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "TitleSetting", "ppt_page"})
+
+	err = pptItem.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "ppt_page", "TitleSetting"})
 
 	// 将更新后的PPT, 置顶
 	pptMap, err := models.GetPptMappingByPptId(int64(req.PptId))

+ 11 - 1
controllers/ppt_v2_group.go

@@ -324,7 +324,17 @@ func (this *PptV2GroupController) MoveGroupPpt() {
 		br.Msg = "请输入目录ID"
 		return
 	}
-	err = ppt.MoveGroupPpt(req.GroupId, req.GroupPptId, req.PrevGroupPptId, req.NextGroupPptId, this.SysUser.AdminId)
+	// 由于是倒序, 所以需要颠倒NextGroupPptId和PrevGroupPptId的位置
+	err = ppt.MoveGroupPpt(req.GroupId, req.GroupPptId, req.NextGroupPptId, req.PrevGroupPptId, this.SysUser.AdminId)
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+	// 增加人为移动的标识
+	mappingInfo := &models.PptV2GroupMapping{}
+	mappingInfo.GroupPptId = req.GroupPptId
+	mappingInfo.IsMoved = true
+	err = mappingInfo.Update([]string{"is_moved"})
 	if err != nil {
 		br.Msg = err.Error()
 		return

+ 1 - 0
controllers/report.go

@@ -1865,6 +1865,7 @@ func (this *ReportController) SendMsg() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+
 	if req.ReportId <= 0 {
 		br.Msg = "参数错误"
 		br.ErrMsg = "参数错误"

+ 101 - 120
controllers/report_chapter.go

@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/report"
+	"eta/eta_api/models/system"
 	"eta/eta_api/services"
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
@@ -332,38 +333,12 @@ func (this *ReportController) EditDayWeekChapter() {
 	}
 
 	// 操作权限校验
-	{
-		// 如果不是创建人,那么就要去查看是否授权
-		if reportInfo.AdminId != sysUser.AdminId {
-			// 授权用户权限校验
-			chapterGrantObj := report.ReportChapterGrant{}
-			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
-			if tmpErr != nil {
-				if tmpErr.Error() == utils.ErrNoRow() {
-					br.Msg = "没有权限"
-					br.ErrMsg = "没有权限"
-					br.IsSendEmail = false
-					return
-				}
-				br.Msg = "获取章节id授权用户失败"
-				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
-				return
-			}
-		}
-
-		// 标记更新中
-		{
-			markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
-			if err != nil {
-				br.Msg = err.Error()
-				return
-			}
-			if markStatus.Status == 1 {
-				br.Msg = markStatus.Msg
-				br.IsSendEmail = false
-				return
-			}
-		}
+	hasAuth, msg, errMsg, isSendEmail := checkOpPermission(sysUser, reportInfo, reportChapterInfo, true, this.Lang)
+	if !hasAuth {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		br.IsSendEmail = isSendEmail
+		return
 	}
 
 	if reportInfo.State == 2 {
@@ -530,38 +505,12 @@ func (this *ReportController) DelChapter() {
 	}
 
 	// 操作权限校验
-	{
-		// 如果不是创建人,那么就要去查看是否授权
-		if reportInfo.AdminId != sysUser.AdminId {
-			// 授权用户权限校验
-			chapterGrantObj := report.ReportChapterGrant{}
-			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
-			if tmpErr != nil {
-				if tmpErr.Error() == utils.ErrNoRow() {
-					br.Msg = "没有权限"
-					br.ErrMsg = "没有权限"
-					br.IsSendEmail = false
-					return
-				}
-				br.Msg = "获取章节id授权用户失败"
-				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
-				return
-			}
-		}
-
-		// 标记更新中
-		{
-			markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
-			if err != nil {
-				br.Msg = err.Error()
-				return
-			}
-			if markStatus.Status == 1 {
-				br.Msg = markStatus.Msg
-				br.IsSendEmail = false
-				return
-			}
-		}
+	hasAuth, msg, errMsg, isSendEmail := checkOpPermission(sysUser, reportInfo, reportChapterInfo, true, this.Lang)
+	if !hasAuth {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		br.IsSendEmail = isSendEmail
+		return
 	}
 
 	if reportInfo.State == 2 {
@@ -572,7 +521,7 @@ func (this *ReportController) DelChapter() {
 	}
 
 	// 删除章节
-	err, errMsg := services.DelChapter(reportInfo, reportChapterInfo, sysUser)
+	err, errMsg = services.DelChapter(reportInfo, reportChapterInfo, sysUser)
 	if err != nil {
 		br.Msg = "删除失败"
 		if errMsg != "" {
@@ -629,7 +578,7 @@ func (this *ReportController) GetReportChapterList() {
 	}
 
 	// 权限校验
-	isAuth, err := services.CheckReportAuthByReportChapterInfo(sysUser.AdminId, reportInfo.AdminId, reportId)
+	isAuth, err := services.CheckReportAuthByReportId(sysUser, reportInfo.AdminId, reportId)
 	if err != nil {
 		br.Msg = "获取报告权限失败"
 		br.ErrMsg = "获取报告权限失败,Err:" + err.Error()
@@ -757,7 +706,7 @@ func (this *ReportController) GetReportChapterList() {
 			}
 
 			// 报告章节的操作权限
-			tmpChapterItem.IsAuth = services.CheckChapterAuthByAdminIdList(sysUser.AdminId, reportInfo.AdminId, tmpChapterIdGrandList)
+			tmpChapterItem.IsAuth = services.CheckChapterAuthByAdminIdList(sysUser, reportInfo.AdminId, tmpChapterIdGrandList)
 
 			resp = append(resp, tmpChapterItem)
 		}
@@ -811,7 +760,7 @@ func (this *ReportController) GetDayWeekChapter() {
 	}
 
 	// 权限校验
-	isAuth, err := services.CheckReportAuthByReportChapterInfo(sysUser.AdminId, reportInfo.AdminId, reportInfo.Id)
+	isAuth, err := services.CheckReportAuthByReportId(sysUser, reportInfo.AdminId, reportInfo.Id)
 	if err != nil {
 		br.Msg = "获取报告权限失败"
 		br.ErrMsg = "获取报告权限失败,Err:" + err.Error()
@@ -986,24 +935,12 @@ func (this *ReportController) EditChapterTrendTag() {
 	}
 
 	// 操作权限校验
-	{
-		// 如果不是创建人,那么就要去查看是否授权
-		if reportInfo.AdminId != sysUser.AdminId {
-			// 授权用户权限校验
-			chapterGrantObj := report.ReportChapterGrant{}
-			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(chapterInfo.ReportChapterId, sysUser.AdminId)
-			if tmpErr != nil {
-				if tmpErr.Error() == utils.ErrNoRow() {
-					br.Msg = "没有权限"
-					br.ErrMsg = "没有权限"
-					br.IsSendEmail = false
-					return
-				}
-				br.Msg = "获取章节id授权用户失败"
-				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
-				return
-			}
-		}
+	hasAuth, msg, errMsg, isSendEmail := checkOpPermission(sysUser, reportInfo, chapterInfo, false, this.Lang)
+	if !hasAuth {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		br.IsSendEmail = isSendEmail
+		return
 	}
 
 	// 更新章节标签
@@ -1129,7 +1066,7 @@ func (this *ReportController) VoiceUpload() {
 	}
 
 	// 权限校验
-	isAuth, err := services.CheckChapterAuthByReportChapterInfo(this.SysUser.AdminId, reportInfo.AdminId, reportChapterInfo)
+	isAuth, err := services.CheckChapterAuthByReportChapterInfo(this.SysUser, reportInfo.AdminId, reportChapterInfo)
 	if err != nil {
 		br.Msg = "获取报告权限失败"
 		br.ErrMsg = "获取报告权限失败,Err:" + err.Error()
@@ -1357,7 +1294,7 @@ func (this *ReportController) PublishDayWeekReportChapter() {
 	}
 
 	var publishTime time.Time
-	if reportInfo.MsgIsSend == 1 && reportInfo.PublishTime.IsZero() { //如果报告曾经发布过,并且已经发送过模版消息,则章节的发布时间为报告的发布时间
+	if reportInfo.MsgIsSend == 1 && !reportInfo.PublishTime.IsZero() { //如果报告曾经发布过,并且已经发送过模版消息,则章节的发布时间为报告的发布时间
 		publishTime = reportInfo.PublishTime
 	} else {
 		publishTime = time.Now()
@@ -1557,38 +1494,12 @@ func (this *ReportController) EditChapterTitle() {
 	}
 
 	// 操作权限校验
-	{
-		// 如果不是创建人,那么就要去查看是否授权
-		if reportInfo.AdminId != sysUser.AdminId {
-			// 授权用户权限校验
-			chapterGrantObj := report.ReportChapterGrant{}
-			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
-			if tmpErr != nil {
-				if tmpErr.Error() == utils.ErrNoRow() {
-					br.Msg = "没有权限"
-					br.ErrMsg = "没有权限"
-					br.IsSendEmail = false
-					return
-				}
-				br.Msg = "获取章节id授权用户失败"
-				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
-				return
-			}
-		}
-
-		// 标记更新中
-		{
-			markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
-			if err != nil {
-				br.Msg = err.Error()
-				return
-			}
-			if markStatus.Status == 1 {
-				br.Msg = markStatus.Msg
-				br.IsSendEmail = false
-				return
-			}
-		}
+	hasAuth, msg, errMsg, isSendEmail := checkOpPermission(sysUser, reportInfo, reportChapterInfo, true, this.Lang)
+	if !hasAuth {
+		br.Msg = msg
+		br.ErrMsg = errMsg
+		br.IsSendEmail = isSendEmail
+		return
 	}
 
 	if reportInfo.State == 2 {
@@ -1726,3 +1637,73 @@ func (this *ReportController) CancelPublishReportChapter() {
 	br.Success = true
 	br.Msg = "撤销成功"
 }
+
+// checkOpPermission
+// @Description: 操作权限校验
+// @author: Roc
+// @datetime 2024-11-12 09:58:34
+// @param sysUser *system.Admin
+// @param reportInfo *models.Report
+// @param reportChapterInfo *models.ReportChapter
+// @param isMarkStatus bool
+// @param lang string
+// @return hasAuth bool
+// @return msg string
+// @return errMsg string
+// @return isSendEmail bool
+func checkOpPermission(sysUser *system.Admin, reportInfo *models.Report, reportChapterInfo *models.ReportChapter, isMarkStatus bool, lang string) (hasAuth bool, msg, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+
+	// 权限校验
+	isAuth, err := services.CheckChapterAuthByReportChapterInfo(sysUser, reportInfo.AdminId, reportChapterInfo)
+	if err != nil {
+		msg = "获取报告权限失败"
+		errMsg = "获取报告权限失败,Err:" + err.Error()
+		return
+	}
+	if !isAuth {
+		msg = "没有权限"
+		errMsg = "没有权限"
+		isSendEmail = false
+		return
+	}
+
+	// 如果不是创建人,那么就要去查看是否授权
+	//if reportInfo.AdminId != sysUser.AdminId && !utils.IsAdminRole(sysUser.RoleTypeCode) {
+	//	// 授权用户权限校验
+	//	chapterGrantObj := report.ReportChapterGrant{}
+	//	_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
+	//	if tmpErr != nil {
+	//		if tmpErr.Error() == utils.ErrNoRow() {
+	//			msg = "没有权限"
+	//			errMsg = "没有权限"
+	//			isSendEmail = false
+	//			return
+	//		}
+	//		msg = "获取章节id授权用户失败"
+	//		errMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
+	//		return
+	//	}
+	//}
+
+	// 标记更新中
+	if isMarkStatus {
+		markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, lang)
+		if err != nil {
+			msg = err.Error()
+			errMsg = err.Error()
+			return
+		}
+		if markStatus.Status == 1 {
+			msg = markStatus.Msg
+			errMsg = markStatus.Msg
+			isSendEmail = false
+			return
+		}
+	}
+
+	// 有权限
+	hasAuth = true
+
+	return
+}

+ 1 - 0
controllers/report_chapter_type.go

@@ -161,6 +161,7 @@ func (this *ReportChapterTypeController) Add() {
 	item.IsSet = 0
 	item.ReportChapterTypeKey = req.ReportChapterTypeName
 	item.TickerTitle = req.ReportChapterTypeName
+	item.IsShow = 1
 
 	if e = item.Create(); e != nil {
 		br.Msg = "操作失败"

+ 123 - 16
controllers/report_v2.go

@@ -12,13 +12,14 @@ import (
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"html"
 	"io"
 	"os"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // ListReport
@@ -134,11 +135,17 @@ func (this *ReportController) ListReport() {
 		pars = append(pars, 1)
 		condition += `  AND a.state in (2,6) `
 	case 3:
-		condition += ` AND a.admin_id = ? `
-		pars = append(pars, this.SysUser.AdminId)
+		// 如果不是超管,那么就看自己有权限的
+		if !utils.IsAdminRole(this.SysUser.RoleTypeCode) {
+			condition += ` AND a.admin_id = ? `
+			pars = append(pars, this.SysUser.AdminId)
+		}
 	case 2:
-		condition += ` AND (a.admin_id = ? or b.admin_id = ?) `
-		pars = append(pars, this.SysUser.AdminId, this.SysUser.AdminId)
+		// 如果不是超管,那么就看自己有权限的
+		if !utils.IsAdminRole(this.SysUser.RoleTypeCode) {
+			condition += ` AND (a.admin_id = ? or b.admin_id = ?) `
+			pars = append(pars, this.SysUser.AdminId, this.SysUser.AdminId)
+		}
 	}
 
 	// 共享报告需要连表查询,所以需要单独写
@@ -481,7 +488,12 @@ func (this *ReportController) Add() {
 	item.IsPublicPublish = req.IsPublicPublish
 	item.ReportCreateTime = time.Now()
 
-	err, errMsg := services.AddReportAndChapter(item, req.InheritReportId, req.GrantAdminIdList)
+	reportDate := time.Now()
+	t, _ := time.ParseInLocation(utils.FormatDate, req.CreateTime, time.Local)
+	if !t.IsZero() {
+		reportDate = t
+	}
+	err, errMsg := services.AddReportAndChapter(item, req.InheritReportId, req.GrantAdminIdList, reportDate)
 	if err != nil {
 		br.Msg = "保存失败"
 		if errMsg != "" {
@@ -820,6 +832,7 @@ func (this *ReportController) SaveReportContent() {
 // @Param   ClassifyIdFirst   query   int  true       "一级分类id"
 // @Param   ClassifyIdSecond   query   int  true       "二级分类id"
 // @Param   ClassifyIdThird   query   int  true       "三级分类id"
+// @Param   State   query   string  true       "报告状态,多状态用英文,隔开"
 // @Success 200 {object} models.ReportListResp
 // @router /list/authorized [get]
 func (this *ReportController) AuthorizedListReport() {
@@ -834,6 +847,7 @@ func (this *ReportController) AuthorizedListReport() {
 	classifyIdFirst, _ := this.GetInt("ClassifyIdFirst", 0)
 	classifyIdSecond, _ := this.GetInt("ClassifyIdSecond", 0)
 	classifyIdThird, _ := this.GetInt("ClassifyIdThird", 0)
+	stateStr := this.GetString("State")
 
 	var startSize int
 	if pageSize <= 0 {
@@ -894,21 +908,30 @@ func (this *ReportController) AuthorizedListReport() {
 		pars = utils.GetLikeKeywordPars(pars, keyword, 1)
 	}
 
+	if stateStr != `` {
+		stateStrList := strings.Split(stateStr, ",")
+		condition += ` AND a.state in (` + utils.GetOrmInReplace(len(stateStrList)) + `) `
+		pars = append(pars, stateStrList)
+	}
+
 	var err error
 	var total int
 
-	orCondition := `AND ( (a.is_public_publish = ? AND a.state in (2,6)) or a.admin_id = ? `
-	pars = append(pars, 1, this.SysUser.AdminId)
+	// 如果不是超管,那么只能看到有权限的报告
+	if !utils.IsAdminRole(this.SysUser.RoleTypeCode) {
+		orCondition := `AND ( (a.is_public_publish = ? AND a.state in (2,6)) or a.admin_id = ? `
+		pars = append(pars, 1, this.SysUser.AdminId)
 
-	// 当前用户有权限的报告id列表
-	num := len(grantReportIdList)
-	if num > 0 {
-		orCondition += ` OR a.id in (` + utils.GetOrmInReplace(num) + `)`
-		pars = append(pars, grantReportIdList)
-	}
-	orCondition += ` ) `
+		// 当前用户有权限的报告id列表
+		num := len(grantReportIdList)
+		if num > 0 {
+			orCondition += ` OR a.id in (` + utils.GetOrmInReplace(num) + `)`
+			pars = append(pars, grantReportIdList)
+		}
+		orCondition += ` ) `
 
-	condition += orCondition
+		condition += orCondition
+	}
 
 	total, err = models.GetReportListCountByAuthorized(condition, pars)
 	if err != nil {
@@ -1650,6 +1673,90 @@ func (this *ReportController) CancelApprove() {
 	br.Msg = "操作成功"
 }
 
+// ShareGenerate
+// @Title 获取复制链接
+// @Description 获取复制链接
+// @Param	request	body models.ReportShartLinkReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /share/generate [post]
+func (this *ReportController) ShareGenerate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.ReportShartUrlReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	link, err := services.GetReportShareUrlToken(req, this.SysUser.AdminId)
+	if err != nil || link == "" {
+		br.Msg = "复制链接失败"
+		br.ErrMsg = "获取复制链接失败, Err: " + err.Error()
+		return
+	}
+
+	resp := new(models.ReportShartUrlResp)
+	resp.UrlToken = link
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ShareTransform
+// @Title 获取原始链接
+// @Description 获取原始链接
+// @Param	Token   query   string  true    "复制链接的token"
+// @Success 200 Ret=200 操作成功
+// @router /share/link [get]
+func (this *ReportCommonController) ShareTransform() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	token := this.GetString("Token")
+
+	link, msg, err := services.TransfromToOriginUrl(token)
+	if err != nil {
+		if msg == "" {
+			msg = "获取失败"
+		}
+
+		htmlTpl := `
+		<!DOCTYPE html>
+		<html lang="zh">
+		<head>
+		    <meta charset="UTF-8">
+		    <title>链接失效</title>
+		</head>
+		<body>
+		    <h1>链接失效</h1>
+		    <p>%s</p>
+		</body>
+		</html>
+		`
+		htmlTpl = fmt.Sprintf(htmlTpl, msg)
+		this.Ctx.Output.SetStatus(404)
+		this.Ctx.Output.Body([]byte(htmlTpl))
+		utils.FileLog.Info("获取复制链接失败, Err: " + err.Error())
+		return
+	}
+
+	this.Ctx.Redirect(302, link)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
 // init
 // @Description: 修复历史报告数据
 // @author: Roc

+ 284 - 0
controllers/residual_analysis/residual_analysis_controller.go

@@ -0,0 +1,284 @@
+package residual_analysis
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/residual_analysis_model"
+	"eta/eta_api/services/residual_analysis_service"
+)
+
+// ResidualAnalysisController 残差分析
+type ResidualAnalysisController struct {
+	controllers.BaseAuthController
+}
+
+// ResidualAnalysisPreview
+// @Title 残差分析预览
+// @Description 残差分析预览
+// @Success 200 {object} residual_analysis_model.ResidualAnalysisResp
+// @router /residual/analysis/preview [post]
+func (this *ResidualAnalysisController) ResidualAnalysisPreview() {
+	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 residual_analysis_model.ResidualAnalysisReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.EdbInfoIdA == req.EdbInfoIdB {
+		br.Msg = "自变量指标和因变量指标不能相同"
+		br.ErrMsg = "自变量指标和因变量指标不能相同"
+		return
+	}
+
+	resp, err := residual_analysis_service.ResidualAnalysisPreview(req)
+	if err != nil {
+		br.Ret = 403
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ContrastPreview
+// @Title 对比指标预览
+// @Description 对比指标预览
+// @Success 200 {object} residual_analysis_model.ResidualAnalysisChartEdbInfoMapping
+// @router /contrast/preview [get]
+func (this *ResidualAnalysisController) ContrastPreview() {
+	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")
+	if IndexCode == "" {
+		br.Ret = 403
+		br.Msg = "IndexCode不能为空"
+		br.ErrMsg = "IndexCode不能为空"
+		return
+	}
+
+	resp, err := residual_analysis_service.ContrastPreview(IndexCode)
+	if err != nil {
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// SaveResidualAnalysis
+// @Title 保存残差分析指标
+// @Description 保存残差分析指标
+// @Success 200
+// @router /save/residual/analysis [post]
+func (this *ResidualAnalysisController) SaveResidualAnalysis() {
+	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 residual_analysis_model.ResidualAnalysisIndexSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ClassifyId == 0 {
+		br.Msg = "分类id不能为空"
+		br.ErrMsg = "分类id不能为空"
+		return
+	}
+
+	if req.Source == 0 {
+		br.Msg = "来源不能为空"
+		br.ErrMsg = "来源不能为空"
+		return
+	}
+
+	err = residual_analysis_service.SaveResidualAnalysis(req, sysUser)
+	if err != nil {
+		br.Ret = 403
+		br.Msg = err.Error()
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "添加成功"
+}
+
+// SaveResidualAnalysisConfig
+// @Title 保存残差指标配置
+// @Description 保存残差指标配置
+// @Success 200
+// @router /save/residual/analysis/config [post]
+func (this *ResidualAnalysisController) SaveResidualAnalysisConfig() {
+	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 residual_analysis_model.ResidualAnalysisReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	configId, err := residual_analysis_service.SaveResidualAnalysisConfig(req, sysUser)
+	if err != nil {
+		br.Ret = 403
+		br.Msg = "保存失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "添加成功"
+	br.Data = configId
+}
+
+// ResidualAnalysisDetail
+// @Title 残差分析指标详情
+// @Description 残差分析指标详情
+// @Success 200 {object} []*data_manage.EdbInfoList
+// @router /residual/analysis/detail [get]
+func (this *ResidualAnalysisController) ResidualAnalysisDetail() {
+	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
+	}
+
+	EdbInfoId, err := this.GetInt("EdbInfoId")
+	if err != nil {
+		br.Msg = "EdbInfoId参数异常!"
+		br.ErrMsg = "EdbInfoId参数解析失败,Err:" + err.Error()
+	}
+	if EdbInfoId <= 0 {
+		br.Msg = "EdbInfoId参数异常!"
+		br.ErrMsg = "EdbInfoId参数异常!"
+	}
+
+	resp, err := residual_analysis_service.ResidualAnalysisDetail(EdbInfoId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		br.Ret = 403
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// CheckResidualAnalysisExist
+// @Title 校验残差指标是否存在
+// @Description 校验残差指标是否存在
+// @Success 200 {object}
+// @router /check/residual/analysis/exist [get]
+func (this *ResidualAnalysisController) CheckResidualAnalysisExist() {
+	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
+	}
+
+	configId, err := this.GetInt("ConfigId")
+	if err != nil {
+		br.Msg = "EdbInfoId参数异常!"
+		br.ErrMsg = "EdbInfoId参数解析失败,Err:" + err.Error()
+	}
+	if configId <= 0 {
+		br.Msg = "ConfigId参数异常!"
+		br.ErrMsg = "ConfigId参数异常!"
+	}
+
+	resp, err := residual_analysis_service.CheckResidualAnalysisExist(configId)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		br.Ret = 403
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 35 - 20
controllers/sandbox/sandbox.go

@@ -2394,16 +2394,21 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		return
 	}
 	edbList := make([]*sandbox.SandboxLinkCheckItem, 0)
-	for _, v := range edbInfoList {
-		tmp := &sandbox.SandboxLinkCheckItem{
-			Id:         v.EdbInfoId,
-			Name:       v.EdbName,
-			UniqueCode: v.UniqueCode,
-			ClassifyId: v.ClassifyId,
+	for _, id := range req.EdbInfoIdList {
+		for _, v := range edbInfoList {
+			if v.EdbInfoId == id {
+				tmp := &sandbox.SandboxLinkCheckItem{
+					Id:         v.EdbInfoId,
+					Name:       v.EdbName,
+					UniqueCode: v.UniqueCode,
+					ClassifyId: v.ClassifyId,
+				}
+				edbList = append(edbList, tmp)
+			}
 		}
-		edbList = append(edbList, tmp)
 	}
 
+
 	chartList, err := data_manage.GetChartInfoByIdList(req.ChartInfoIdList)
 	if err != nil {
 		br.Msg = `获取失败`
@@ -2411,16 +2416,21 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		return
 	}
 	chartListTmp := make([]*sandbox.SandboxLinkCheckItem, 0)
-	for _, v := range chartList {
-		tmp := &sandbox.SandboxLinkCheckItem{
-			Id:         v.ChartInfoId,
-			Name:       v.ChartName,
-			UniqueCode: v.UniqueCode,
-			ClassifyId: v.ChartClassifyId,
+	for _, id := range req.ChartInfoIdList {
+		for _, v := range chartList {
+			if v.ChartInfoId == id {
+				tmp := &sandbox.SandboxLinkCheckItem{
+					Id:         v.ChartInfoId,
+					Name:       v.ChartName,
+					UniqueCode: v.UniqueCode,
+					ClassifyId: v.ChartClassifyId,
+				}
+				chartListTmp = append(chartListTmp, tmp)
+			}
 		}
-		chartListTmp = append(chartListTmp, tmp)
 	}
 
+
 	reportList, err := models.GetSimpleReportByIds(req.ReportIdList)
 	if err != nil {
 		br.Msg = `获取失败`
@@ -2428,14 +2438,19 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		return
 	}
 	reportListTmp := make([]*sandbox.SandboxLinkCheckItem, 0)
-	for _, v := range reportList {
-		tmp := &sandbox.SandboxLinkCheckItem{
-			Id:         v.Id,
-			Name:       v.Title,
-			UniqueCode: v.ReportCode,
+	for _, id := range req.ReportIdList {
+		for _, v := range reportList {
+			if v.Id == id {
+				tmp := &sandbox.SandboxLinkCheckItem{
+					Id:         v.Id,
+					Name:       v.Title,
+					UniqueCode: v.ReportCode,
+				}
+				reportListTmp = append(reportListTmp, tmp)
+			}
 		}
-		reportListTmp = append(reportListTmp, tmp)
 	}
+
 	resp.EdbInfoIdList = edbList
 	resp.ChartInfoIdList = chartListTmp
 	resp.ReportIdList = reportListTmp

+ 53 - 26
controllers/sys_admin.go

@@ -755,32 +755,55 @@ func (this *SysAdminController) Edit() {
 		}
 	}
 
-	adminInfo.AdminName = req.AdminName
-	adminInfo.RealName = req.RealName
-	adminInfo.LastUpdatedTime = time.Now().Format(utils.FormatDateTime)
-	adminInfo.Mobile = req.Mobile
-	adminInfo.RoleId = req.RoleId
-	adminInfo.RoleName = roleName
-	adminInfo.Enabled = req.Enabled
-	adminInfo.Authority = authority
-	adminInfo.Position = req.Position
-	adminInfo.RoleTypeCode = roleItem.RoleTypeCode
-	adminInfo.Province = req.Province
-	adminInfo.ProvinceCode = req.ProvinceCode
-	adminInfo.City = req.City
-	adminInfo.CityCode = req.CityCode
-	adminInfo.EmployeeId = req.EmployeeId
-	adminInfo.Email = req.Email
-	adminInfo.TelAreaCode = req.TelAreaCode
-	adminInfo.IsLdap = req.IsLdap
-	cols := []string{
-		"AdminName", "RealName", "LastUpdatedTime", "Mobile", "RoleId", "RoleName", "Enabled", "Authority",
-		"Position", "RoleTypeCode", "Province", "ProvinceCode", "City", "CityCode", "EmployeeId", "Email", "TelAreaCode", "IsLdap",
-	}
-	if e := adminInfo.Update(cols); e != nil {
-		br.Msg = "编辑失败"
-		br.ErrMsg = "更新用户信息失败, Err:" + e.Error()
-		return
+	if adminInfo.RoleName == "admin" && adminInfo.RealName == "admin" {
+		adminInfo.LastUpdatedTime = time.Now().Format(utils.FormatDateTime)
+		adminInfo.Mobile = req.Mobile
+		adminInfo.Position = req.Position
+		adminInfo.Province = req.Province
+		adminInfo.ProvinceCode = req.ProvinceCode
+		adminInfo.City = req.City
+		adminInfo.CityCode = req.CityCode
+		adminInfo.EmployeeId = req.EmployeeId
+		adminInfo.Email = req.Email
+		adminInfo.TelAreaCode = req.TelAreaCode
+		adminInfo.IsLdap = req.IsLdap
+		cols := []string{
+			"LastUpdatedTime", "Mobile", "Position", "Province", "ProvinceCode",
+			"City", "CityCode", "EmployeeId", "Email", "TelAreaCode", "IsLdap",
+		}
+		if e := adminInfo.Update(cols); e != nil {
+			br.Msg = "编辑失败"
+			br.ErrMsg = "更新用户信息失败, Err:" + e.Error()
+			return
+		}
+	} else {
+		adminInfo.AdminName = req.AdminName
+		adminInfo.RealName = req.RealName
+		adminInfo.LastUpdatedTime = time.Now().Format(utils.FormatDateTime)
+		adminInfo.Mobile = req.Mobile
+		adminInfo.RoleId = req.RoleId
+		adminInfo.RoleName = roleName
+		adminInfo.Enabled = req.Enabled
+		adminInfo.Authority = authority
+		adminInfo.Position = req.Position
+		adminInfo.RoleTypeCode = roleItem.RoleTypeCode
+		adminInfo.Province = req.Province
+		adminInfo.ProvinceCode = req.ProvinceCode
+		adminInfo.City = req.City
+		adminInfo.CityCode = req.CityCode
+		adminInfo.EmployeeId = req.EmployeeId
+		adminInfo.Email = req.Email
+		adminInfo.TelAreaCode = req.TelAreaCode
+		adminInfo.IsLdap = req.IsLdap
+		cols := []string{
+			"AdminName", "RealName", "LastUpdatedTime", "Mobile", "RoleId", "RoleName", "Enabled", "Authority",
+			"Position", "RoleTypeCode", "Province", "ProvinceCode", "City", "CityCode", "EmployeeId", "Email", "TelAreaCode", "IsLdap",
+		}
+		if e := adminInfo.Update(cols); e != nil {
+			br.Msg = "编辑失败"
+			br.ErrMsg = "更新用户信息失败, Err:" + e.Error()
+			return
+		}
 	}
 
 	// 同步用户缓存
@@ -849,6 +872,10 @@ func (this *SysAdminController) EditEnabled() {
 		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error()
 		return
 	}
+	if adminItem.RoleName == "admin" && adminItem.RealName == "admin" {
+		br.Msg = "禁止对admin使用<禁用>功能"
+		return
+	}
 
 	if req.Enabled == 0 {
 		//禁用

+ 21 - 1
controllers/sys_role.go

@@ -7,10 +7,11 @@ import (
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 type SysRoleController struct {
@@ -113,6 +114,11 @@ func (this *SysRoleController) Edit() {
 		br.Msg = "角色不存在, 请刷新页面"
 		return
 	}
+	// 不允许编辑admin用户
+	if item.RoleName == "admin" {
+		br.Msg = "admin用户不可编辑"
+		return
+	}
 	exists, e := system.GetSysRoleByName(req.RoleName)
 	if e != nil && e.Error() != utils.ErrNoRow() {
 		br.Msg = "操作失败"
@@ -179,6 +185,10 @@ func (this *SysRoleController) Delete() {
 		br.ErrMsg = "获取角色信息失败, Err: " + e.Error()
 		return
 	}
+	if role.RoleName == "admin" {
+		br.Msg = "admin用户不可删除"
+		return
+	}
 
 	err = system.DeleteSysRole(req.RoleId)
 	if err != nil {
@@ -515,6 +525,16 @@ func (this *SysRoleController) SysRoleMenuAuthList() {
 		}
 	}
 
+	sysRole, err := system.GetSysRoleById(roleId)
+	if err == nil {
+		if sysRole.RoleName == "admin" {
+			br.Ret = 200
+			br.Success = true
+			br.Msg = "获取成功"
+			return
+		}
+	}
+
 	order := `sort ASC, create_time DESC, menu_id DESC`
 	list, e := system.GetSysMenuItemsByCondition(` AND hidden = 0`, make([]interface{}, 0), []string{}, order)
 	if e != nil {

+ 3 - 3
controllers/sys_team.go

@@ -63,7 +63,7 @@ func (this *SysTeamController) Add() {
 			}
 
 			// 同步分组缓存
-			if utils.BusinessCode == utils.BusinessCodeRelease {
+			if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
 				var syncData system.SyncGroupData
 				syncData.Source = utils.SOURCE_ETA_FLAG
 				syncData.GroupId = int(groupId)
@@ -123,7 +123,7 @@ func (this *SysTeamController) Edit() {
 	}
 
 	// 同步分组缓存
-	if utils.BusinessCode == utils.BusinessCodeRelease {
+	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
 		var syncData system.SyncGroupData
 		syncData.Source = utils.SOURCE_ETA_FLAG
 		syncData.GroupId = item.GroupId
@@ -172,7 +172,7 @@ func (this *SysTeamController) Delete() {
 	}
 
 	// 同步分组缓存
-	if utils.BusinessCode == utils.BusinessCodeRelease {
+	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
 		var syncData system.SyncGroupData
 		syncData.Source = utils.SOURCE_ETA_FLAG
 		syncData.GroupId = req.TeamId

+ 27 - 0
controllers/target.go

@@ -184,6 +184,13 @@ func (this *TargetController) DataAdd() {
 		br.ErrMsg = "新增失败,Err:" + err.Error()
 		return
 	}
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, edbdata.TradeCode)
+		if err != nil {
+			fmt.Println("DataAdd CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+		}
+	}
 
 	// 添加操作记录
 	go func() {
@@ -382,11 +389,13 @@ func (this *TargetController) BatchDataEdit() {
 	}
 
 	edbDataEditList := make([]data.EdbDataEdit, 0)
+	edbCodeMap := make(map[string]string)
 	for _, trade := range req.List {
 		if trade.TradeCode == "" {
 			br.Msg = "指标编码不可为空!"
 			return
 		}
+		edbCodeMap[trade.TradeCode] = trade.TradeCode
 
 		close := ""
 		loc := reflect.ValueOf(trade.Close).Kind().String()
@@ -417,6 +426,15 @@ func (this *TargetController) BatchDataEdit() {
 		br.ErrMsg = "批量修改失败:" + err.Error()
 		return
 	}
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		for _, edbCode := range edbCodeMap {
+			err = utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, edbCode)
+			if err != nil {
+				fmt.Println("BatchDataEdit CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+			}
+		}
+	}
 	br.Ret = 200
 	br.Success = true
 	br.Data = failEdbDataList
@@ -1287,6 +1305,15 @@ func (this *TargetController) DataDelete() {
 		br.ErrMsg = "删除失败,Err:" + err.Error()
 		return
 	}
+
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, req.TradeCode)
+		if err != nil {
+			fmt.Println("DataDelete CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+		}
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "删除成功"

+ 51 - 49
go.mod

@@ -4,25 +4,26 @@ go 1.21.7
 
 require (
 	baliance.com/gooxml v1.0.1
-	github.com/PuerkitoBio/goquery v1.9.1
-	github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.2
-	github.com/alibabacloud-go/alimt-20181012/v2 v2.2.0
-	github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.6
-	github.com/alibabacloud-go/dm-20151123/v2 v2.0.9
+	github.com/PuerkitoBio/goquery v1.9.2
+	github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3
+	github.com/alibabacloud-go/alimt-20181012/v2 v2.3.0
+	github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8
+	github.com/alibabacloud-go/dm-20151123/v2 v2.2.1
 	github.com/alibabacloud-go/tea v1.2.2
-	github.com/alibabacloud-go/tea-utils/v2 v2.0.5
-	github.com/aliyun/alibaba-cloud-sdk-go v1.62.695
+	github.com/alibabacloud-go/tea-utils/v2 v2.0.6
+	github.com/aliyun/alibaba-cloud-sdk-go v1.62.800
 	github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
-	github.com/aws/aws-sdk-go v1.51.2
+	github.com/aws/aws-sdk-go v1.55.4
 	github.com/beego/bee/v2 v2.1.0
-	github.com/beego/beego/v2 v2.1.0
-	github.com/beevik/etree v1.3.0
+	github.com/beego/beego/v2 v2.2.2
+	github.com/beevik/etree v1.4.1
+	github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/go-ldap/ldap v3.0.3+incompatible
 	github.com/go-mysql-org/go-mysql v1.9.1
 	github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc
-	github.com/go-sql-driver/mysql v1.7.1
+	github.com/go-sql-driver/mysql v1.8.1
 	github.com/go-xorm/xorm v0.7.9
 	github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b
 	github.com/google/uuid v1.6.0
@@ -30,29 +31,30 @@ require (
 	github.com/h2non/filetype v1.1.3
 	github.com/jung-kurt/gofpdf v1.16.2
 	github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53
-	github.com/microcosm-cc/bluemonday v1.0.26
-	github.com/minio/minio-go/v7 v7.0.69
+	github.com/microcosm-cc/bluemonday v1.0.27
+	github.com/minio/minio-go/v7 v7.0.74
 	github.com/mojocn/base64Captcha v1.3.6
 	github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19
 	github.com/olivere/elastic/v7 v7.0.32
 	github.com/pdfcpu/pdfcpu v0.8.0
 	github.com/qiniu/qmgo v1.1.8
 	github.com/rdlucklib/rdluck_tools v1.0.3
-	github.com/shopspring/decimal v1.3.1
+	github.com/shopspring/decimal v1.4.0
 	github.com/silenceper/wechat/v2 v2.1.6
-	github.com/spf13/viper v1.7.0
+	github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72
+	github.com/spf13/viper v1.19.0
 	github.com/tealeg/xlsx v1.0.5
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.880
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.973
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.973
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.973
 	github.com/xuri/excelize/v2 v2.8.1
-	github.com/yidane/formula v0.0.0-20220322063702-c9da84ba3476
-	go.mongodb.org/mongo-driver v1.15.0
-	golang.org/x/net v0.21.0
+	go.mongodb.org/mongo-driver v1.16.0
+	golang.org/x/net v0.27.0
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 )
 
 require (
+	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/BurntSushi/toml v1.3.2 // indirect
 	github.com/Masterminds/semver v1.5.0 // indirect
 	github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
@@ -67,7 +69,6 @@ require (
 	github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
 	github.com/aliyun/credentials-go v1.3.1 // indirect
 	github.com/andybalholm/cascadia v1.3.2 // indirect
-	github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211218165449-dd623ecc2f02 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect
@@ -77,21 +78,21 @@ require (
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/fatih/structs v1.1.0 // indirect
-	github.com/fsnotify/fsnotify v1.6.0 // indirect
+	github.com/fsnotify/fsnotify v1.7.0 // indirect
+	github.com/go-ini/ini v1.67.0 // indirect
 	github.com/go-playground/locales v0.13.0 // indirect
 	github.com/go-playground/universal-translator v0.17.0 // indirect
 	github.com/go-playground/validator/v10 v10.4.1 // indirect
-	github.com/goccy/go-json v0.10.2 // indirect
+	github.com/goccy/go-json v0.10.3 // indirect
 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
-	github.com/golang/protobuf v1.5.3 // indirect
-	github.com/golang/snappy v0.0.1 // indirect
+	github.com/golang/snappy v0.0.4 // indirect
 	github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac // indirect
 	github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82 // indirect
 	github.com/gonum/integrate v0.0.0-20181209220457-a422b5c0fdf2 // indirect
 	github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect
 	github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9 // indirect
 	github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 // indirect
-	github.com/gorilla/css v1.0.0 // indirect
+	github.com/gorilla/css v1.0.1 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/hhrutter/lzw v1.0.0 // indirect
@@ -99,49 +100,50 @@ require (
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/klauspost/compress v1.17.8 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.6 // indirect
+	github.com/klauspost/compress v1.17.9 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/leodido/go-urn v1.2.0 // indirect
-	github.com/magiconair/properties v1.8.1 // indirect
+	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-runewidth v0.0.15 // indirect
-	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
-	github.com/minio/sha256-simd v1.0.1 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
-	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
+	github.com/montanaflynn/stats v0.7.1 // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
-	github.com/pelletier/go-toml v1.9.2 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pingcap/errors v0.11.5-0.20221009092201-b66cddb77c32 // indirect
 	github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c // indirect
 	github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22 // indirect
 	github.com/pingcap/tidb/pkg/parser v0.0.0-20231103042308-035ad5ccbe67 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
-	github.com/prometheus/client_golang v1.16.0 // indirect
-	github.com/prometheus/client_model v0.3.0 // indirect
-	github.com/prometheus/common v0.42.0 // indirect
-	github.com/prometheus/procfs v0.10.1 // indirect
+	github.com/prometheus/client_golang v1.19.0 // indirect
+	github.com/prometheus/client_model v0.5.0 // indirect
+	github.com/prometheus/common v0.48.0 // indirect
+	github.com/prometheus/procfs v0.12.0 // indirect
 	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
 	github.com/rs/xid v1.5.0 // indirect
+	github.com/sagikazarmark/locafero v0.4.0 // indirect
+	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
 	github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
 	github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 // indirect
-	github.com/sirupsen/logrus v1.9.3 // indirect
-	github.com/spf13/afero v1.1.2 // indirect
-	github.com/spf13/cast v1.5.0 // indirect
-	github.com/spf13/jwalterweatherman v1.0.0 // indirect
+	github.com/sirupsen/logrus v1.9.0 // indirect
+	github.com/sourcegraph/conc v0.3.0 // indirect
+	github.com/spf13/afero v1.11.0 // indirect
+	github.com/spf13/cast v1.6.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
-	github.com/subosito/gotenv v1.2.0 // indirect
+	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/tidwall/gjson v1.14.1 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/pretty v1.2.0 // indirect
 	github.com/tjfoc/gmsm v1.3.2 // indirect
+	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
 	github.com/xdg-go/stringprep v1.0.4 // indirect
@@ -151,14 +153,14 @@ require (
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.26.0 // indirect
-	golang.org/x/crypto v0.19.0 // indirect
+	golang.org/x/crypto v0.25.0 // indirect
 	golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
 	golang.org/x/image v0.15.0 // indirect
-	golang.org/x/sync v0.2.0 // indirect
-	golang.org/x/sys v0.17.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
-	golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
-	google.golang.org/protobuf v1.30.0 // indirect
+	golang.org/x/sync v0.7.0 // indirect
+	golang.org/x/sys v0.22.0 // indirect
+	golang.org/x/text v0.16.0 // indirect
+	golang.org/x/time v0.5.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
 	gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect

+ 117 - 257
go.sum

@@ -3,18 +3,11 @@ baliance.com/gooxml v1.0.1/go.mod h1:+gpUgmkAF4zCtwOFPNRLDAvpVRWoKs5EeQTSv/HYFnw
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
-cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
-cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
-cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
-cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
-cloud.google.com/go v0.46.3 h1:AVXDdKsrtX33oR9fbCMu/+c1o8Ofjq6Ku/MInaLVg5Y=
-cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
-cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
-cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
-cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
+cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
@@ -23,11 +16,10 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
 github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI=
-github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY=
-github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.2 h1:enQwehstpeaAnsyse1Aqb6r0sU5UJbiNvIqVmPo+KWI=
-github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.2/go.mod h1:SQq4xfIdvf6WYKSDxAJc+xOJdolt+/bc1jnQKMtPMvQ=
+github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE=
+github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk=
+github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3 h1:vrA6+R1BMLKMTbos8jAeuBrImHPGtY4gTlcue3OIej8=
+github.com/SebastiaanKlippert/go-wkhtmltopdf v1.9.3/go.mod h1:SQq4xfIdvf6WYKSDxAJc+xOJdolt+/bc1jnQKMtPMvQ=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
 github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
@@ -37,17 +29,17 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
 github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
-github.com/alibabacloud-go/alimt-20181012/v2 v2.2.0 h1:9AwDOjOZvhycl60jlXuMBSSl52rpWlcAuwxJOAQM4Bo=
-github.com/alibabacloud-go/alimt-20181012/v2 v2.2.0/go.mod h1:4gZhZ+BvRg/k14Z8SZnmu86zNqjslSpcC1wFl0jabl4=
+github.com/alibabacloud-go/alimt-20181012/v2 v2.3.0 h1:IDXPw5MOdK3EmDw3xFLtm6FgXnaYvj981UCyHY9GDG8=
+github.com/alibabacloud-go/alimt-20181012/v2 v2.3.0/go.mod h1:NR9bEoCnxfA6/7Q3VAqUOD76ervfR12m+3nw4WuKjP8=
 github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.0/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.6 h1:y1K+zKhpWcxso8zqI03CcYuwgyZPFwQdwAQOXAeuOVM=
-github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.6/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.7/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8 h1:benoD0QHDrylMzEQVpX/6uKtrN8LohT66ZlKXVJh7pM=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI=
 github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
 github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA=
 github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
-github.com/alibabacloud-go/dm-20151123/v2 v2.0.9 h1:3OPVk25YWcJ48whyVCFOf168dafhxSh7uRo+DFNNyg0=
-github.com/alibabacloud-go/dm-20151123/v2 v2.0.9/go.mod h1:AhCnEI1csfLmYL5fS5TbrxPR2xZZHRQ9MmkF04Iyez8=
+github.com/alibabacloud-go/dm-20151123/v2 v2.2.1 h1:qE4yvFGOyM+AukL7ALK7wQw17WVWXki5td0M5vn9QzE=
+github.com/alibabacloud-go/dm-20151123/v2 v2.2.1/go.mod h1:ogBn6PUJHYDhbZNC3gqOhdj22+zGpeyAR05/EY7aRJA=
 github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
 github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
 github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
@@ -75,9 +67,9 @@ github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQ
 github.com/alibabacloud-go/tea-utils v1.3.6 h1:bVjrxHztM8hAs6nOfLWCgxQfAtKb9RgFFMV6J3rdvB4=
 github.com/alibabacloud-go/tea-utils v1.3.6/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
-github.com/alibabacloud-go/tea-utils/v2 v2.0.4/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
-github.com/alibabacloud-go/tea-utils/v2 v2.0.5 h1:EUakYEUAwr6L3wLT0vejIw2rc0IA1RSXDwLnIb3f2vU=
 github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.6 h1:ZkmUlhlQbaDC+Eba/GARMPy6hKdCLiSke5RsN5LcyQ0=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
 github.com/alibabacloud-go/tea-xml v1.1.1/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
 github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
 github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
@@ -89,8 +81,8 @@ github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j
 github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
 github.com/alicebob/miniredis/v2 v2.30.0 h1:uA3uhDbCxfO9+DI/DuGeAMr9qI+noVWwGPNTFuKID5M=
 github.com/alicebob/miniredis/v2 v2.30.0/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q=
-github.com/aliyun/alibaba-cloud-sdk-go v1.62.695 h1:Lk9qjMhhkzZaD4eyx23v0E2+4nAIfwreJ/ecKdaTU6E=
-github.com/aliyun/alibaba-cloud-sdk-go v1.62.695/go.mod h1:CJJYa1ZMxjlN/NbXEwmejEnBkhi0DV+Yb3B2lxf+74o=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.800 h1:1NucX8xUg3F6m8Z6ermSniqyNXvUsfaW7B6CRMTpc0s=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.800/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
@@ -98,40 +90,32 @@ github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/x
 github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
 github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
 github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
-github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211218165449-dd623ecc2f02 h1:o2oaBQGTzO+xNh12e7xWkphNe7H2DTiWv1ml9a2P9PQ=
-github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20211218165449-dd623ecc2f02/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
 github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
-github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
-github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
-github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
-github.com/aws/aws-sdk-go v1.51.2 h1:Ruwgz5aqIXin5Yfcgc+PCzoqW5tEGb9aDL/JWDsre7k=
-github.com/aws/aws-sdk-go v1.51.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/aws/aws-sdk-go v1.55.4 h1:u7sFWQQs5ivGuYvCxi7gJI8nN/P9Dq04huLaw39a4lg=
+github.com/aws/aws-sdk-go v1.55.4/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
 github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
 github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
 github.com/beego/bee/v2 v2.1.0 h1:4WngbAnkvVOyKy74WXcRH3clon76wkjhuzrV2mx2fQU=
 github.com/beego/bee/v2 v2.1.0/go.mod h1:wDhKy5TNxv46LHKsK2gyxo38ObCOm9PbCN89lWHK3EU=
-github.com/beego/beego/v2 v2.1.0 h1:Lk0FtQGvDQCx5V5yEu4XwDsIgt+QOlNjt5emUa3/ZmA=
-github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
+github.com/beego/beego/v2 v2.2.2 h1:h6TNybAiMPXx9RXxK71Wz+JkPE7rpsL+ctjSZpv5yB0=
+github.com/beego/beego/v2 v2.2.2/go.mod h1:A3BC73uulBnqW3O1uBEN7q+oykprxipZTYRdZtEuKyY=
 github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
 github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
-github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU=
-github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc=
+github.com/beevik/etree v1.4.1 h1:PmQJDDYahBGNKDcpdX8uPy1xRCwoCGVUiW669MEirVI=
+github.com/beevik/etree v1.4.1/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
 github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
 github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d h1:pVrfxiGfwelyab6n21ZBkbkmbevaf+WvMIiR7sr97hw=
 github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
 github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -144,11 +128,6 @@ github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
 github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
 github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
@@ -157,15 +136,17 @@ github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGii
 github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
 github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149 h1:TkVfb0s14IUHDGvjQfq3f0PZnV1zh609did4DrnD4q4=
+github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149/go.mod h1:zkR27k4K0I8FS6rkEd8qBhPeS8i3X2FKfvSPdF64OpQ=
 github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
 github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@@ -176,22 +157,22 @@ github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
 github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
-github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
-github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
-github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
-github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk=
@@ -215,32 +196,28 @@ github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc/go.mod h1:25m
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
-github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
-github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
 github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM=
 github.com/go-xorm/xorm v0.7.9 h1:LZze6n1UvRmM5gpL9/U9Gucwqo6aWlFVlfcHKH10qA0=
 github.com/go-xorm/xorm v0.7.9/go.mod h1:XiVxrMMIhFkwSkh96BW7PACl7UhLtx2iJIHMdmjh5sQ=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
 github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
 github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -249,12 +226,11 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
 github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac h1:Q0Jsdxl5jbxouNs1TQYt0gxesYMU4VXRbsTlgDloZ50=
 github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc=
@@ -271,7 +247,6 @@ github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP
 github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b h1:fbskpz/cPqWH8VqkQ7LJghFkl2KPAiIFUHrTJ2O3RGk=
 github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -279,57 +254,32 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
 github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
 github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
 github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
-github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
-github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
-github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
-github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
-github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
-github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
-github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
-github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
-github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
-github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
-github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
-github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
 github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
 github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
 github.com/hhrutter/tiff v1.0.1 h1:MIus8caHU5U6823gx7C6jrfoEvfSTGtEFRiM8/LOzC0=
@@ -338,15 +288,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
 github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
 github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -360,14 +307,13 @@ github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5Pt
 github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
 github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53 h1:+8X3HMX8A2QhvNg3dImiQTCiVUt6BQXz1mW+/DrWI+k=
 github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53/go.mod h1:E61jD6q4yJ6Cu9uDGRAfiENM1G5TVZhOog0Y3+GgTpQ=
-github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
-github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
-github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -384,12 +330,10 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
 github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
@@ -397,24 +341,12 @@ github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO
 github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
-github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
-github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
 github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
 github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.0.69 h1:l8AnsQFyY1xiwa/DaQskY4NXSLA2yrGsW5iD9nRPVS0=
-github.com/minio/minio-go/v7 v7.0.69/go.mod h1:XAvOPJQ5Xlzk5o3o/ArO2NMbhSGkimC+bpW/ngRKDmQ=
-github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
-github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
-github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
-github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
-github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
-github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
-github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/minio/minio-go/v7 v7.0.74 h1:fTo/XlPBTSpo3BAMshlwKL5RspXRv9us5UeHEGYCFe0=
+github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -428,8 +360,9 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw=
 github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
-github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
+github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -438,7 +371,6 @@ github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19/go.mod h1:Lj
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
 github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -459,13 +391,12 @@ github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
 github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pdfcpu/pdfcpu v0.8.0 h1:SuEB4uVsPFz1nb802r38YpFpj9TtZh/oB0bGG34IRZw=
 github.com/pdfcpu/pdfcpu v0.8.0/go.mod h1:jj03y/KKrwigt5xCi8t7px2mATcKuOzkIOoCX62yMho=
 github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml v1.9.2 h1:7NiByeVF4jKSG1lDF3X8LTIkq2/bu+1uYbIm1eS5tzk=
-github.com/pelletier/go-toml v1.9.2/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
 github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@@ -483,37 +414,32 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
-github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
+github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
+github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
-github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
-github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
-github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
+github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
-github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
-github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
 github.com/qiniu/qmgo v1.1.8 h1:E64M+P59aqQpXKI24ClVtluYkLaJLkkeD2hTVhrdMks=
 github.com/qiniu/qmgo v1.1.8/go.mod h1:QvZkzWNEv0buWPx0kdZsSs6URhESVubacxFPlITmvB8=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -530,23 +456,23 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
 github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
-github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
-github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 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=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
-github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
-github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
 github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=
 github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
@@ -558,33 +484,32 @@ github.com/silenceper/wechat/v2 v2.1.6 h1:2br2DxNzhksmvIBJ+PfMqjqsvoZmd/5BnMIfjK
 github.com/silenceper/wechat/v2 v2.1.6/go.mod h1:7Iu3EhQYVtDUJAj+ZVRy8yom75ga7aDWv8RurLkVm0s=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
-github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
-github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
 github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
-github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
-github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
-github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
+github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -592,21 +517,22 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
-github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
 github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873 h1:CbeN5Fdzq3xea36+ZKPQcuRwwJk0ZYQRxcyWkyK5768=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873/go.mod h1:vzSh5OxbOCyFt+SdlEd9oCQGBb1oObkD7Xfod/UPvVk=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.873/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880 h1:0Ok1pZ06/zZMCiW8Dm8wYOGJK1HCU5OXwNSyE5UVOAM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.880 h1:PnzU5KS7x3LQGE0yetGLEGwJtLb6Uzsd79mbCiRh1rw=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.880/go.mod h1:5DGl21YNTtHXi9+QIr8XmlSelukl+Weaz+beLQQ+NE0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.973 h1:Vi7wT+fjCLzdlSAq87cjVHZwRAPgNjTtYvXCVeNZpd0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.973/go.mod h1:rZKC4v/5EbMhXe35m+/44RJ93xuZWEYGKmzxMBYzqjY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.973 h1:XtrGe/XEyusLgGiv1DpEg9SRR7sxsSbIgAhMxcEVbjY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.973/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.973 h1:fd68qywl6VYMTt1C41VJJI7p4kyOXVmm54uVgUKpU60=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.973/go.mod h1:MdyACChA7ITk0lIom3MjaCKp8s8Yykkq3vKAporZGdc=
 github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
 github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
 github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
@@ -616,12 +542,13 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
 github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
 github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
 github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
 github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
 github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
 github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
@@ -631,15 +558,12 @@ github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3k
 github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
 github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
 github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
 github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0=
 github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
 github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ=
 github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE=
 github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4=
 github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
-github.com/yidane/formula v0.0.0-20220322063702-c9da84ba3476 h1:66fLxv8xlhSr42ZhVAYjUY/sEF0olUUAESVlsxVduuw=
-github.com/yidane/formula v0.0.0-20220322063702-c9da84ba3476/go.mod h1:9/dQiKiN04yPMdgsuFmKGuI2Hdp6OmFV9gSWS1col6g=
 github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
@@ -652,14 +576,10 @@ github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRF
 github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
 github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
 github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
-go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
-go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
+go.mongodb.org/mongo-driver v1.16.0 h1:tpRsfBJMROVHKpdGyc1BBEzzjDUWjItxbVSZ8Ls4BQ4=
+go.mongodb.org/mongo-driver v1.16.0/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -668,21 +588,17 @@ go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
 go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
 go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
 go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
 go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
 go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -692,15 +608,13 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
+golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
-golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
 golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
 golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
@@ -714,13 +628,8 @@ golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
-golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -729,18 +638,12 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -758,11 +661,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
 golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
+golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -774,14 +676,11 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -789,10 +688,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -810,15 +705,14 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -838,14 +732,13 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
-golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -853,20 +746,11 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -881,30 +765,14 @@ gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
 gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
 gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
-google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
-google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
-google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
 google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
-google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -913,8 +781,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
@@ -926,25 +794,20 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
 gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
 gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
-gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-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.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 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/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -961,9 +824,6 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
-rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
 xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8=
 xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU=

+ 1 - 1
main.go

@@ -11,7 +11,7 @@ import (
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
 
-	"github.com/beego/beego/v2/adapter/logs"
+	"github.com/beego/beego/v2/core/logs"
 	"github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web/context"
 )

+ 4 - 5
models/bi_dashboard/bi_dashboard_detail.go

@@ -22,8 +22,8 @@ func (m *BiDashboardDetail) TableName() string {
 
 // add
 //func AddBiDashboardDetail(item *BiDashboardDetail) (err error) {
-	//err = global.DEFAULT_DmSQL.Create(item).Error
-	//return
+//err = global.DEFAULT_DmSQL.Create(item).Error
+//return
 //}
 
 func GetBiDashboardDetailById(id int) (list []*BiDashboardDetail, err error) {
@@ -56,7 +56,7 @@ type MoveDashboardDetailReq struct {
 }
 
 // update
-func EditBiDashboardDetail(item *BiDashboardDetail) (err error){
+func EditBiDashboardDetail(item *BiDashboardDetail) (err error) {
 	//return global.DEFAULT_DmSQL.Model(item).Where("bi_dashboard_detail_id = ?", item.BiDashboardDetailId).Updates(item).Error
 	o := orm.NewOrm()
 	_, err = o.Raw("UPDATE bi_dashboard_detail SET bi_dashboard_id=?,type=?,unique_code=?,sort=?,modify_time=? WHERE bi_dashboard_detail_id=?", item.BiDashboardId, item.Type, item.UniqueCode, item.Sort, item.ModifyTime, item.BiDashboardDetailId).Exec()
@@ -67,11 +67,10 @@ type DelDashboardDetailReq struct {
 	BiDashboardDetailId int `description:"看板详情id"`
 }
 
-
 // del
 func DeleteBiDashboardDetailByDetailId(id int) (err error) {
 	//return global.DEFAULT_DmSQL.Where("bi_dashboard_detail_id = ?", id).Delete(&BiDashboardDetail{}).Error
 	o := orm.NewOrm()
 	_, err = o.Raw("DELETE from bi_dashboard_detail where bi_dashboard_detail_id=?", id).Exec()
 	return
-}
+}

+ 1 - 1
models/bi_dashboard/bi_dashboard_grant.go

@@ -72,4 +72,4 @@ func GetDashboardGrantInfo(biDashboardId int) (list []*BiDashboardGrant, err err
 	o := orm.NewOrm()
 	_, err = o.Raw("SELECT * FROM bi_dashboard_grant where bi_dashboard_id=?", biDashboardId).QueryRows(&list)
 	return
-}
+}

+ 35 - 35
models/business_conf.go

@@ -12,45 +12,45 @@ import (
 var (
 	BusinessConfMap map[string]string
 )
-const (
-	BusinessConfUseXf                     = "UseXf"
-	BusinessConfXfAppid                   = "XfAppid"
-	BusinessConfXfApiKey                  = "XfApiKey"
-	BusinessConfXfApiSecret               = "XfApiSecret"
-	BusinessConfXfVcn                     = "XfVcn"
-	BusinessConfEnPptCoverImgs            = "EnPptCoverImgs"
-	BusinessConfIsReportApprove           = "IsReportApprove"
-	BusinessConfReportApproveType         = "ReportApproveType"
-	BusinessConfCompanyName               = "CompanyName"
-	BusinessConfCompanyWatermark          = "CompanyWatermark"
-	BusinessConfWatermarkChart            = "WatermarkChart"
-	BusinessConfLoginSmsTpId              = "LoginSmsTpId"
-	BusinessConfLoginSmsGjTpId            = "LoginSmsGjTpId"
-	BusinessConfSmsJhgnAppKey             = "SmsJhgnAppKey"
-	BusinessConfSmsJhgjAppKey             = "SmsJhgjAppKey"
-	BusinessConfLdapHost                  = "LdapHost"
-	BusinessConfLdapBase                  = "LdapBase"
-	BusinessConfLdapPort                  = "LdapPort"
-	BusinessConfEmailClient               = "EmailClient"
-	BusinessConfEmailServerHost           = "EmailServerHost"
-	BusinessConfEmailServerPort           = "EmailServerPort"
-	BusinessConfEmailSender               = "EmailSender"
-	BusinessConfEmailSenderUserName       = "EmailSenderUserName"
-	BusinessConfEmailSenderPassword       = "EmailSenderPassword"
-	BusinessConfSmsClient                 = "SmsClient"
-	BusinessConfNanHuaSmsAppKey           = "NanHuaSmsAppKey"
-	BusinessConfNanHuaSmsAppSecret        = "NanHuaSmsAppSecret"
-	BusinessConfNanHuaSmsApiHost          = "NanHuaSmsApiHost"
-	BusinessConfLoginSmsTplContent        = "LoginSmsTplContent"
-	BusinessConfLoginEmailTemplateSubject = "LoginEmailTemplateSubject"
-	BusinessConfLoginEmailTemplateContent = "LoginEmailTemplateContent"
-	BusinessConfLdapBindUserSuffix        = "LdapBindUserSuffix"
-	BusinessConfLdapUserFilter            = "LdapUserFilter"
 
+const (
+	BusinessConfUseXf                        = "UseXf"
+	BusinessConfXfAppid                      = "XfAppid"
+	BusinessConfXfApiKey                     = "XfApiKey"
+	BusinessConfXfApiSecret                  = "XfApiSecret"
+	BusinessConfXfVcn                        = "XfVcn"
+	BusinessConfEnPptCoverImgs               = "EnPptCoverImgs"
+	BusinessConfIsReportApprove              = "IsReportApprove"
+	BusinessConfReportApproveType            = "ReportApproveType"
+	BusinessConfCompanyName                  = "CompanyName"
+	BusinessConfCompanyWatermark             = "CompanyWatermark"
+	BusinessConfWatermarkChart               = "WatermarkChart"
+	BusinessConfLoginSmsTpId                 = "LoginSmsTpId"
+	BusinessConfLoginSmsGjTpId               = "LoginSmsGjTpId"
+	BusinessConfSmsJhgnAppKey                = "SmsJhgnAppKey"
+	BusinessConfSmsJhgjAppKey                = "SmsJhgjAppKey"
+	BusinessConfLdapHost                     = "LdapHost"
+	BusinessConfLdapBase                     = "LdapBase"
+	BusinessConfLdapPort                     = "LdapPort"
+	BusinessConfEmailClient                  = "EmailClient"
+	BusinessConfEmailServerHost              = "EmailServerHost"
+	BusinessConfEmailServerPort              = "EmailServerPort"
+	BusinessConfEmailSender                  = "EmailSender"
+	BusinessConfEmailSenderUserName          = "EmailSenderUserName"
+	BusinessConfEmailSenderPassword          = "EmailSenderPassword"
+	BusinessConfSmsClient                    = "SmsClient"
+	BusinessConfNanHuaSmsAppKey              = "NanHuaSmsAppKey"
+	BusinessConfNanHuaSmsAppSecret           = "NanHuaSmsAppSecret"
+	BusinessConfNanHuaSmsApiHost             = "NanHuaSmsApiHost"
+	BusinessConfLoginSmsTplContent           = "LoginSmsTplContent"
+	BusinessConfLoginEmailTemplateSubject    = "LoginEmailTemplateSubject"
+	BusinessConfLoginEmailTemplateContent    = "LoginEmailTemplateContent"
+	BusinessConfLdapBindUserSuffix           = "LdapBindUserSuffix"
+	BusinessConfLdapUserFilter               = "LdapUserFilter"
+	BusinessConfSmsJhgjVariable              = "SmsJhgjVariable"              // 聚合国际短信变量
 	BusinessConfTencentApiSecretId           = "TencentApiSecretId"           // 腾讯云API-密钥对
 	BusinessConfTencentApiSecretKey          = "TencentApiSecretKey"          // 腾讯云API-密钥对
 	BusinessConfTencentApiRecTaskCallbackUrl = "TencentApiRecTaskCallbackUrl" // 腾讯云API-语音识别回调地址
-	BusinessConfSmsJhgjVariable              = "SmsJhgjVariable"              // 聚合国际短信变量
 
 	BusinessConfEdbStopRefreshRule = "EdbStopRefreshRule" // 是否停止指标刷新规则
 	BusinessConfReport2ImgUrl      = "Report2ImgUrl"      // 报告转长图地址(用于兼容内外网环境的)

+ 15 - 0
models/chart_permission.go

@@ -227,6 +227,14 @@ func (c *ChartPermission) GetFirstChartPermissionByParentId(parentId int) (item
 	return
 }
 
+// GetChartPermissionList 获取品种权限列表
+func GetChartPermissionList() (list []*ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := `SELECT * FROM chart_permission ORDER BY product_id ASC, sort ASC`
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
 // GetChartPermissionById 主键获取品种
 func GetChartPermissionById(permissionId int) (item *ChartPermission, err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -248,6 +256,7 @@ type SimpleChartPermission struct {
 	ChartPermissionName string                   `description:"品种名称"`
 	Sort                int                      `description:"排序"`
 	Children            []*SimpleChartPermission `description:"子分类"`
+	//IsLatestEdit        bool                     `description:"是否是最后一级"`
 }
 
 func FormatChartPermission2Simple(origin *ChartPermission) (item *SimpleChartPermission) {
@@ -289,3 +298,9 @@ func GetChartPermissionByIdList(permissionIdList []int) (items []*ChartPermissio
 
 	return
 }
+
+type FaCalendarPermissionResp struct {
+	List                  []*SimpleChartPermission
+	CheckedPermissionId   int
+	CheckedPermissionName string
+}

+ 213 - 0
models/data_manage/base_from_clarksons_classify.go

@@ -0,0 +1,213 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+// BaseFromClarksonsClassify 卓创红期原始数据分类表
+type BaseFromClarksonsClassify struct {
+	BaseFromClassifyId int       `orm:"column(base_from_clarksons_classify_id);pk"`
+	ClassifyName       string    `description:"分类名称"`
+	ParentId           int       `description:"父级id"`
+	Level              int       `description:"层级"`
+	Sort               int       `description:"排序字段"`
+	ModifyTime         time.Time `description:"修改时间"`
+	CreateTime         time.Time `description:"创建时间"`
+}
+
+type BaseFromClarksonsClassifyItem struct {
+	BaseFromClassifyId int                              `orm:"column(base_from_clarksons_classify_id);pk"`
+	ClassifyName       string                           `description:"分类名称"`
+	ParentId           int                              `description:"父级id"`
+	Level              int                              `description:"层级"`
+	Sort               int                              `description:"排序字段"`
+	UniqueCode         string                           `description:"唯一code"`
+	ModifyTime         time.Time                        `description:"修改时间"`
+	CreateTime         time.Time                        `description:"创建时间"`
+	ClassifyNameEn     string                           `description:"英文分类名称"`
+	Children           []*BaseFromClarksonsClassifyItem `description:"子分类"`
+}
+
+type BaseFromClarksonsClassifyMaxSort struct {
+	BaseFromClassifyId int `description:"分类id"`
+	MaxSort            int `description:"最大排序"`
+}
+
+func (t *BaseFromClarksonsClassify) Add() (insertId int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	insertId, err = o.Insert(t)
+	return
+}
+
+func (t *BaseFromClarksonsClassify) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(t, cols...)
+	return
+}
+
+func BatchAddClarksonsClassify(items []*BaseFromClarksonsClassify) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+// 获取所有分类
+func GetClarksonsClassifyAll() (items []*BaseFromClarksonsClassifyItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_classify ORDER BY sort ASC, base_from_clarksons_classify_id ASC`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+// GetChildClarksonsClassifyListById 获取子分类列表
+func GetChildClarksonsClassifyListById(classifyId int) (items []*BaseFromClarksonsClassifyItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_classify WHERE parent_id=? `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+// GetChildClarksonsClassifyIdsById 获取子分类的id集合
+func GetChildClarksonsClassifyIdsById(classifyId int) (items []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT base_from_clarksons_classify_id FROM base_from_clarksons_classify WHERE parent_id=? `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+// GetChildClarksonsClassifyMaxSortById 获取子分类最大排序
+func GetChildClarksonsClassifyMaxSortById(classifyId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT MAX(sort) AS sort FROM base_from_clarksons_classify WHERE parent_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&sort)
+	return
+}
+
+// GetClarksonsClassifyCountById 获取分类数量
+func GetClarksonsClassifyCountById(classifyId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(*) AS count FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&count)
+	return
+}
+
+// GetClarksonsClassifyById 通过分类id获取分类
+func GetClarksonsClassifyById(classifyId int) (item *BaseFromClarksonsClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}
+
+// GetClarksonsChildClassifyById 通过分类id获取子分类
+func GetClarksonsChildClassifyIdsById(classifyId int) (items []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT base_from_clarksons_classify_id FROM base_from_clarksons_classify WHERE parent_id=? `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+// GetClarksonsClassifyListByIds 通过分类id获取分类列表
+func GetClarksonsClassifyListByIds(classifyIds []int) (items []*BaseFromClarksonsClassify, err error) {
+	if len(classifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `)`
+	_, err = o.Raw(sql, classifyIds).QueryRows(&items)
+	return
+}
+
+// GetClarksonsClassifyCountByName 通过分类名称获取分类
+func GetClarksonsClassifyCountByName(classifyName string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(*) AS count FROM base_from_clarksons_classify WHERE 1=1`
+
+	sql += ` AND classify_name=? `
+	err = o.Raw(sql, classifyName).QueryRow(&count)
+	return
+}
+
+func GetBaseFromClarksonsClassifyEnCount(classifyNameEn string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(1) AS count FROM base_from_clarksons_classify WHERE classify_name_en=? AND parent_id=? `
+	err = o.Raw(sql, classifyNameEn, parentId).QueryRow(&count)
+	return
+}
+
+func GetBaseFromClarksonsClassifyCount(classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(1) AS count FROM base_from_clarksons_classify WHERE classify_name=? AND parent_id=? `
+	err = o.Raw(sql, classifyName, parentId).QueryRow(&count)
+	return
+}
+
+func DeleteClarksonsClassifyById(classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` DELETE FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id=? `
+	_, err = o.Raw(sql, classifyId).Exec()
+	return
+}
+
+// BatchDeleteClarksonsClassifyById 批量删除分类
+func BatchDeleteClarksonsClassifyById(classifyId []int) (err error) {
+	if len(classifyId) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	sql := ` DELETE FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id IN (` + utils.GetOrmInReplace(len(classifyId)) + `) `
+	_, err = o.Raw(sql, classifyId).Exec()
+
+	return
+}
+
+// DeleteClarksonsClassifyByClassifyId 根据分类id删除对应的指标分类
+func DeleteClarksonsClassifyByClassifyId(classifyIdList []int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	num := len(classifyIdList)
+	if num <= 0 {
+		return
+	}
+	//删除分类
+	sql := `DELETE FROM base_from_clarksons_classify WHERE base_from_clarksons_classify_id IN (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, classifyIdList).Exec()
+	return
+}
+
+// GetClarksonsIndexClassifyMinSort 获取最小不等于0的排序
+func GetClarksonsIndexClassifyMinSort(parentId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT MIN(sort) FROM base_from_clarksons_classify WHERE parent_id=? AND sort <> 0 `
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+// MoveUpClarksonsIndexClassifyBySort 往上移动
+func MoveUpClarksonsIndexClassifyBySort(parentId, nextSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_clarksons_classify set sort = sort + 1 where parent_id=? and sort >= ? and sort< ?`
+	_, err = o.Raw(sql, parentId, nextSort, currentSort).Exec()
+	return
+}
+
+// MoveDownClarksonsIndexClassifyBySort 往下移动
+func MoveDownClarksonsIndexClassifyBySort(parentId, prevSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_clarksons_classify set sort = sort - 1 where parent_id=? and sort <= ? and sort> ? `
+	_, err = o.Raw(sql, parentId, prevSort, currentSort).Exec()
+	return
+}

+ 81 - 0
models/data_manage/base_from_clarksons_data.go

@@ -0,0 +1,81 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type BaseFromClarksonsData struct {
+	BaseFromClarksonsDataId          int       `orm:"column(base_from_clarksons_data_id);pk"`
+	BaseFromClarksonsIndexId int       `description:"指标id"`
+	IndexCode            string    `description:"指标编码"`
+	DataTime             string    `description:"数据日期"`
+	Value                float64   `description:"数据值"`
+	CreateTime           time.Time `description:"创建时间"`
+	ModifyTime           time.Time `description:"修改时间"`
+	DataTimestamp        int64     `description:"数据时间戳"`
+}
+
+// GetClarksonsDataByIndexId 根据指标id获取指标数据
+func GetClarksonsDataByIndexId(indexId int) (items []*BaseFromClarksonsData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_data WHERE base_from_clarksons_index_id=? ORDER BY data_time DESC`
+	_, err = o.Raw(sql, indexId).QueryRows(&items)
+	return
+}
+
+// GetClarksonsDataDataTimeByIndexId 根据指标id获取指标数据的日期列表
+func GetClarksonsDataDataTimeByIndexId(indexIdList []int) (items []string, err error) {
+	if len(indexIdList) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT DISTINCT data_time FROM base_from_clarksons_data WHERE base_from_clarksons_index_id IN (` + utils.GetOrmInReplace(len(indexIdList)) + `) ORDER BY data_time DESC`
+	_, err = o.Raw(sql, indexIdList).QueryRows(&items)
+	return
+}
+
+func GetClarksonsIndexDataByCode(indexCode string) (items []*BaseFromClarksonsData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_clarksons_data WHERE index_code=? ORDER BY data_time DESC  `
+	_, err = o.Raw(sql, indexCode).QueryRows(&items)
+	return
+}
+
+func GetClarksonsIndexDataCount(indexCode string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count  FROM base_from_clarksons_data WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&count)
+	return
+}
+
+// GetClarksonsLastUpdateTimeLastByIndexCode 根据指标编码查询 返回ModifyTime最后一条数据
+func GetClarksonsLastUpdateTimeLastByIndexCode(indexCodes []string) (items []*BaseFromClarksonsData, err error) {
+	o := orm.NewOrmUsingDB("data")
+
+	// 构造 SQL 查询
+	sql := `SELECT t1.index_code, t1.data_time, t2.value
+			FROM (
+    			SELECT index_code, MAX(data_time) AS data_time
+   				 FROM base_from_clarksons_data
+    			WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodes)) + `)
+    			GROUP BY index_code
+			) AS t1
+			JOIN base_from_clarksons_data AS t2 ON t1.index_code = t2.index_code AND t1.data_time = t2.data_time`
+
+	// 执行 SQL 查询
+	_, err = o.Raw(sql, indexCodes).QueryRows(&items)
+	if err != nil {
+		return nil, err
+	}
+	return items, nil
+}
+
+func GetClarksonsIndexData(indexCode string, startSize, pageSize int) (items []*BaseFromClarksonsData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_clarksons_data WHERE index_code=? ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCode, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 424 - 0
models/data_manage/base_from_clarksons_index.go

@@ -0,0 +1,424 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type BaseFromClarksonsIndex struct {
+	BaseFromClarksonsIndexId int       `orm:"pk"`
+	ClassifyId           int       `description:"指标分类id"`
+	IndexCode            string    `description:"指标编码"`
+	IndexName            string    `description:"指标名称"`
+	Unit                 string    `description:"单位"`
+	Frequency            string    `description:"频度"`
+	StartDate            string    `description:"开始日期"`
+	EndDate              string    `description:"结束日期"`
+	Sort                 int       `description:"排序"`
+	CreateTime           time.Time
+	ModifyTime           time.Time
+}
+
+type BaseFromClarksonsIndexView struct {
+	BaseFromClarksonsIndexId int     `orm:"pk"`
+	EdbInfoId            int     `description:"指标库id"`
+	ClassifyId           int     `description:"指标分类id"`
+	IndexCode            string  `description:"指标编码"`
+	IndexName            string  `description:"指标名称"`
+	UniqueCode           string  `description:"唯一code"`
+	Frequency            string  `description:"频度"`
+	Unit                 string  `description:"单位"`
+	StartDate            string  `description:"开始日期"`
+	EndDate              string  `description:"结束日期"`
+	Sort                 int     `description:"排序"`
+	LatestDate           string  `description:"最后更新时间"`
+	EdbExist             int     `description:"edb是否存在"`
+	ModifyTime           string
+}
+
+type BaseFromClarksonsIndexList struct {
+	BaseFromClarksonsIndexId int     `orm:"pk"`
+	IndexCode          string    // 指标编码
+	IndexName          string    // 指标名称
+	ClassifyId         int       // 分类Id
+	Unit               string    // 单位
+	Frequency          string    // 频度
+	Describe           string    // 指标描述
+	CreateTime         string // 创建时间
+	ModifyTime         string // 修改时间
+	DataList           []*BaseFromClarksonsData
+	Paging             *paging.PagingItem `description:"分页数据"`
+}
+func (b *BaseFromClarksonsIndex) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(b, cols...)
+	return
+}
+
+// GetClarksonsIndexByCondition 根据条件获取克拉克森指标列表
+func GetClarksonsIndexByCondition(condition string, pars []interface{}) (items []*BaseFromClarksonsIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE 1=1 `
+
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC, base_from_clarksons_index_id ASC`
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexByCondition 根据条件获取克拉克森指标列表
+func GetClarksonsIndexByConditionAndFrequency(condition, frequency string, pars []interface{}) (items []*BaseFromClarksonsIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE 1=1 `
+
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` AND frequency=?`
+	sql += ` ORDER BY sort ASC, base_from_clarksons_index_id ASC`
+	_, err = o.Raw(sql, pars, frequency).QueryRows(&items)
+	return
+}
+
+func GetClarksonsIndexCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(*) AS count FROM base_from_clarksons_index WHERE 1=1 `
+
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC, base_from_clarksons_index_id ASC`
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetClarksonsIndexAndEdbInfoByCondition 根据条件获取克拉克森index和指标库的信息
+func GetClarksonsIndexAndEdbInfoByCondition(condition string, pars []interface{}) (items []*BaseFromClarksonsIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT b.*, e.edb_info_id FROM base_from_clarksons_index AS b LEFT JOIN edb_info AS e ON b.index_code=e.edb_code AND e.source=? WHERE 1=1 `
+
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC `
+	_, err = o.Raw(sql, utils.DATA_SOURCE_SCI_HQ, pars).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexByIndexCode 根据指标编码获取指标信息
+func GetClarksonsIndexByIndexCode(indexCode string) (item *BaseFromClarksonsIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE index_code=? `
+	err = o.Raw(sql, indexCode).QueryRow(&item)
+	return
+}
+
+// GetClarksonsIndexByIndexId 根据指标id获取指标信息
+func GetClarksonsIndexByIndexId(indexId int) (item *BaseFromClarksonsIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE base_from_clarksons_index_id=? `
+	err = o.Raw(sql, indexId).QueryRow(&item)
+	return
+}
+
+// GetClarksonsIndexListByIndexIds 根据指标id获取指标信息
+func GetClarksonsIndexListByIndexIds(indexIds []int) (items []*BaseFromClarksonsIndex, err error) {
+	if len(indexIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE base_from_clarksons_index_id IN (` + utils.GetOrmInReplace(len(indexIds)) + `) `
+	_, err = o.Raw(sql, indexIds).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexCountByClassifyIds 获取分类下指标的个数
+func GetClarksonsIndexCountByClassifyIds(classifyIds []int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	num := len(classifyIds)
+	if num <= 0 {
+		return
+	}
+	sql := `SELECT COUNT(1) AS count FROM base_from_clarksons_index WHERE classify_id IN (` + utils.GetOrmInReplace(num) + `) `
+	err = o.Raw(sql, classifyIds).QueryRow(&count)
+	return
+}
+
+// GetClarksonsIndexByClassifyId 根据分类id获取克拉克森指标列表
+func GetClarksonsIndexByClassifyId(classifyIds []int, startSize, pageSize int) (items []*BaseFromClarksonsIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT b.*, e.edb_info_id,
+	CASE WHEN e.edb_info_id IS NULL THEN 0 ELSE 1 END AS edb_exist
+	FROM base_from_clarksons_index AS b
+	LEFT JOIN edb_info AS e ON b.index_code=e.edb_code AND e.source=101
+	WHERE b.classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `) ORDER BY b.sort ASC LIMIT ?,? `
+	_, err = o.Raw(sql, classifyIds, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexCountByClassifyId 根据分类id获取克拉克森指标数量
+func GetClarksonsIndexCountByClassifyId(classifyIds []int) (count int, err error) {
+	if len(classifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(*) AS count FROM base_from_clarksons_index WHERE classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `) `
+	err = o.Raw(sql, classifyIds).QueryRow(&count)
+	return
+}
+
+// GetClarksonsIndexCount 获取克拉克森指标数量
+func GetClarksonsIndexCount() (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(*) AS count FROM base_from_clarksons_index `
+	err = o.Raw(sql).QueryRow(&count)
+	return
+}
+
+func GetClarksonsIndexByPage(startSize, pageSize int) (items []*BaseFromClarksonsIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT b.*, e.edb_info_id,
+	CASE WHEN e.edb_info_id IS NULL THEN 0 ELSE 1 END AS edb_exist
+	FROM base_from_clarksons_index AS b
+	LEFT JOIN edb_info AS e ON b.index_code=e.edb_code AND e.source=101
+	ORDER BY b.modify_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexBaseInfoByClassifyId 根据分类id获取克拉克森指标列表
+func GetClarksonsIndexBaseInfoByClassifyId(classifyId int) (items []*BaseFromClarksonsIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT base_from_clarksons_index_id, classify_id, index_code, index_name, CONCAT(classify_id, '_', base_from_clarksons_index_id) AS unique_code  FROM base_from_clarksons_index WHERE classify_id = ? ORDER BY sort ASC `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+// GetClarksonsIndexBaseInfoByClassifyId 根据分类id获取克拉克森指标列表
+func GetClarksonsIndexBaseInfoByCondition(condition string, pars []interface{}) (items []*BaseFromClarksonsIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT base_from_clarksons_index_id, index_code, index_name  FROM base_from_clarksons_index WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC `
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+	return
+}
+
+func GetClarksonsDataMaxCount(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT MAX(t.num) AS count FROM ( SELECT COUNT(1) AS num  FROM base_from_clarksons_index AS a INNER JOIN base_from_clarksons_data AS b ON a.index_code=b.index_code WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` GROUP BY a.base_from_clarksons_index_id) AS t `
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetClarksonsIndexMaxSortByClassifyId 根据分类id获取指标最大排序
+func GetClarksonsIndexMaxSortByClassifyId(classifyId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT MAX(sort) FROM base_from_clarksons_index WHERE classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&sort)
+	return
+}
+
+func GetClarksonsFrequency(classifyId int) (items []*string, err error) {
+	sql := `SELECT DISTINCT frequency FROM base_from_clarksons_index WHERE classify_id=? ORDER BY FIELD(frequency,'日度','周度','月度','季度','半年','年度') `
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+func GetClarksonsFrequencyByCondition(condition string, pars []interface{}) (items []*string, err error) {
+	sql := `SELECT DISTINCT frequency FROM base_from_clarksons_index WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY FIELD(frequency,'日度','周度','月度','季度','半年','年度') `
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+	return
+}
+
+func GetClarksonsFrequencyByCode(code string) (items []*string, err error) {
+	sql := `SELECT DISTINCT frequency FROM base_from_clarksons_index WHERE index_code=? ORDER BY FIELD(frequency,'日度','周度','月度','季度','半年','年度') `
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw(sql, code).QueryRows(&items)
+	return
+}
+
+// GetClarksonsClassifyMaxSortByClassifyIds 通过分类id获取对应分类的最大sort
+func GetClarksonsClassifyMaxSortByClassifyIds(classifyIds []int) (items []*BaseFromClarksonsClassifyMaxSort, err error) {
+	if len(classifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT bc.base_from_clarksons_classify_id, COALESCE(MAX(bi.sort), 0) AS max_sort FROM base_from_clarksons_classify  AS bc
+	LEFT JOIN base_from_clarksons_index AS bi
+	ON bc.base_from_clarksons_classify_id=bi.classify_id  
+	WHERE bc.base_from_clarksons_classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `)
+	GROUP BY bc.base_from_clarksons_classify_id
+	`
+	// sql = ` SELECT classify_id, MAX(sort) AS max_sort FROM base_from_clarksons_index WHERE classify_id IN (` + utils.GetOrmInReplace(len(classifyIds)) + `) GROUP BY classify_id `
+	_, err = o.Raw(sql, classifyIds).QueryRows(&items)
+	return
+}
+
+func BatchModifyClarksonsIndexClassify(items []*BaseFromClarksonsIndex) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE base_from_clarksons_index SET classify_id=?, sort=? WHERE base_from_clarksons_index_id=? `
+	p, err := o.Raw(sql).Prepare()
+	if err != nil {
+		return
+	}
+	defer func() {
+		p.Close()
+	}()
+	for _, v := range items {
+		_, err = p.Exec(v.ClassifyId, v.Sort, v.BaseFromClarksonsIndexId)
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+// MoveDownClarksonsIndexBySort 往下移动
+func MoveDownClarksonsIndexBySort(classifyId, prevSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_clarksons_index set sort = sort - 1 where classify_id=? and sort <= ? and sort> ? `
+	_, err = o.Raw(sql, classifyId, prevSort, currentSort).Exec()
+	return
+}
+
+// MoveUpClarksonsIndexBySort 往上移动
+func MoveUpClarksonsIndexBySort(classifyId, nextSort, currentSort int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `update base_from_clarksons_index set sort = sort + 1 where classify_id=? and sort >= ? and sort< ?`
+	_, err = o.Raw(sql, classifyId, nextSort, currentSort).Exec()
+	return
+}
+
+func DeleteClarksonsIndexById(indexId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := `DELETE FROM base_from_clarksons_index WHERE base_from_clarksons_index_id=? `
+	_, err = to.Raw(sql, indexId).Exec()
+	if err != nil {
+		return
+	}
+	sql = `DELETE FROM base_from_clarksons_data WHERE base_from_clarksons_index_id=? `
+	_, err = to.Raw(sql, indexId).Exec()
+	if err != nil {
+		return
+	}
+	return
+}
+
+func DeleteClarksonsIndexByIds(indexIds []int) (err error) {
+	if len(indexIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+	sql := `DELETE FROM base_from_clarksons_index WHERE base_from_clarksons_index_id IN (` + utils.GetOrmInReplace(len(indexIds)) + `) `
+	_, err = o.Raw(sql, indexIds).Exec()
+	if err != nil {
+		return
+	}
+	sql = `DELETE FROM base_from_clarksons_data WHERE base_from_clarksons_index_id IN (` + utils.GetOrmInReplace(len(indexIds)) + `) `
+	_, err = o.Raw(sql, indexIds).Exec()
+	if err != nil {
+		return
+	}
+	return
+}
+
+// MoveClarksonsIndex 移动指标分类
+func MoveClarksonsIndex(indexId, classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` UPDATE base_from_clarksons_index
+			SET
+			  classify_id = ?, modify_time=NOW() 
+			WHERE base_from_clarksons_index_id = ?`
+	_, err = o.Raw(sql, classifyId, indexId).Exec()
+	return
+}
+
+// GetClarksonsIndexMinSortByClassifyId 获取最小不等于0的排序
+func GetClarksonsIndexMinSortByClassifyId(classifyId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT min(sort) FROM base_from_clarksons_index WHERE classify_id=? and sort <> 0 `
+	err = o.Raw(sql, classifyId).QueryRow(&sort)
+	return
+}
+
+// GetClarksonsIndexInfoCount 分页查询指标信息行数
+func GetClarksonsIndexInfoCount(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT count(1) FROM base_from_clarksons_index WHERE index_code not in (select edb_code from edb_info) `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetClarksonsIndexInfoPage 分页查询指标信息
+func GetClarksonsIndexInfoPage(condition string, pars []interface{}) (items []*BaseFromRzdIndexAndData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE index_code not in (select edb_code from edb_info) `
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+
+}
+
+func GetClarksonsIndex(condition string, pars interface{}) (items []*BaseFromClarksonsIndexView, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_clarksons_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += `ORDER BY base_from_clarksons_index_id ASC `
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func GetClarksonsIndexLatestDate(indexCode string) (ModifyTime string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT modify_time FROM base_from_clarksons_data WHERE index_code=? ORDER BY modify_time DESC limit 1 `
+	err = o.Raw(sql, indexCode).QueryRow(&ModifyTime)
+	return
+}

+ 3 - 2
models/data_manage/base_from_trade_index.go

@@ -256,6 +256,7 @@ type BaseFromCoalmineFirmIndex struct {
 	IndexName                   string // 省份/企业名称
 	IndexCode                   string // 持买单量指标编码
 	DataTime                    string // 指标时间
+	DataTimeDate                string // 指标时间
 	DealValue                   string // 数据量
 	GroupName                   string // 集团名
 	Source                      string // 来源
@@ -477,7 +478,7 @@ func GetClassifyFirmByGroupName(groupName string) (items []*string, err error) {
 // 查询指标
 func GetPageFromCoalmineFirmIndexByFrequency(frequency, classify string, startSize, pageSize int) (items []*BaseFromCoalmineFirmIndex, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := `SELECT * FROM base_from_coalmine_firm_index WHERE frequency=? AND index_code=? ORDER BY data_time DESC LIMIT ?,?  `
+	sql := `SELECT * FROM base_from_coalmine_firm_index WHERE frequency=? AND index_code=? ORDER BY data_time_date DESC LIMIT ?,?  `
 	_, err = o.Raw(sql, frequency, classify, startSize, pageSize).QueryRows(&items)
 	return
 }
@@ -698,6 +699,6 @@ type BaseFromCoalmineClassify struct {
 func GetCoalmineClassifyList() (list []*BaseFromCoalmineClassify, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := "SELECT * FROM base_from_coalmine_classify"
-	_,err = o.Raw(sql).QueryRows(&list)
+	_, err = o.Raw(sql).QueryRows(&list)
 	return
 }

+ 101 - 71
models/data_manage/chart_info.go

@@ -1089,85 +1089,115 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 	}
 	chartEdbMappingIdList := make([]string, 0)
 
-	for _, v := range chartEdbInfoList {
-		// 查询该指标是否存在,如果存在的话,那么就去修改,否则新增
-		var tmpChartEdbMapping *ChartEdbMapping
-		csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND edb_info_id=? AND source = ? `
-		err = to.Raw(csql, req.ChartInfoId, v.EdbInfoId, utils.CHART_SOURCE_DEFAULT).QueryRow(&tmpChartEdbMapping)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			fmt.Println("QueryRow Err:", err.Error())
-			return err
-		}
-		if tmpChartEdbMapping != nil {
-			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(tmpChartEdbMapping.ChartEdbMappingId))
-			tmpChartEdbMapping.ModifyTime = time.Now()
-			tmpChartEdbMapping.MaxData = v.MaxData
-			tmpChartEdbMapping.MinData = v.MinData
-			tmpChartEdbMapping.IsOrder = v.IsOrder
-			tmpChartEdbMapping.IsAxis = v.IsAxis
-			tmpChartEdbMapping.EdbInfoType = v.EdbInfoType
-			tmpChartEdbMapping.LeadValue = v.LeadValue
-			tmpChartEdbMapping.LeadUnit = v.LeadUnit
-			tmpChartEdbMapping.ChartStyle = v.ChartStyle
-			tmpChartEdbMapping.ChartColor = v.ChartColor
-			tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
-			tmpChartEdbMapping.ChartWidth = v.ChartWidth
-			tmpChartEdbMapping.EdbAliasName = v.EdbAliasName
-			tmpChartEdbMapping.IsConvert = v.IsConvert
-			tmpChartEdbMapping.ConvertType = v.ConvertType
-			tmpChartEdbMapping.ConvertValue = v.ConvertValue
-			tmpChartEdbMapping.ConvertUnit = v.ConvertUnit
-			tmpChartEdbMapping.ConvertEnUnit = v.ConvertEnUnit
-			_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName",
-				"IsConvert", "ConvertType", "ConvertValue", "ConvertUnit", "ConvertEnUnit")
-			if err != nil {
-				fmt.Println("chart_edb_mapping Err:" + err.Error())
-				return err
-			}
-		} else {
-			mapItem := new(ChartEdbMapping)
-			mapItem.ChartInfoId = req.ChartInfoId
-			mapItem.EdbInfoId = v.EdbInfoId
-			mapItem.CreateTime = time.Now()
-			mapItem.ModifyTime = time.Now()
-			timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
-			mapItem.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp + "_" + strconv.Itoa(v.EdbInfoId))
-			mapItem.MaxData = v.MaxData
-			mapItem.MinData = v.MinData
-			mapItem.IsOrder = v.IsOrder
-			mapItem.IsAxis = v.IsAxis
-			mapItem.EdbInfoType = v.EdbInfoType
-			mapItem.LeadValue = v.LeadValue
-			mapItem.LeadUnit = v.LeadUnit
-			mapItem.ChartStyle = v.ChartStyle
-			mapItem.ChartColor = v.ChartColor
-			mapItem.PredictChartColor = v.PredictChartColor
-			mapItem.ChartWidth = v.ChartWidth
-			mapItem.Source = utils.CHART_SOURCE_DEFAULT
-			mapItem.EdbAliasName = v.EdbAliasName
-			mapItem.IsConvert = v.IsConvert
-			mapItem.ConvertType = v.ConvertType
-			mapItem.ConvertValue = v.ConvertValue
-			mapItem.ConvertUnit = v.ConvertUnit
-			mapItem.ConvertEnUnit = v.ConvertEnUnit
-			tmpId, err := to.Insert(mapItem)
-			if err != nil {
-				fmt.Println("AddChartEdbMapping Err:" + err.Error())
-				return err
+	// 获取已经配置的关联指标列表
+	var tmpChartEdbMappingList []*ChartEdbMapping
+	csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND source = ? ORDER BY chart_edb_mapping_id ASC`
+	_, err = to.Raw(csql, req.ChartInfoId, utils.CHART_SOURCE_DEFAULT).QueryRows(&tmpChartEdbMappingList)
+	if err != nil {
+		fmt.Println("获取已经配置的关联指标列表 Err:", err.Error())
+		return err
+	}
+
+	// 已经配置的关联指标列表长度下标
+	tmpEdbIndex := len(tmpChartEdbMappingList) - 1
+	// 当下要配置的关联指标列表长度下标
+	reqEdbIndex := len(chartEdbInfoList) - 1
+
+	addChartEdbList := make([]*ChartEdbMapping, 0)
+	removeIdList := make([]int, 0)
+	for k, v := range chartEdbInfoList {
+		// 如果当前下标小于等于已经配置的关联指标的最大长度,那么就校验
+		if k <= tmpEdbIndex {
+			tmpChartEdbMapping := tmpChartEdbMappingList[k]
+
+			// 顺序未变
+			if tmpChartEdbMapping.EdbInfoId == v.EdbInfoId {
+				chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(tmpChartEdbMapping.ChartEdbMappingId))
+				tmpChartEdbMapping.ModifyTime = time.Now()
+				tmpChartEdbMapping.MaxData = v.MaxData
+				tmpChartEdbMapping.MinData = v.MinData
+				tmpChartEdbMapping.IsOrder = v.IsOrder
+				tmpChartEdbMapping.IsAxis = v.IsAxis
+				tmpChartEdbMapping.EdbInfoType = v.EdbInfoType
+				tmpChartEdbMapping.LeadValue = v.LeadValue
+				tmpChartEdbMapping.LeadUnit = v.LeadUnit
+				tmpChartEdbMapping.ChartStyle = v.ChartStyle
+				tmpChartEdbMapping.ChartColor = v.ChartColor
+				tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
+				tmpChartEdbMapping.ChartWidth = v.ChartWidth
+				tmpChartEdbMapping.EdbAliasName = v.EdbAliasName
+				tmpChartEdbMapping.IsConvert = v.IsConvert
+				tmpChartEdbMapping.ConvertType = v.ConvertType
+				tmpChartEdbMapping.ConvertValue = v.ConvertValue
+				tmpChartEdbMapping.ConvertUnit = v.ConvertUnit
+				tmpChartEdbMapping.ConvertEnUnit = v.ConvertEnUnit
+				_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName",
+					"IsConvert", "ConvertType", "ConvertValue", "ConvertUnit", "ConvertEnUnit")
+				if err != nil {
+					fmt.Println("chart_edb_mapping Err:" + err.Error())
+					return err
+				}
+				continue
+			} else {
+				// 如果是指标的顺序变了,那么需要删除该配置,进行新的配置
+				removeIdList = append(removeIdList, tmpChartEdbMapping.ChartEdbMappingId)
 			}
-			mapItem.ChartEdbMappingId = int(tmpId)
-			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(mapItem.ChartEdbMappingId))
+		}
+
+		// 如果是指标的顺序变了 或者
+		// 如果当前下标是超过了已经配置的关联指标的最大长度,那么就新增
+		mapItem := new(ChartEdbMapping)
+		mapItem.ChartInfoId = req.ChartInfoId
+		mapItem.EdbInfoId = v.EdbInfoId
+		mapItem.CreateTime = time.Now()
+		mapItem.ModifyTime = time.Now()
+		timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		mapItem.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp + "_" + strconv.Itoa(v.EdbInfoId))
+		mapItem.MaxData = v.MaxData
+		mapItem.MinData = v.MinData
+		mapItem.IsOrder = v.IsOrder
+		mapItem.IsAxis = v.IsAxis
+		mapItem.EdbInfoType = v.EdbInfoType
+		mapItem.LeadValue = v.LeadValue
+		mapItem.LeadUnit = v.LeadUnit
+		mapItem.ChartStyle = v.ChartStyle
+		mapItem.ChartColor = v.ChartColor
+		mapItem.PredictChartColor = v.PredictChartColor
+		mapItem.ChartWidth = v.ChartWidth
+		mapItem.Source = utils.CHART_SOURCE_DEFAULT
+		mapItem.EdbAliasName = v.EdbAliasName
+		mapItem.IsConvert = v.IsConvert
+		mapItem.ConvertType = v.ConvertType
+		mapItem.ConvertValue = v.ConvertValue
+		mapItem.ConvertUnit = v.ConvertUnit
+		mapItem.ConvertEnUnit = v.ConvertEnUnit
+
+		addChartEdbList = append(addChartEdbList, mapItem)
+	}
+
+	// 当前保存的指标数与已有的指标数不一致,需要删除已有的指标关联配置
+	if reqEdbIndex < tmpEdbIndex {
+		for i := reqEdbIndex + 1; i <= tmpEdbIndex; i++ {
+			removeIdList = append(removeIdList, tmpChartEdbMappingList[i].ChartEdbMappingId)
 		}
 	}
-	if len(chartEdbMappingIdList) > 0 {
-		chartEdbMappingIdStr := strings.Join(chartEdbMappingIdList, ",")
-		dsql := `DELETE FROM chart_edb_mapping WHERE chart_info_id=? AND chart_edb_mapping_id NOT IN(` + chartEdbMappingIdStr + `)`
-		_, err = to.Raw(dsql, req.ChartInfoId).Exec()
+
+	// 删除已经移除了的指标关联配置
+	removeNum := len(removeIdList)
+	if removeNum > 0 {
+		dsql := `DELETE FROM chart_edb_mapping WHERE chart_info_id=? AND chart_edb_mapping_id  IN(` + utils.GetOrmInReplace(removeNum) + `)`
+		_, err = to.Raw(dsql, req.ChartInfoId, removeIdList).Exec()
 		if err != nil {
 			fmt.Println("delete err:" + err.Error())
 			return err
 		}
 	}
+
+	// 将新的指标关联配置写入
+	if len(addChartEdbList) > 0 {
+		_, err = to.InsertMulti(500, addChartEdbList)
+	}
+
 	return
 }
 

+ 1 - 1
models/data_manage/data_manage_permission/classify_no_auth_record.go

@@ -10,7 +10,7 @@ import (
 // @Description: 资产分类数据权限未授权记录表
 type DataPermissionClassifyNoAuthRecord struct {
 	DataPermissionClassifyNoAuthRecordId int64     `json:"data_permission_classify_no_auth_record_id" orm:"column(data_permission_classify_no_auth_record_id);pk"` // 资产分类数据操作记录id
-	Source                               int32     `json:"source"`                                                                                                 // 数据来源,1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
+	Source                               int32     `json:"source"`                                                                                                 // 数据来源,1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
 	SubSource                            int32     `json:"sub_source"`                                                                                             // 子来源 :ETA表格中的各种表格类型,以及图表的来源(这个是后续的扩展方向)
 	OpUniqueCode                         string    `json:"op_unique_code"`                                                                                         // 操作的唯一编码,主要是记录统一操作的日志
 	ClassifyId                           string    `json:"classify_id"`                                                                                            // 资产分类id(指标、图表、表格)

+ 26 - 4
models/data_manage/data_manage_permission/edb.go

@@ -107,11 +107,33 @@ func SetPermissionByEdbIdList(edbIdList []string, userIdList []int, edbInfoType
 
 	// 获取已经配置的指标权限用户
 	edbInfoPermissionList := make([]*EdbInfoPermission, 0)
-	sql := `SELECT * FROM edb_info_permission WHERE edb_info_type = ? AND edb_info_id in (` + utils.GetOrmInReplace(edbNum) + `) `
-	_, err = o.Raw(sql, edbInfoType, edbIdList).QueryRows(&edbInfoPermissionList)
-	if err != nil {
-		return
+	// 定义批次大小
+	batchSize := 500
+	var sql string
+	for i := 0; i < edbNum; i += batchSize {
+		// 确定当前批次的结束索引
+		end := i + batchSize
+		if end > edbNum {
+			end = edbNum
+		}
+
+		// 获取当前批次的 ID 列表
+		batch := edbIdList[i:end]
+
+		// 生成批次查询 SQL
+		sql = `SELECT * FROM edb_info_permission WHERE edb_info_type = ? AND edb_info_id in (` + utils.GetOrmInReplace(len(batch)) + `)`
+
+		// 执行查询
+		var batchResult []*EdbInfoPermission
+		_, err = o.Raw(sql, edbInfoType, batch).QueryRows(&batchResult)
+		if err != nil {
+			return
+		}
+
+		// 将批次结果追加到总列表中
+		edbInfoPermissionList = append(edbInfoPermissionList, batchResult...)
 	}
+
 	edbInfoPermissionMap := make(map[string]*EdbInfoPermission)
 	for _, v := range edbInfoPermissionList {
 		edbInfoPermissionMap[fmt.Sprint(v.EdbInfoId, "_", v.SysUserId)] = v

+ 1 - 1
models/data_manage/data_manage_permission/move.go

@@ -55,7 +55,7 @@ func ModifyDataUserIdByOldUserId(oldUserIdList []int, userId int, userName strin
 		}
 	}()
 
-	// 钢联化工数据库
+	// 上海钢联数据库
 	if isMoveMysteelChemical {
 		sql := `UPDATE base_from_mysteel_chemical_index SET sys_user_id=?,sys_user_real_name=? WHERE sys_user_id in (` + utils.GetOrmInReplace(num) + `)  `
 		_, err = o.Raw(sql, userId, userName, oldUserIdList).Exec()

+ 1 - 1
models/data_manage/data_manage_permission/move_record.go

@@ -9,7 +9,7 @@ import (
 // @Description: 数据资产转移记录表
 type DataPermissionMoveRecord struct {
 	DataPermissionMoveRecordId int64     `json:"data_permission_move_record_id" orm:"column(data_permission_move_record_id);pk"` // 数据操作记录id
-	Source                     int32     `json:"source"`                                                                         // 数据来源,1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
+	Source                     int32     `json:"source"`                                                                         // 数据来源,1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
 	SubSource                  int32     `json:"sub_source"`                                                                     // 子来源 :ETA表格中的各种表格类型,以及图表的来源(这个是后续的扩展方向)
 	OpUniqueCode               string    `json:"op_unique_code"`                                                                 // 操作的唯一编码,主要是记录统一操作的日志
 	DataId                     string    `json:"data_id"`                                                                        // 资产id(指标、图表、表格)

+ 1 - 1
models/data_manage/data_manage_permission/no_auth_record.go

@@ -10,7 +10,7 @@ import (
 // @Description: 资产数据权限设置记录表
 type DataPermissionNoAuthRecord struct {
 	DataPermissionNoAuthRecordId int64     `json:"data_permission_no_auth_record_id" orm:"column(data_permission_no_auth_record_id);pk"` // 资产数据操作记录id
-	Source                       int32     `json:"source"`                                                                               // 数据来源,1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
+	Source                       int32     `json:"source"`                                                                               // 数据来源,1:手工数据指标 2:上海钢联数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
 	SubSource                    int32     `json:"sub_source"`                                                                           // 子来源 :ETA表格中的各种表格类型,以及图表的来源(这个是后续的扩展方向)
 	OpUniqueCode                 string    `json:"op_unique_code"`                                                                       // 操作的唯一编码,主要是记录统一操作的日志
 	DataId                       string    `json:"data_id"`                                                                              // 资产id(指标、图表、表格)

+ 2 - 0
models/data_manage/edb_classify.go

@@ -76,6 +76,7 @@ func GetEdbClassifyEnCount(classifyNameEn string, parentId int, classifyType uin
 type EditEdbClassifyReq struct {
 	ClassifyName string `description:"分类名称"`
 	ClassifyId   int    `description:"分类名称"`
+	ParentId     int    `description:"父级分类id"`
 }
 
 func GetEdbClassifyById(classifyId int) (item *EdbClassify, err error) {
@@ -253,6 +254,7 @@ type EdbClassifyItems struct {
 	Button           EdbClassifyItemsButton `description:"操作权限"`
 	IsJoinPermission int                    `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
 	HaveOperaAuth    bool                   `description:"是否有数据权限"`
+	SelectDisable    bool                   `description:"是否可以被选中 前端用"`
 }
 
 type EdbClassifyIdItems struct {

+ 17 - 7
models/data_manage/edb_data_base.go

@@ -179,10 +179,10 @@ func GetEdbDataTableName(source, subSource int) (tableName string) {
 		tableName = "edb_data_sci99"
 	case utils.DATA_SOURCE_SCI_HQ:
 		tableName = "edb_data_sci_hq"
-	case utils.DATA_SOURCE_PREDICT: // 基础预测指标->30
-		tableName = "edb_data_predict_base"
 	case utils.DATA_SOURCE_LY: // 粮油商务网->86
 		tableName = "edb_data_ly"
+	case utils.DATA_SOURCE_PREDICT: // 基础预测指标->30
+		tableName = "edb_data_predict_base"
 	case utils.DATA_SOURCE_TRADE_ANALYSIS: // 持仓分析->92
 		tableName = "edb_data_trade_analysis"
 	case utils.DATA_SOURCE_CALCULATE_STL:
@@ -347,13 +347,15 @@ func GetBaseIndexInfoByEdbCode(edbCode string, source int) (item *BaseIndexInfo,
 	return
 }
 
-func GetBaseIndexTableName(source int) (tableName string) {
-	edbSource := EdbSourceIdMap[source]
-	if edbSource != nil {
-		tableName = edbSource.IndexTableName
-	}
+func GetEdbDataBaseByCodeAndDate(source, subSource int, edbCode string, startDate string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	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 GetEdbDataAllByEdbCodeAndSubSource(edbCode string, source, subSource, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCode)
@@ -396,6 +398,14 @@ func GetEdbDataTableNameAndSubSource(source, subSource int) (tableName string) {
 	return
 }
 
+func GetBaseIndexTableName(source int) (tableName string) {
+	edbSource := EdbSourceIdMap[source]
+	if edbSource != nil {
+		tableName = edbSource.IndexTableName
+	}
+	return
+}
+
 func GetEdbDataAllByEdbCodes(edbCodes []string, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCodes)

+ 2 - 2
models/data_manage/edb_data_mysteel_chemical.go

@@ -4,7 +4,7 @@ import (
 	"github.com/beego/beego/v2/client/orm"
 )
 
-// GetEdbDataMysteelChemicalMaxOrMinDate 根据钢联化工指标code获取最大、最小日期
+// GetEdbDataMysteelChemicalMaxOrMinDate 根据上海钢联指标code获取最大、最小日期
 func GetEdbDataMysteelChemicalMaxOrMinDate(edbCode string) (minDate, maxDate string, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT MIN(data_time) AS minDate,MAX(data_time) AS maxDate FROM edb_data_mysteel_chemical WHERE edb_code=? `
@@ -12,7 +12,7 @@ func GetEdbDataMysteelChemicalMaxOrMinDate(edbCode string) (minDate, maxDate str
 	return
 }
 
-// 更新钢联化工指标的刷新状态
+// 更新上海钢联指标的刷新状态
 func UpdateMysteelChemicalRefreshStatus(edbCode string, isStop int) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = ? WHERE index_code =? and is_stop=1`

+ 6 - 6
models/data_manage/edb_data_wind.go

@@ -80,14 +80,14 @@ func EdbInfoUpdateStatusByEdbInfoId(edbInfoIds []int, isStop int, calculateEdbIn
 
 	// 更改指标的更新状态
 	if len(edbInfoIds) == 1 {
-		sql := ` UPDATE edb_info SET no_update = ? WHERE edb_info_id=? `
-		_, err = o.Raw(sql, isStop, edbInfoIds[0]).Exec()
+		sql := ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id=? `
+		_, err = o.Raw(sql, isStop, time.Now(), edbInfoIds[0]).Exec()
 		if err != nil {
 			return
 		}
 	} else {
-		sql := ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(edbInfoIds)) + `) `
-		_, err = o.Raw(sql, isStop, edbInfoIds).Exec()
+		sql := ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(edbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, time.Now(), edbInfoIds).Exec()
 		if err != nil {
 			return
 		}
@@ -95,8 +95,8 @@ func EdbInfoUpdateStatusByEdbInfoId(edbInfoIds []int, isStop int, calculateEdbIn
 
 	if len(calculateEdbInfoIds) > 0 {
 		// 批量更新相关联的指标ID
-		sql := ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
-		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		sql := ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, time.Now(), calculateEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}

+ 66 - 51
models/data_manage/edb_info.go

@@ -38,35 +38,37 @@ type EdbInfo struct {
 	CreateTime       time.Time
 	ModifyTime       time.Time
 	BaseModifyTime   time.Time
-	MinValue         float64 `description:"指标最小值"`
-	MaxValue         float64 `description:"指标最大值"`
-	CalculateFormula string  `description:"计算公式"`
-	EdbType          int     `description:"指标类型:1:基础指标,2:计算指标"`
-	Sort             int     `description:"排序字段"`
-	LatestDate       string  `description:"数据最新日期(实际日期)"`
-	LatestValue      float64 `description:"数据最新值(实际值)"`
-	EndValue         float64 `description:"数据的最新值(预测日期的最新值)"`
-	MoveType         int     `description:"移动方式:1:领先(默认),2:滞后"`
-	MoveFrequency    string  `description:"移动频度"`
-	NoUpdate         int8    `description:"是否停止更新,0:继续更新;1:停止更新"`
-	ServerUrl        string  `description:"服务器地址"`
-	ChartImage       string  `description:"图表图片"`
-	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
-	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
-	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
-	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
-	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
-	TerminalCode     string  `description:"终端编码,用于配置在机器上"`
-	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
-	ErDataUpdateDate string  `description:"本次更新,数据发生变化的最早日期"`
-	SourceIndexName  string  `description:"数据源中的指标名称"`
-	SubSource        int     `description:"子数据来源:0:经济数据库,1:日期序列"`
-	SubSourceName    string  `description:"子数据来源名称"`
-	IndicatorCode    string  `description:"指标代码"`
-	StockCode        string  `description:"证券代码"`
-	Extra            string  `description:"指标额外配置"`
-	IsJoinPermission int     `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
-	IsStaticData     int     `description:"是否是静态指标,0否,1是"`
+	MinValue         float64   `description:"指标最小值"`
+	MaxValue         float64   `description:"指标最大值"`
+	CalculateFormula string    `description:"计算公式"`
+	EdbType          int       `description:"指标类型:1:基础指标,2:计算指标"`
+	Sort             int       `description:"排序字段"`
+	LatestDate       string    `description:"数据最新日期(实际日期)"`
+	LatestValue      float64   `description:"数据最新值(实际值)"`
+	EndValue         float64   `description:"数据的最新值(预测日期的最新值)"`
+	MoveType         int       `description:"移动方式:1:领先(默认),2:滞后"`
+	MoveFrequency    string    `description:"移动频度"`
+	NoUpdate         int8      `description:"是否停止更新,0:继续更新;1:停止更新"`
+	ServerUrl        string    `description:"服务器地址"`
+	ChartImage       string    `description:"图表图片"`
+	Calendar         string    `description:"公历/农历" orm:"default(公历);"`
+	DataDateType     string    `orm:"column(data_date_type);size(255);null;default(交易日)"`
+	ManualSave       int       `description:"是否有手动保存过上下限: 0-否; 1-是"`
+	TerminalCode     string    `description:"终端编码,用于配置在机器上"`
+	DataUpdateTime   string    `description:"最近一次数据发生变化的时间"`
+	ErDataUpdateDate string    `description:"本次更新,数据发生变化的最早日期"`
+	SourceIndexName  string    `description:"数据源中的指标名称"`
+	SubSource        int       `description:"子数据来源:0:经济数据库,1:日期序列"`
+	SubSourceName    string    `description:"子数据来源名称"`
+	IndicatorCode    string    `description:"指标代码"`
+	StockCode        string    `description:"证券代码"`
+	EmptyType        int       `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int       `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string    `description:"指标额外配置"`
+	IsJoinPermission int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	IsStaticData     int       `description:"是否是静态指标,0否,1是"`
+	SetUpdateTime    time.Time `description:"设置启用/禁用刷新状态的时间"`
+	EndDateType      int       `description:"预测指标截止日期类型:0:未来日期,1未来期数"`
 }
 
 type EdbInfoFullClassify struct {
@@ -465,10 +467,12 @@ type EdbInfoList struct {
 	NoUpdate         int8                    `description:"是否停止更新,0:继续更新;1:停止更新"`
 	IsJoinPermission int                     `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
 	HaveOperaAuth    bool                    `description:"是否有数据权限,默认:false"`
-	IsStaticData     int                     `description:"是否是静态指标,0否,1是"`
 	IsSupplierStop   int                     `description:"是否供应商停更:1:停更,0:未停更"`
+	IsStaticData     int                     `description:"是否是静态指标,0否,1是"`
 	MoveType         int                     `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency    string                  `description:"移动频度"`
+	MinValue         float64                 `description:"最小值"`
+	MaxValue         float64                 `description:"最大值"`
 }
 
 type EdbDataInsertConfigItem struct {
@@ -1274,11 +1278,11 @@ type EdbInfoView struct {
 	IsUpdate         int     `description:"当天是否已更新,1:未更新,2:已更新"`
 	LatestDate       string  `description:"数据最新日期(实际日期)"`
 	LatestValue      float64 `description:"数据最新值(实际值)"`
+	EndValue         float64 `description:"数据的最新值(预测日期的最新值)"`
 	SubSource        int     `description:"子数据来源:0:经济数据库,1:日期序列"`
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
 	StockCode        string  `description:"证券代码"`
-	EndValue         float64 `description:"数据的最新值(预测日期的最新值)"`
 }
 
 // 获取指标的所有计算指标,以及计算指标所依赖计算指标
@@ -1464,9 +1468,12 @@ func GetEdbInfoListByCondition(condition string, pars []interface{}, startSize,
 
 	sql += ` ORDER BY edb_info_id `
 	sql += orderDesc
-	sql += ` LIMIT ?,? `
+	if pageSize > 0 {
+		sql += ` LIMIT ?,? `
+		pars = append(pars, startSize, pageSize)
+	}
 
-	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
 
@@ -1821,15 +1828,15 @@ func ModifyEdbInfoUpdateStatus(edbIdList []int, isStop int, calculateEdbInfoIds
 	}()
 
 	// 更改指标的更新状态
-	sql := ` UPDATE edb_info SET no_update = ? WHERE  edb_info_id IN (` + utils.GetOrmInReplace(idNum) + `) `
-	_, err = o.Raw(sql, isStop, edbIdList).Exec()
+	sql := ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE  edb_info_id IN (` + utils.GetOrmInReplace(idNum) + `) `
+	_, err = o.Raw(sql, isStop, time.Now(), edbIdList).Exec()
 	if err != nil {
 		return
 	}
 	if len(calculateEdbInfoIds) > 0 {
 		// 批量更新相关联的指标ID
-		sql = ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
-		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, time.Now(), calculateEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
@@ -1977,6 +1984,11 @@ func getAllDataByMongo(edbInfoId, source, subSource int, startDataTime string) (
 	return
 }
 
+type ReplaceEdbInfoItem struct {
+	OldEdbInfo *EdbInfo
+	NewEdbInfo *EdbInfo
+}
+
 // GetEdbClassifyIdListBySource 获取普通指标的分类列表
 func GetEdbClassifyIdListBySource(source int) (items []int, err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -1996,9 +2008,15 @@ func GetEdbInfoByClassifyIdAndSource(classifyId, edbInfoType, source int) (items
 	return
 }
 
-type ReplaceEdbInfoItem struct {
-	OldEdbInfo *EdbInfo
-	NewEdbInfo *EdbInfo
+func GetEdbInfoListByCond(condition string, pars []interface{}) (list []*EdbInfoList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_info WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY create_time DESC `
+	_, err = o.Raw(sql, pars).QueryRows(&list)
+	return
 }
 
 type EdbInfoEditRecord struct {
@@ -2036,17 +2054,6 @@ type EdbInfoExtra struct {
 	ApiExtraPars string `description:"API-额外参数(如同花顺日期序列)"`
 }
 
-func GetEdbInfoListByCond(condition string, pars []interface{}) (list []*EdbInfoList, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM edb_info WHERE 1=1 `
-	if condition != "" {
-		sql += condition
-	}
-	sql += ` ORDER BY create_time DESC `
-	_, err = o.Raw(sql, pars).QueryRows(&list)
-	return
-}
-
 func GetThsHfEdbInfoMaxAndMinInfoByMongo(source, subSource int, edbCode string) (item *EdbInfoMaxAndMinInfo, err error) {
 	mogDataObj := new(mgo.EdbDataThsHf)
 	pipeline := []bson.M{
@@ -2130,3 +2137,11 @@ type EdbNameCheckResult struct {
 	EdbName string
 	Exist   bool
 }
+
+// UpdateEdbClassifyIdByChartInfoId
+func UpdateEdbClassifyIdByChartInfoId(chartInfoIds []int, classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` update edb_info set classify_id = ? WHERE edb_info_id in (` + utils.GetOrmInReplace(len(chartInfoIds)) + `) `
+	_, err = o.Raw(sql, classifyId, chartInfoIds).Exec()
+	return
+}

+ 15 - 15
models/data_manage/edb_info_relation.go

@@ -104,14 +104,14 @@ func AddOrUpdateEdbInfoRelation(objectId, objectType int, relationList []*EdbInf
 
 	if len(refreshEdbInfoIds) > 0 {
 		//todo 是否需要所有指标的刷新状态
-		sql := ` UPDATE edb_info SET no_update = 0 WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) AND  no_update = 1`
-		_, err = o.Raw(sql, refreshEdbInfoIds).Exec()
+		sql := ` UPDATE edb_info SET no_update = 0, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, time.Now(), refreshEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
 	}
 
-	//更新数据源钢联化工指标
+	//更新数据源上海钢联指标
 	if len(indexCodeList) > 0 {
 		// 更改数据源的更新状态
 		sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
@@ -172,14 +172,14 @@ func AddOrUpdateEdbInfoRelationMulti(relationList []*EdbInfoRelation, refreshEdb
 
 	if len(refreshEdbInfoIds) > 0 {
 		// todo 更新指标的刷新状态
-		sql := ` UPDATE edb_info SET no_update = 0 WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) AND no_update = 1`
-		_, err = o.Raw(sql, refreshEdbInfoIds).Exec()
+		sql := ` UPDATE edb_info SET no_update = 0, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, time.Now(), refreshEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
 	}
 
-	//更新数据源钢联化工指标
+	//更新数据源上海钢联指标
 	if len(indexCodeList) > 0 {
 		// 更改数据源的更新状态
 		sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
@@ -386,7 +386,7 @@ func ReplaceRelationEdbInfoId(oldEdbInfo, newEdbInfo *EdbInfo, edbRelationIds []
 		return
 	}
 
-	sourceWhere := ` and (refer_object_type in (1,2 ) or (refer_object_type=4 and refer_object_sub_type !=5) )` //平衡表和事件日历中的直接引用无需替换,
+	sourceWhere := ` and (refer_object_type in (1,2,5) or (refer_object_type=4 and refer_object_sub_type !=5) )` //平衡表和事件日历中的直接引用无需替换,
 	// 替换edb_info_id
 	sql = ` UPDATE edb_info_relation SET edb_info_id=?, source=?, edb_name=?, edb_code=?, modify_time=?, relation_time=?  WHERE edb_info_id=? ` + sourceWhere + ` and relation_type=0 and edb_info_relation_id in (` + utils.GetOrmInReplace(len(edbRelationIds)) + `)`
 	_, err = o.Raw(sql, newEdbInfo.EdbInfoId, newEdbInfo.Source, newEdbInfo.EdbName, newEdbInfo.EdbCode, now, now, oldEdbInfo.EdbInfoId, edbRelationIds).Exec()
@@ -416,14 +416,14 @@ func ReplaceRelationEdbInfoId(oldEdbInfo, newEdbInfo *EdbInfo, edbRelationIds []
 
 	if len(refreshEdbInfoIds) > 0 {
 		// todo 更新指标的刷新状态
-		sql := ` UPDATE edb_info SET no_update = 0 WHERE  edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) AND no_update = 1`
-		_, err = o.Raw(sql, refreshEdbInfoIds).Exec()
+		sql := ` UPDATE edb_info SET no_update = 0, set_update_time=? WHERE  edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, time.Now(), refreshEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
 	}
 
-	//更新数据源钢联化工指标
+	//更新数据源上海钢联指标
 	if len(indexCodeList) > 0 {
 		// 更改数据源的更新状态
 		sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
@@ -490,17 +490,17 @@ func UpdateSecondRelationEdbInfoId(edbRelationIds []int, relationList []*EdbInfo
 
 	if len(refreshEdbInfoIds) > 0 {
 		// todo 更新指标的刷新状态
-		sql := ` UPDATE edb_info SET no_update = 0 WHERE  edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) AND no_update = 1`
-		_, err = o.Raw(sql, refreshEdbInfoIds).Exec()
+		sql = ` UPDATE edb_info SET no_update = 0, set_update_time=? WHERE  edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, time.Now(), refreshEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
 	}
 
-	//更新数据源钢联化工指标
+	//更新数据源上海钢联指标
 	if len(indexCodeList) > 0 {
 		// 更改数据源的更新状态
-		sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
+		sql = ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
 		_, err = o.Raw(sql, indexCodeList).Exec()
 		if err != nil {
 			return
@@ -513,7 +513,7 @@ func UpdateSecondRelationEdbInfoId(edbRelationIds []int, relationList []*EdbInfo
 			relationCodes = append(relationCodes, relationCode)
 		}
 		if len(relationCodes) > 0 {
-			sql := ` UPDATE edb_info_relation e1  
+			sql = ` UPDATE edb_info_relation e1  
 JOIN edb_info_relation e2 ON e1.relation_code = e2.relation_code   
 SET e1.parent_relation_id = e2.edb_info_relation_id  
 WHERE  

+ 2 - 1
models/data_manage/excel/excel_info.go

@@ -415,7 +415,6 @@ FROM excel_info WHERE 1=1 AND is_delete=0 `
 	_, err = o.Raw(sql, pars).QueryRows(&item)
 	return
 }
-
 func GetExcelListCountByCondition(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT COUNT(1) AS count FROM excel_info WHERE 1=1 AND is_delete=0 `
@@ -516,6 +515,7 @@ func AddExcelInfoAndSheet(excelInfo *ExcelInfo, sheetParamsList []AddExcelSheetP
 			CalcChain:    sheetInfo.CalcChain,
 			ModifyTime:   time.Now(),
 			CreateTime:   time.Now(),
+			Frozen:       sheetInfo.Frozen,
 		}
 		sheetId, tmpErr := o.Insert(excelSheetInfo)
 		if tmpErr != nil {
@@ -591,6 +591,7 @@ func SaveExcelInfoAndSheet(excelInfo *ExcelInfo, updateExcelInfoParam []string,
 			CalcChain:    sheetInfo.CalcChain,
 			ModifyTime:   time.Now(),
 			CreateTime:   time.Now(),
+			Frozen:       sheetInfo.Frozen,
 		}
 		sheetId, tmpErr := o.Insert(excelSheetInfo)
 		if tmpErr != nil {

+ 3 - 0
models/data_manage/excel/excel_sheet.go

@@ -17,6 +17,7 @@ type ExcelSheet struct {
 	CalcChain    string    `description:"计算公式"`
 	ModifyTime   time.Time `description:"最近修改日期"`
 	CreateTime   time.Time `description:"创建日期"`
+	Frozen       string    `description:"冻结行"`
 }
 
 // Update 更新 excel表格的sheet基础信息
@@ -63,6 +64,7 @@ type SheetItem struct {
 	ModifyTime   time.Time       `description:"最近修改日期" json:"-"`
 	CreateTime   time.Time       `description:"创建日期"`
 	Data         *ExcelSheetData `description:"excel的数据"`
+	Frozen       string          `description:"冻结行"`
 }
 
 // GetAllSheetItemList 根据excel_id获取所有的sheet详情
@@ -95,4 +97,5 @@ type AddExcelSheetParams struct {
 	Config       string            `description:"配置信息"`
 	CalcChain    string            `description:"计算公式"`
 	DataList     []*ExcelSheetData `description:"excel的数据"`
+	Frozen       string            `description:"冻结行"`
 }

+ 11 - 0
models/data_manage/excel/request/excel_info.go

@@ -110,6 +110,7 @@ type TableDataReq struct {
 	Data          []EdbInfoData     `description:"数据列表"`
 	TextRowData   [][]ManualDataReq `description:"文本列表"`
 	DecimalConfig []DecimalConfig   `description:"小数位数配置"`
+	DateSize      interface{}       `description:"日期列的大小"`
 }
 type DecimalConfig struct {
 	Row     string `description:"行上的索引, 目前仅保存指标的日期"`
@@ -229,6 +230,16 @@ type CopyExcelInfoReq struct {
 	ExcelClassifyId int    `description:"分类id"`
 }
 
+// AddAndEditSandbox 添加/编辑沙盘的请求数据
+type AddAndEditSandbox struct {
+	ExcelInfoId       int    `description:"excel表格ID"`
+	Name              string `description:"沙盘名称"`
+	ChartPermissionId int    `description:"品种权限id"`
+	Content           string `description:"沙盘内容"`
+	PicUrl            string `description:"沙盘图片地址"`
+	SvgData           string `description:"沙盘svg图片数据"`
+}
+
 // MarkEditExcel 标记编辑表格的请求数据
 type MarkEditExcel struct {
 	ExcelInfoId int `description:"表格id"`

+ 1 - 0
models/data_manage/excel/request/mixed_table.go

@@ -137,6 +137,7 @@ type MixCellShowStyle struct {
 	Nt              string      `description:"变换类型:number 小数点位数改变,percent百分比," json:"nt"`
 	GlObj           interface{} `description:"公式对象:1:数值,2:百分比,3:文本" json:"glObj"`
 	Width           float64     `description:"单元格宽度" json:"width"`
+	Height          float64     `description:"单元格高度" json:"height"`
 	Decimal         *int        `description:"小数点位数" json:"decimal"`
 	Last            string      `description:"起始操作:nt|decimal" json:"last"`
 	Color           string      `description:"颜色值,#RRG" json:"color"`

+ 7 - 7
models/data_manage/factor_edb_series.go

@@ -360,6 +360,13 @@ func (a FactorEdbSeriesCorrelationMatrixOrder) Less(i, j int) bool {
 	return a[i].XData > a[j].XData
 }
 
+// CalculateCorrelationMatrixPars 计算相关性矩阵参数
+type CalculateCorrelationMatrixPars struct {
+	BaseEdbInfoId int               `description:"标的指标ID"`
+	SeriesIds     []int             `description:"系列IDs"`
+	Correlation   CorrelationConfig `description:"相关性配置"`
+}
+
 // RemoveSeriesAndMappingByFactorEdbSeriesId 删除系列和指标关联
 func (m *FactorEdbSeries) RemoveSeriesAndMappingByFactorEdbSeriesId(factorEdbSeriesChartMapping *FactorEdbSeriesChartMapping) (err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -421,10 +428,3 @@ func (m *FactorEdbSeries) RemoveSeriesAndMappingByFactorEdbSeriesId(factorEdbSer
 	}
 	return
 }
-
-// CalculateCorrelationMatrixPars 计算相关性矩阵参数
-type CalculateCorrelationMatrixPars struct {
-	BaseEdbInfoId int               `description:"标的指标ID"`
-	SeriesIds     []int             `description:"系列IDs"`
-	Correlation   CorrelationConfig `description:"相关性配置"`
-}

+ 8 - 8
models/data_manage/my_chart.go

@@ -914,14 +914,6 @@ func GetChartInfoViewByIdList(chartInfoIdList []int) (items []*ChartInfoView, er
 	return
 }
 
-// GetMyChartClassifyByClassifyId 主键获取分类
-func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM my_chart_classify WHERE my_chart_classify_id = ? `
-	err = o.Raw(sql, classifyId).QueryRow(&item)
-	return
-}
-
 // MyChartClassifyItem 我的图表分类信息
 type MyChartClassifyItem struct {
 	MyChartClassifyId   int    `description:"分类ID"`
@@ -972,6 +964,14 @@ func GetMyChartClassifyIdAndNum(cond string, pars []interface{}) (items []*MyCha
 	return
 }
 
+// GetMyChartClassifyByClassifyId 主键获取分类
+func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM my_chart_classify WHERE my_chart_classify_id = ? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}
+
 func GetChartClassifyByIds(chartClassifyIds []string) (chart_classify_ids string, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := `SELECT GROUP_CONCAT(DISTINCT t.chart_classify_id) AS chart_classify_ids

+ 4 - 4
models/data_manage/mysteel_chemical_classify.go

@@ -7,7 +7,7 @@ import (
 	"time"
 )
 
-// BaseFromMysteelChemicalClassify 钢联化工分类表
+// BaseFromMysteelChemicalClassify 上海钢联分类表
 type BaseFromMysteelChemicalClassify struct {
 	BaseFromMysteelChemicalClassifyId int       `orm:"column(base_from_mysteel_chemical_classify_id);pk"`
 	ClassifyName                      string    `description:"分类名称"`
@@ -21,7 +21,7 @@ type BaseFromMysteelChemicalClassify struct {
 	ClassifyNameEn                    string    `description:"英文分类名称"`
 }
 
-// AddBaseFromMysteelChemicalClassify 添加钢联化工分类
+// AddBaseFromMysteelChemicalClassify 添加上海钢联分类
 func AddBaseFromMysteelChemicalClassify(item *BaseFromMysteelChemicalClassify) (lastId int64, err error) {
 	o := orm.NewOrmUsingDB("data")
 	lastId, err = o.Insert(item)
@@ -66,7 +66,7 @@ func GetBaseFromMysteelChemicalClassifyById(classifyId int) (item *BaseFromMyste
 	return
 }
 
-// EditBaseFromMysteelChemicalClassify 修改钢联化工分类
+// EditBaseFromMysteelChemicalClassify 修改上海钢联分类
 func EditBaseFromMysteelChemicalClassify(classifyId int, classifyName string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := `UPDATE base_from_mysteel_chemical_classify SET classify_name=?,modify_time=NOW() WHERE base_from_mysteel_chemical_classify_id=? `
@@ -75,7 +75,7 @@ func EditBaseFromMysteelChemicalClassify(classifyId int, classifyName string) (e
 }
 
 // EditBaseFromMysteelChemicalClassifyEn
-// @Description: 修改钢联化工英文分类名称
+// @Description: 修改上海钢联英文分类名称
 // @author: Roc
 // @datetime 2024-04-16 16:34:53
 // @param classifyId int

+ 36 - 36
models/data_manage/mysteel_chemical_index.go

@@ -10,10 +10,10 @@ import (
 	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
-// BaseFromMysteelChemicalIndex 钢联化工指标表
+// BaseFromMysteelChemicalIndex 上海钢联指标表
 type BaseFromMysteelChemicalIndex struct {
 	BaseFromMysteelChemicalIndexId    int       `orm:"column(base_from_mysteel_chemical_index_id);pk"`
-	BaseFromMysteelChemicalClassifyId int       `orm:"column(base_from_mysteel_chemical_classify_id)" description:"钢联化工指标分类id"`
+	BaseFromMysteelChemicalClassifyId int       `orm:"column(base_from_mysteel_chemical_classify_id)" description:"上海钢联指标分类id"`
 	IndexCode                         string    `description:"指标编码"`
 	IndexName                         string    `description:"指标名称"`
 	Unit                              string    `description:"单位"`
@@ -80,7 +80,7 @@ var BaseFromMysteelChemicalIndexCols = struct {
 	ModifyTime:                     "modify_time",
 }
 
-// Update 更新钢联化工指标基础信息
+// Update 更新上海钢联指标基础信息
 func (item *BaseFromMysteelChemicalIndex) Update(cols []string) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	_, err = o.Update(item, cols...)
@@ -108,7 +108,7 @@ func (m *BaseFromMysteelChemicalIndex) GeItemsByCondition(condition string, pars
 	return
 }
 
-// AddBaseFromMysteelChemicalIndex 添加钢联化工指标
+// AddBaseFromMysteelChemicalIndex 添加上海钢联指标
 func AddBaseFromMysteelChemicalIndex(item *BaseFromMysteelChemicalIndex) (lastId int64, err error) {
 	o := orm.NewOrmUsingDB("data")
 	lastId, err = o.Insert(item)
@@ -120,17 +120,17 @@ func AddBaseFromMysteelChemicalIndex(item *BaseFromMysteelChemicalIndex) (lastId
 	return
 }
 
-// AddBaseFromMysteelChemicalIndex 添加钢联化工指标
+// AddBaseFromMysteelChemicalIndex 添加上海钢联指标
 func BatchAddBaseFromMysteelChemicalIndex(items []*BaseFromMysteelChemicalIndex) (lastId int64, err error) {
 	o := orm.NewOrmUsingDB("data")
 	_, err = o.InsertMulti(len(items), items)
 	return
 }
 
-// BaseFromMysteelChemicalData 钢联化工指标数据表
+// BaseFromMysteelChemicalData 上海钢联指标数据表
 type BaseFromMysteelChemicalData struct {
 	BaseFromMysteelChemicalDataId  int       `orm:"column(base_from_mysteel_chemical_data_id);pk"`
-	BaseFromMysteelChemicalIndexId int       `orm:"column(base_from_mysteel_chemical_index_id)" description:"钢联化工指标id"`
+	BaseFromMysteelChemicalIndexId int       `orm:"column(base_from_mysteel_chemical_index_id)" description:"上海钢联指标id"`
 	IndexCode                      string    `description:"指标编码"`
 	DataTime                       time.Time `description:"数据日期"`
 	Value                          float64   `description:"数据值"`
@@ -138,7 +138,7 @@ type BaseFromMysteelChemicalData struct {
 	CreateTime                     time.Time `description:"创建时间"`
 }
 
-// MysteelChemicalFrequency 钢联化工频度
+// MysteelChemicalFrequency 上海钢联频度
 type MysteelChemicalFrequency struct {
 	Frequency string `description:"频度:1-日度 2-周度 3-月度 4-季度 5-年度 99-无固定频率"`
 }
@@ -153,7 +153,7 @@ func GetMysteelChemicalIndexByClassifyId(classifyId int) (items []*BaseFromMyste
 	return
 }
 
-// MysteelChemicalFrequencyByClassifyId 根据分类id获取钢联化工频度数据列表
+// MysteelChemicalFrequencyByClassifyId 根据分类id获取上海钢联频度数据列表
 func MysteelChemicalFrequencyByClassifyId(classifyId int) (items []*MysteelChemicalFrequency, err error) {
 	o := orm.NewOrmUsingDB("data")
 	if classifyId == 0 {
@@ -167,7 +167,7 @@ func MysteelChemicalFrequencyByClassifyId(classifyId int) (items []*MysteelChemi
 	}
 }
 
-// GetMysteelChemicalFrequency 获取钢联化工频度数据列表
+// GetMysteelChemicalFrequency 获取上海钢联频度数据列表
 func GetMysteelChemicalFrequency(condition string, pars []interface{}) (items []*MysteelChemicalFrequency, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT frequency FROM base_from_mysteel_chemical_index WHERE 1=1 AND frequency != "" `
@@ -179,11 +179,11 @@ func GetMysteelChemicalFrequency(condition string, pars []interface{}) (items []
 	return
 }
 
-// MysteelChemicalList 钢联化工指标列表
+// MysteelChemicalList 上海钢联指标列表
 type MysteelChemicalList struct {
 	Id                                int                `orm:"column(base_from_mysteel_chemical_index_id)"`
-	BaseFromMysteelChemicalClassifyId int                `orm:"column(base_from_mysteel_chemical_classify_id)" description:"钢联化工指标分类id"`
-	ParentClassifyId                  int                `description:"钢联化工指标父级分类id"`
+	BaseFromMysteelChemicalClassifyId int                `orm:"column(base_from_mysteel_chemical_classify_id)" description:"上海钢联指标分类id"`
+	ParentClassifyId                  int                `description:"上海钢联指标父级分类id"`
 	IndexCode                         string             `description:"指标编码"`
 	IndexName                         string             `description:"指标名称"`
 	UnitName                          string             `orm:"column(unit)"`
@@ -197,13 +197,13 @@ type MysteelChemicalList struct {
 	DataList                          []*MysteelChemicalData
 }
 
-// MysteelChemicalData 钢联化工数据列表
+// MysteelChemicalData 上海钢联数据列表
 type MysteelChemicalData struct {
 	InputValue string `orm:"column(value)" description:"值"`
 	DataTime   string `orm:"column(data_time)" description:"日期"`
 }
 
-// GetMysteelChemicalIndex 根据分类id获取钢联化工频度数据列表
+// GetMysteelChemicalIndex 根据分类id获取上海钢联频度数据列表
 func GetMysteelChemicalIndex(condition string, pars []interface{}) (items []*MysteelChemicalList, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM base_from_mysteel_chemical_index WHERE 1=1 `
@@ -216,7 +216,7 @@ func GetMysteelChemicalIndex(condition string, pars []interface{}) (items []*Mys
 	return
 }
 
-// GetMysteelChemicalIndexData 根据指标code获取钢联化工数据列表
+// GetMysteelChemicalIndexData 根据指标code获取上海钢联数据列表
 func GetMysteelChemicalIndexData(indexCode string, startSize, pageSize int) (items []*MysteelChemicalData, err error) {
 	sql := ` SELECT * FROM (
 	SELECT DISTINCT a.index_code,a.value,a.data_time FROM base_from_mysteel_chemical_data AS a WHERE index_code=? 
@@ -229,7 +229,7 @@ func GetMysteelChemicalIndexData(indexCode string, startSize, pageSize int) (ite
 	return
 }
 
-// GetMysteelChemicalIndexDataCount 根据指标code获取钢联化工数据列表 获取钢联数据总数
+// GetMysteelChemicalIndexDataCount 根据指标code获取上海钢联数据列表 获取钢联数据总数
 func GetMysteelChemicalIndexDataCount(indexCode string) (count int, err error) {
 	sql := `SELECT COUNT(1) AS count FROM (
 			SELECT * FROM (
@@ -328,7 +328,7 @@ func GetBaseFromMysteelChemicalDataTimeByIndexId(indexIdList []int) (items []str
 	return
 }
 
-// GetMysteelChemicalIndexDataByCode 通过钢联化工指标code获取所有数据列表
+// GetMysteelChemicalIndexDataByCode 通过上海钢联指标code获取所有数据列表
 func GetMysteelChemicalIndexDataByCode(indexCode string) (items []*MysteelChemicalData, err error) {
 	sql := ` SELECT * FROM (
 	SELECT DISTINCT a.index_code,a.value,a.data_time FROM base_from_mysteel_chemical_data AS a WHERE index_code=? 
@@ -341,7 +341,7 @@ func GetMysteelChemicalIndexDataByCode(indexCode string) (items []*MysteelChemic
 	return
 }
 
-// MoveBaseFromMysteelChemicalIndex 移动钢联化工指标分类
+// MoveBaseFromMysteelChemicalIndex 移动上海钢联指标分类
 func MoveBaseFromMysteelChemicalIndex(chartInfoId, classifyId int) (err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` UPDATE base_from_mysteel_chemical_index
@@ -371,7 +371,7 @@ func GetFirstBaseFromMysteelChemicalIndexByClassifyId(classifyId int) (item *Bas
 	return
 }
 
-// GetMysteelChemicalIndexCount 根据条件获取钢联化工数据
+// GetMysteelChemicalIndexCount 根据条件获取上海钢联数据
 func GetMysteelChemicalIndexCount(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT COUNT(1) AS count FROM base_from_mysteel_chemical_index WHERE 1=1 `
@@ -384,7 +384,7 @@ func GetMysteelChemicalIndexCount(condition string, pars []interface{}) (count i
 	return
 }
 
-// GetMysteelChemicalIndexList 根据分类id获取钢联化工频度数据列表
+// GetMysteelChemicalIndexList 根据分类id获取上海钢联频度数据列表
 func GetMysteelChemicalIndexList(condition string, pars []interface{}, startSize, pageSize int, orderDesc string) (items []*BaseFromMysteelChemicalIndex, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM base_from_mysteel_chemical_index WHERE 1=1 `
@@ -497,7 +497,7 @@ type TerminalNum struct {
 	Num          int    `description:"num"`
 }
 
-// GetMysteelChemicalGroupTerminalNum 获取钢联化工指标的终端分布
+// GetMysteelChemicalGroupTerminalNum 获取上海钢联指标的终端分布
 func GetMysteelChemicalGroupTerminalNum() (items []*TerminalNum, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT terminal_code,count(1) num FROM base_from_mysteel_chemical_index GROUP BY terminal_code ORDER BY num ASC `
@@ -509,7 +509,7 @@ func GetMysteelChemicalGroupTerminalNum() (items []*TerminalNum, err error) {
 // @Description: 刷新配置的基础指标信息结构体
 type BaseRefreshEdbInfo struct {
 	EdbInfoId       int
-	ClassifyId      int    `description:"钢联化工指标分类id"`
+	ClassifyId      int    `description:"上海钢联指标分类id"`
 	IndexCode       string `description:"指标编码"`
 	IndexName       string `description:"指标名称"`
 	EndDate         string `description:"最新日期"`
@@ -530,7 +530,7 @@ type RefreshBaseEdbInfoResp struct {
 }
 
 // GetMysteelChemicalBaseInfoList
-// @Description: 获取钢联化工数据列表
+// @Description: 获取上海钢联数据列表
 // @author: Roc
 // @datetime 2024-01-10 14:28:35
 // @param condition string
@@ -572,7 +572,7 @@ func GetMysteelChemicalBaseInfoList(condition string, pars []interface{}, orderB
 }
 
 // ModifyMysteelChemicalUpdateStatus
-// @Description:  修改钢联化工数据停更状态
+// @Description:  修改上海钢联数据停更状态
 // @author: Roc
 // @datetime 2024-01-08 16:23:31
 // @param edbIdList []int
@@ -620,8 +620,8 @@ func ModifyMysteelChemicalUpdateStatus(edbIdList []int, indexCodeList []string,
 	}
 
 	// 更改指标的更新状态
-	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
-	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, indexCodeList).Exec()
+	sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
+	_, err = o.Raw(sql, isStop, time.Now(), utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, indexCodeList).Exec()
 	if err != nil {
 		return
 	}
@@ -630,7 +630,7 @@ func ModifyMysteelChemicalUpdateStatus(edbIdList []int, indexCodeList []string,
 }
 
 // ModifyMysteelChemicalUpdateStatusByEdbInfoId
-// @Description:  修改单个钢联化工指标停更状态,同时停更依赖于该指标的计算指标
+// @Description:  修改单个上海钢联指标停更状态,同时停更依赖于该指标的计算指标
 // @author: Roc
 // @datetime 2024-01-08 16:23:31
 // @param edbIdList []int
@@ -658,15 +658,15 @@ func ModifyMysteelChemicalUpdateStatusByEdbInfoId(edbInfoId, isStop int, edbCode
 	}
 
 	// 更改指标的更新状态
-	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_info_id=? `
-	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, edbInfoId).Exec()
+	sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE source = ? AND sub_source= ? AND edb_info_id=? `
+	_, err = o.Raw(sql, isStop, time.Now(), utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, edbInfoId).Exec()
 	if err != nil {
 		return
 	}
 	if len(calculateEdbInfoIds) > 0 {
 		// 批量更新相关联的指标ID
-		sql = ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
-		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, time.Now(), calculateEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}
@@ -696,15 +696,15 @@ func ModifyMysteelChemicalUpdateStatusByEdbInfoIds(edbInfoIds []int, isStop int,
 	}
 
 	// 更改指标的更新状态
-	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND edb_info_id IN (` + utils.GetOrmInReplace(len(edbInfoIds)) + `) `
-	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, edbInfoIds).Exec()
+	sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE source = ? AND edb_info_id IN (` + utils.GetOrmInReplace(len(edbInfoIds)) + `) `
+	_, err = o.Raw(sql, isStop, time.Now(), utils.DATA_SOURCE_MYSTEEL_CHEMICAL, edbInfoIds).Exec()
 	if err != nil {
 		return
 	}
 	if len(calculateEdbInfoIds) > 0 {
 		// 批量更新相关联的指标ID
-		sql = ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
-		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, time.Now(), calculateEdbInfoIds).Exec()
 		if err != nil {
 			return
 		}

+ 3 - 0
models/data_manage/predict_edb_conf.go

@@ -19,6 +19,7 @@ type PredictEdbConf struct {
 	EndDate          time.Time `description:"截止日期"`
 	ModifyTime       time.Time `description:"修改时间"`
 	CreateTime       time.Time `description:"添加时间"`
+	EndNum           int       `description:"截止期数"`
 }
 
 // PredictEdbConfDetail 预测规则 和 规则相关联的指标
@@ -35,6 +36,7 @@ type PredictEdbConfDetail struct {
 	ModifyTime       time.Time                               `description:"修改时间"`
 	CreateTime       time.Time                               `description:"添加时间"`
 	CalculateList    []*PredictEdbConfCalculateMappingDetail `description:"配置与指标的关联信息"`
+	EndNum           int                                     `description:"截止期数"`
 }
 
 // PredictEdbConfAndData 预测规则和其对应的动态数据
@@ -46,6 +48,7 @@ type PredictEdbConfAndData struct {
 	FixedValue       float64        `description:"固定值"`
 	Value            string         `description:"配置的值"`
 	EndDate          time.Time      `description:"截止日期"`
+	EndNum           int            `description:"截止期数"`
 	ModifyTime       time.Time      `description:"修改时间"`
 	CreateTime       time.Time      `description:"添加时间"`
 	DataList         []*EdbDataList `description:"动态数据"`

+ 74 - 0
models/data_manage/request/clarksons_data.go

@@ -0,0 +1,74 @@
+package request
+
+type AddBaseFromClarksonsClassifyReq struct {
+	ParentId     int    `description:"上级id"`
+	ClassifyName string `description:"分类名称"`
+}
+
+// DelBaseFromClarksonsReq 删除卓创红期分类
+type DelBaseFromClarksonsClassifyReq struct {
+	BaseFromClassifyId int `description:"分类id"`
+}
+
+// EditBaseFromSciClassifyReq 编辑卓创红期分类
+type EditBaseFromClarksonsClassifyReq struct {
+	ClassifyName       string `description:"分类名称"`
+	BaseFromClassifyId int    `description:"分类id"`
+}
+
+// EditBaseFromClarksonsReq 编辑卓创红期指标所属分类
+type EditBaseFromClarksonsReq struct {
+	BaseFromClarksonsIndexId int `description:"指标id"`
+	BaseFromClassifyId       int `description:"分类id"`
+}
+
+// DelBaseFromClarksonsReq 删除卓创红期指标
+type DelBaseFromClarksonsReq struct {
+	BaseFromClarksonsIndexId int `description:"指标id"`
+}
+
+// ResetBaseFromClarksonsReq 重置指标所属分类
+type ResetBaseFromClarksonsReq struct {
+	BaseFromClarksonsIndexId int `description:"指标id"`
+}
+
+// ClarksonsDataBatchAddCheckReq 卓创红期指标批量添加校验
+type ClarksonsDataBatchAddCheckReq struct {
+	// MysteelChemicalDataListReq
+	IndexCodes []string `description:"指标编码"`
+}
+
+// ClarksonsDataBatchListReq 卓创红期指标批量列表
+type ClarksonsDataBatchListReq struct {
+	ClassifyIds string `description:"分类id"`
+	KeyWord     string `description:"关键字"`
+	Frequencies string `description:"频度"`
+	SelectedId  []int  `description:"已选指标id, 为true时表示反选"`
+	IsSelectAll bool   `description:"是否查询全部, 默认false, true:全选, false:查询已选"`
+	PageSize   int    `description:"每页条数"`
+	CurrentIndex int   `description:"当前页"`
+}
+
+// MoveBaseFromClarksonsClassifyReq 移动分类请求参数
+type MoveBaseFromClarksonsClassifyReq struct {
+	BaseFromClassifyId int `description:"分类id"`
+	ParentId           int `description:"父级分类id"`
+	PrevClassifyId     int `description:"上一个兄弟节点分类id"`
+	NextClassifyId     int `description:"下一个兄弟节点分类id"`
+}
+
+// MoveBaseFromClarksonsReq 移动指标请求参数
+type MoveBaseFromClarksonsReq struct {
+	BaseFromClassifyId           int `description:"分类id"`
+	BaseFromClarksonsIndexId     int `description:"指标id"`
+	PrevBaseFromClarksonsIndexId int `description:"上一个兄弟节点id"`
+	NextBaseFromClarksonsIndexId int `description:"下一个兄弟节点id"`
+}
+
+// ExportClarksonsExcelReq导出卓创红期excel指标
+type ExportClarksonsExcelReq struct {
+	KeyWord            string   `description:"关键字, 指标编码或指标ID"`
+	IndexCode          []string `description:"指标编码,全选时,表示反选"`
+	IsSelectedAll      bool     `description:"是否全选:true:全选|false: 无"`
+	BaseFromClassifyId int      `description:"指标id"`
+}

+ 12 - 0
models/data_manage/request/edb_info.go

@@ -6,3 +6,15 @@ type ModifyEdbInfoReq struct {
 	MaxValue  float64 `description:"最大值"`
 	MinValue  float64 `description:"最小值"`
 }
+
+// ModifyEdbListReq 批量编辑指标请求参数
+type ModifyEdbListReq struct {
+	SelectAll        bool
+	SubClassify      bool `description:"是否关联指标子分类"`
+	EdbClassifyIds string
+	SysUserIds       string
+	KeyWord          string
+	EdbInfoIds       string `description:"图表ID"`
+	ClassifyId       int    `description:"新图表分类"`
+	Sources          string
+}

+ 7 - 6
models/data_manage/request/mysteel_chemical_data.go

@@ -1,13 +1,13 @@
 package request
 
-// AddBaseFromMysteelChemicalClassifyReq 添加钢联化工分类请求
+// AddBaseFromMysteelChemicalClassifyReq 添加上海钢联分类请求
 type AddBaseFromMysteelChemicalClassifyReq struct {
 	ParentId     int    `description:"上级id"`
 	ClassifyName string `description:"分类名称"`
 	Level        int    `description:"层级,第一级传0,其余传上一级的层级"`
 }
 
-// EditBaseFromMysteelChemicalClassifyReq 修改钢联化工分类请求
+// EditBaseFromMysteelChemicalClassifyReq 修改上海钢联分类请求
 type EditBaseFromMysteelChemicalClassifyReq struct {
 	ClassifyName                      string `description:"分类名称"`
 	BaseFromMysteelChemicalClassifyId int    `description:"分类id"`
@@ -21,12 +21,12 @@ type MoveBaseFromMysteelChemicalClassifyReq struct {
 	NextBaseFromMysteelChemicalClassifyId   int `description:"下一个兄弟节点分类id"`
 }
 
-// DelBaseFromMysteelChemicalClassifyReq 删除钢联化工分类请求
+// DelBaseFromMysteelChemicalClassifyReq 删除上海钢联分类请求
 type DelBaseFromMysteelChemicalClassifyReq struct {
 	BaseFromMysteelChemicalClassifyId int `description:"分类id"`
 }
 
-// AddBaseFromMysteelChemicalReq 添加钢联化工请求
+// AddBaseFromMysteelChemicalReq 添加上海钢联请求
 type AddBaseFromMysteelChemicalReqItem struct {
 	BaseFromMysteelChemicalIndexId    int    `description:"指标id"`
 	BaseFromMysteelChemicalClassifyId int    `description:"分类id"`
@@ -34,12 +34,13 @@ type AddBaseFromMysteelChemicalReqItem struct {
 	UpdateWeek                        string `description:"更新周期"`
 	UpdateTime                        string `description:"更新时间点,多个时间点用英文,隔开"`
 }
-// AddBaseFromMysteelChemicalReq 添加钢联化工请求
+
+// AddBaseFromMysteelChemicalReq 添加上海钢联请求
 type AddBaseFromMysteelChemicalReq struct {
 	List []AddBaseFromMysteelChemicalReqItem
 }
 
-// DelBaseFromMysteelChemicalReq 删除钢联化工请求
+// DelBaseFromMysteelChemicalReq 删除上海钢联请求
 type DelBaseFromMysteelChemicalReq struct {
 	BaseFromMysteelChemicalIndexId int `description:"指标id"`
 }

+ 9 - 7
models/data_manage/request/predict_edb_info.go

@@ -18,6 +18,7 @@ type PredictEdbInfoChartDataReq struct {
 	RuleList     []RuleConfig `description:"配置规则列表"`
 	DataDateType string       `description:"数据日期类型,枚举值:交易日、自然日"`
 	StartYear    int          `description:"当选择的日期类型为最近N年类型时,即date_type=20, 用start_year表示N"`
+	EndDateType  int          `description:"截止日期类型:0:未来日期,1未来期数"`
 }
 
 // AddPredictEdbInfoReq 添加预测指标请求
@@ -29,13 +30,13 @@ type AddPredictEdbInfoReq struct {
 	RuleType        int          `description:"预测规则,1:最新,2:固定值"`
 	FixedValue      float64      `description:"固定值"`
 	RuleList        []RuleConfig `description:"配置规则列表"`
-
-	DataDateType string  `description:"日期类型,枚举值:交易日、自然日"`
-	MaxValue     float64 `description:"最大值"`
-	MinValue     float64 `description:"最小值"`
-	EdbInfoId    int     `description:"指标ID"`
-	AdminId      int     `description:"添加人id"`
-	AdminName    string  `description:"添加人名称"`
+	DataDateType    string       `description:"日期类型,枚举值:交易日、自然日"`
+	MaxValue        float64      `description:"最大值"`
+	MinValue        float64      `description:"最小值"`
+	EdbInfoId       int          `description:"指标ID"`
+	AdminId         int          `description:"添加人id"`
+	AdminName       string       `description:"添加人名称"`
+	EndDateType     int          `description:"截止日期类型:0:未来日期,1未来期数"`
 }
 
 // RuleConfig 预测规则配置
@@ -45,6 +46,7 @@ type RuleConfig struct {
 	EmptyType    int                          `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType int                          `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EndDate      string                       `description:"截止日期"`
+	EndNum       int                          `description:"截止期数"`
 	EdbInfoIdArr []data_manage.EdbInfoFromTag `description:"指标信息"`
 }
 

+ 35 - 0
models/data_manage/response/clarksons_data.go

@@ -0,0 +1,35 @@
+package response
+
+import (
+	"eta/eta_api/models/data_manage"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type ClarksonsIndexPageListResp struct {
+	List   []*data_manage.BaseFromClarksonsIndexView
+	Paging *paging.PagingItem
+}
+
+type EditClarksonsIndexInfoResp struct {
+	BaseFromClarksonsIndexId int
+	IndexCode            string
+}
+
+type ClarksonsSingleDataResp struct {
+	BaseFromClarksonsIndexId int
+	ClassifyId           int
+	EdbInfoId            int
+	Name                 string
+	IndexCode            string
+	IndexName            string
+	Frequency            string
+	Unit                 string
+	ApiStartTime         string
+	ApiUpdateTime        string
+	StartTime            string
+	FinishTime           string
+	CreateTime           string
+	ModifyTime           string
+	Data                 []*data_manage.BaseFromClarksonsData
+}

+ 3 - 2
models/data_manage/smm_data.go

@@ -4,6 +4,7 @@ import (
 	"eta/eta_api/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
 )
 
 type SmmClassify struct {
@@ -341,8 +342,8 @@ func ModifySmmUpdateStatus(edbIdList []int, indexCodeList []string, isStop int)
 	}
 
 	// 更改指标的更新状态
-	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
-	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_YS, 0, indexCodeList).Exec()
+	sql = ` UPDATE edb_info SET no_update = ?, set_update_time=? WHERE source = ? AND sub_source= ? AND edb_code IN (` + utils.GetOrmInReplace(codeNum) + `) `
+	_, err = o.Raw(sql, isStop, time.Now(), utils.DATA_SOURCE_YS, 0, indexCodeList).Exec()
 	if err != nil {
 		return
 	}

+ 1 - 1
models/data_manage/trade_analysis/trade_analysis.go

@@ -154,7 +154,7 @@ type GetPositionTopListItem struct {
 
 func GetTradePositionTop(exchange string, classifyName, classifyType, dataTime string) (list []TradePositionTop, err error) {
 	tableName := "trade_position_" + exchange + "_top"
-	sql := `SELECT * FROM ` + tableName + " WHERE classify_name=? and classify_type=? and data_time=? and `rank` <=20 and `rank` > 0 ORDER BY deal_value desc"
+	sql := "SELECT * FROM " + tableName + " WHERE classify_name=? and classify_type=? and data_time=? and `rank` <=20 and `rank` > 0 ORDER BY deal_value desc"
 
 	o := orm.NewOrmUsingDB("data")
 	_, err = o.Raw(sql, classifyName, classifyType, dataTime).QueryRows(&list)

+ 24 - 6
models/db.go

@@ -20,6 +20,7 @@ import (
 	edbmonitor "eta/eta_api/models/edb_monitor"
 	"eta/eta_api/models/eta_trial"
 	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/models/material"
 	"eta/eta_api/models/ppt_english"
 	"eta/eta_api/models/report"
 	"eta/eta_api/models/report_approve"
@@ -186,15 +187,15 @@ func init() {
 	// 初始化跨品种分析表
 	initCrossVariety()
 
+	// 初始化图表主题
+	initChartTheme()
+
 	//初始化AI
 	initAi()
 
 	// 报告审批
 	initReportApprove()
 
-	// 初始化图表主题
-	initChartTheme()
-
 	// 初始化指标刷新
 	initEdbRefresh()
 
@@ -210,6 +211,9 @@ func init() {
 	// 初始化因子指标系列
 	initFactorEdbSeries()
 
+	// 注册素材库表
+	initMaterial()
+
 	// 初始化STL指标系列
 	initStlEdbInfo()
 
@@ -221,6 +225,7 @@ func init() {
 		initBinlog()
 		go binlogSvr.ListenMysql()
 	}
+
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	afterInitTable()
 
@@ -348,7 +353,7 @@ func initEdbData() {
 		new(data_manage.EdbInfoCalculateMapping),
 		new(data_manage.PredictEdbConf),                  //预测指标配置
 		new(data_manage.BaseFromMysteelChemicalClassify), //预测指标配置
-		new(data_manage.BaseFromMysteelChemicalIndex),    //钢联化工
+		new(data_manage.BaseFromMysteelChemicalIndex),    //上海钢联
 		new(data_manage.BaseFromEiaSteoClassify),         // Eia steo 报告指标
 		new(data_manage.BaseFromEiaSteoIndex),            // Eia steo 报告指标分类
 		new(data_manage.PredictEdbRuleData),              //预测指标,动态规则的计算数据
@@ -370,14 +375,17 @@ func initEdbData() {
 		new(data_manage.EdbDataInsertConfig),      // 指标数据插入配置表
 		new(data_manage.EdbInfoNoPermissionAdmin), //指标不可见用户配置表
 		new(data_manage.EdbTerminal),              //指标终端
+		new(data_manage.EdbInfoRelation),          //指标关系表
 		new(data_manage.BaseFromThsHfIndex),
 		new(data_manage.BaseFromThsHfData),
 		new(data_manage.BaseFromThsHfClassify),
 		new(data_manage.BaseFromEdbMapping),
-		new(data_manage.EdbInfoRelation), //指标关系表
 		new(data_manage.BaseFromSciHqClassify),
 		new(data_manage.BaseFromSciHqIndex),
 		new(data_manage.BaseFromSciHqData),
+		new(data_manage.BaseFromClarksonsClassify),
+		new(data_manage.BaseFromClarksonsIndex),
+		new(data_manage.BaseFromClarksonsData),
 	)
 }
 
@@ -498,7 +506,8 @@ func initBusinessConf() {
 
 func initOutLink() {
 	orm.RegisterModel(
-		new(OutLink)) // 外部链接表
+		new(OutLink), // 外部链接表
+	)
 }
 
 // initEtaTrial 试用平台相关表
@@ -659,6 +668,15 @@ func initFactorEdbSeries() {
 	)
 }
 
+// initMaterial 注册素材库表
+func initMaterial() {
+	//注册对象
+	orm.RegisterModel(
+		new(material.Material),         //素材库表
+		new(material.MaterialClassify), //素材库分类表
+	)
+}
+
 func initStlEdbInfo() {
 	orm.RegisterModel(
 		new(stl.CalculateStlConfig),        // STL指标配置

+ 250 - 0
models/material/material.go

@@ -0,0 +1,250 @@
+package material
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"time"
+)
+
+type Material struct {
+	MaterialId      int       `orm:"column(material_id);pk" description:"素材id"`
+	MaterialName    string    `description:"素材名称"`
+	MaterialNameEn  string    `description:"英文素材名称"`
+	ImgUrl          string    `description:"素材图片地址"`
+	SysUserId       int       `description:"作者id"`
+	SysUserRealName string    `description:"作者名称"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+	ClassifyId      int       `description:"分类id"`
+	Sort            int       `description:"排序"`
+}
+
+// Update 素材字段变更
+func (material *Material) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(material, cols...)
+	return
+}
+
+// GetMaterialById 根据素材id获取素材详情
+func GetMaterialById(MaterialId int) (materialInfo *Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select * FROM material where material_id = ?`
+	err = o.Raw(sql, MaterialId).QueryRow(&materialInfo)
+	return
+}
+func DeleteByMaterialIds(ids []int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `DELETE FROM material WHERE material_id in (` + utils.GetOrmInReplace(len(ids)) + `)`
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func UpdateClassifyByMaterialIds(ids []int, classifyId int, now time.Time) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE material SET classify_id=?, modify_time=? WHERE material_id in (` + utils.GetOrmInReplace(len(ids)) + `) and classify_id != ?`
+	_, err = o.Raw(sql, classifyId, now, ids, classifyId).Exec()
+	return
+}
+
+// AddMultiMaterial 批量添加素材
+func AddMultiMaterial(materialInfoList []*Material) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.InsertMulti(utils.MultiAddNum, materialInfoList)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// MaterialListItem 素材推演列表数据
+type MaterialListItem struct {
+	MaterialId      int    `description:"素材id"`
+	MaterialName    string `description:"素材名称"`
+	MaterialNameEn  string `description:"英文素材名称"`
+	ImgUrl          string `description:"素材图片地址"`
+	ModifyTime      string `description:"修改时间"`
+	CreateTime      string `description:"创建时间"`
+	SysUserId       int    `description:"作者id"`
+	SysUserRealName string `description:"作者名称"`
+}
+
+// MaterialSaveResp 保存素材响应体
+type MaterialSaveResp struct {
+	*Material
+}
+
+type MaterialListItems struct {
+	Material
+	ModifyTime string `description:"修改时间"`
+	CreateTime string `description:"创建时间"`
+	//ParentIds  string
+}
+
+func GetMaterialListPageByCondition(condition string, pars []interface{}, startSize, pageSize int) (item []*MaterialListItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += " ORDER BY create_time DESC, material_id DESC LIMIT ?,? "
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&item)
+	return
+}
+
+func GetMaterialListByCondition(condition string, pars []interface{}) (item []*MaterialListItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += " ORDER BY create_time DESC, material_id DESC"
+	_, err = o.Raw(sql, pars).QueryRows(&item)
+	return
+}
+
+func GetMaterialListCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT COUNT(1) AS count FROM material WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+type MaterialListResp struct {
+	Paging *paging.PagingItem
+	List   []*MaterialListItems
+}
+
+func AddMaterial(item *Material) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	lastId, err = o.Insert(item)
+	return
+}
+
+// GetMaterialByClassifyIdAndName 根据分类id和素材名获取图表信息
+func GetMaterialByClassifyIdAndName(classifyId int, name string) (item *Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material WHERE classify_id = ? and material_name=? `
+	err = o.Raw(sql, classifyId, name).QueryRow(&item)
+	return
+}
+
+// GetMaterialByIds 根据素材id获取素材信息
+func GetMaterialByIds(ids []int) (items []*MaterialListItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material WHERE material_id in (` + utils.GetOrmInReplace(len(ids)) + `) `
+	_, err = o.Raw(sql, ids).QueryRows(&items)
+	return
+}
+
+// SaveAsMaterialReq 添加素材的请求数据
+type SaveAsMaterialReq struct {
+	MaterialName string `description:"素材名称"`
+	ClassifyId   int    `description:"分类id"`
+	ObjectId     int    `description:"对象id"`
+	ObjectType   string `description:"对象类型:chart,excel,sandbox,sa_doc"`
+}
+
+// MyChartSaveAsMaterialReq 添加素材的
+type MyChartSaveAsMaterialReq struct {
+	MaterialList []*MyChartSaveAsMaterialItem
+}
+
+type MyChartSaveAsMaterialItem struct {
+	MaterialName string `description:"素材名称"`
+	ChartInfoId  int    `description:"图表id"`
+	MyChartId    int    `description:"我的图表ID"`
+	ClassifyId   int    `description:"分类id"`
+}
+
+// BatchAddMaterialReq 批量添加素材的请求数据
+type BatchAddMaterialReq struct {
+	MaterialList []BatchAddMaterialItem
+	ClassifyId   int `description:"分类id"`
+}
+
+type BatchAddMaterialItem struct {
+	MaterialName string `description:"素材名称"`
+	ImgUrl       string `description:"素材图片地址"`
+}
+
+// DeleteMaterial 删除素材的请求数据
+type DeleteMaterial struct {
+	MaterialId int `description:"素材id"`
+}
+
+// BatchDeleteMaterialReq 删除素材的请求数据
+type BatchDeleteMaterialReq struct {
+	MaterialIds []int  `description:"素材id"`
+	ClassifyId  int    `description:"分类id"`
+	IsShowMe    bool   `description:"操作人id,支持多选,用英文,隔开"`
+	Keyword     string `description:"关键字"`
+	IsSelectAll bool   `description:"是否选择所有素材"`
+}
+
+type BatchChangeClassifyMaterialReq struct {
+	BatchDeleteMaterialReq
+	NewClassifyId int `description:"新分类ID"`
+}
+
+type ChangeClassifyMaterialReq struct {
+	MaterialId    int `description:"素材id"`
+	NewClassifyId int `description:"新分类ID"`
+}
+
+// RenameMaterialReq 添加/编辑素材的请求数据
+type RenameMaterialReq struct {
+	MaterialId   int    `description:"素材id"`
+	MaterialName string `description:"素材名称"`
+}
+
+func GetMaterialInfoCountByClassifyIds(classifyIds []string) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT COUNT(1) AS count FROM material WHERE classify_id in(` + utils.GetOrmInReplace(len(classifyIds)) + `)`
+	err = o.Raw(sql, classifyIds).QueryRow(&count)
+	return
+}
+
+func GetMaterialByNames(materialNames []string) (items []*Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material WHERE material_name in (` + utils.GetOrmInReplace(len(materialNames)) + `)`
+	_, err = o.Raw(sql, materialNames).QueryRows(&items)
+	return
+}
+
+func GetMaterialByNameEns(materialNames []string) (items []*Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material WHERE material_name_en in (` + utils.GetOrmInReplace(len(materialNames)) + `)`
+	_, err = o.Raw(sql, materialNames).QueryRows(&items)
+	return
+}
+
+func GetMaterialByName(materialName string) (item *Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material WHERE material_name = ?`
+	err = o.Raw(sql, materialName).QueryRow(&item)
+	return
+}
+func GetMaterialByNameEn(materialName string) (item *Material, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material WHERE material_name_en = ?`
+	err = o.Raw(sql, materialName).QueryRow(&item)
+	return
+}
+
+// GetMaterialMaxSort 获取最大的排序数
+func GetMaterialMaxSort() (sort int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT MAX(sort) AS sort FROM material `
+	err = o.Raw(sql).QueryRow(&sort)
+	return
+}
+
+// MyChartSaveAsMaterialResp 添加素材的
+type MyChartSaveAsMaterialResp struct {
+	ExistList []*MyChartSaveAsMaterialItem
+}

+ 215 - 0
models/material/material_classify.go

@@ -0,0 +1,215 @@
+package material
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type MaterialClassify struct {
+	ClassifyId      int       `orm:"column(classify_id);pk"`
+	ClassifyName    string    `description:"分类名称"`
+	ClassifyNameEn  string    `description:"英文分类名称"`
+	ParentId        int       `description:"父级id"`
+	CreateTime      time.Time `description:"创建时间"`
+	ModifyTime      time.Time `description:"修改时间"`
+	SysUserId       int       `description:"创建人id"`
+	SysUserRealName string    `description:"创建人姓名"`
+	Level           int       `description:"层级"`
+	Sort            int       `description:"排序字段,越小越靠前,默认值:10"`
+	LevelPath       string    `description:"层级路径"`
+}
+
+func AddMaterialClassify(item *MaterialClassify) (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	lastId, err = o.Insert(item)
+	return
+}
+
+// GetMaterialClassifyByParentId
+func GetMaterialClassifyByParentId(parentId int) (items []*MaterialClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material_classify WHERE parent_id=? order by sort asc,classify_id asc`
+	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	return
+}
+
+// GetMaterialClassifyAll
+func GetMaterialClassifyAll() (items []*MaterialClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material_classify WHERE parent_id<>0 order by sort asc,classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+type MaterialClassifyItems struct {
+	ClassifyId     int       `orm:"column(classify_id);pk"`
+	ClassifyName   string    `description:"分类名称"`
+	ClassifyNameEn string    `description:"英文分类名称"`
+	ParentId       int       `description:"父级id"`
+	CreateTime     time.Time `description:"创建时间"`
+	ModifyTime     time.Time `description:"修改时间"`
+	SysUserId      int       `description:"创建人id"`
+	SysUserName    string    `description:"创建人姓名"`
+	Level          int       `description:"层级"`
+	Sort           int       `description:"排序字段,越小越靠前,默认值:10"`
+	Children       []*MaterialClassifyItems
+}
+
+type MaterialClassifyListResp struct {
+	AllNodes []*MaterialClassifyItems
+}
+
+type AddMaterialClassifyReq struct {
+	ClassifyName string `description:"分类名称"`
+	ParentId     int    `description:"父级id,第一级传0"`
+	//Level               int    `description:"层级,第一级传0,其余传上一级的层级"`
+}
+
+func GetMaterialClassifyNameCount(classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT COUNT(1) AS count FROM material_classify WHERE parent_id=? AND classify_name=? `
+	err = o.Raw(sql, parentId, classifyName).QueryRow(&count)
+	return
+}
+
+func GetMaterialClassifyNameEnCount(classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT COUNT(1) AS count FROM material_classify WHERE parent_id=? AND classify_name_en=? `
+	err = o.Raw(sql, parentId, classifyName).QueryRow(&count)
+	return
+}
+
+func GetMaterialClassifyNameNotSelfCount(id int, classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT COUNT(1) AS count FROM material_classify WHERE classify_id !=? AND parent_id=? AND classify_name=? `
+	err = o.Raw(sql, id, parentId, classifyName).QueryRow(&count)
+	return
+}
+
+func GetMaterialClassifyNameEnNotSelfCount(id int, classifyName string, parentId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT COUNT(1) AS count FROM material_classify WHERE classify_id !=? AND parent_id=? AND classify_name_en=? `
+	err = o.Raw(sql, id, parentId, classifyName).QueryRow(&count)
+	return
+}
+
+// GetMaterialClassifyMaxSort 获取沙盘分类下最大的排序数
+func GetMaterialClassifyMaxSort(parentId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT MAX(sort) AS sort FROM material_classify WHERE parent_id=? `
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+type EditMaterialClassifyReq struct {
+	ClassifyName string `description:"分类名称"`
+	ClassifyId   int    `description:"分类id"`
+}
+
+func GetMaterialClassifyById(classifyId int) (item *MaterialClassify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material_classify WHERE classify_id=? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}
+
+type MaterialClassifyDeleteCheckReq struct {
+	ClassifyId int `description:"分类id"`
+}
+
+type MaterialClassifyDeleteCheckResp struct {
+	DeleteStatus int    `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:该分类下关联图表不可删除,2:确认删除当前目录及包含的子目录吗"`
+	TipsMsg      string `description:"提示信息"`
+}
+
+type DeleteMaterialClassifyReq struct {
+	ClassifyId int `description:"分类id"`
+	//	MaterialId int `description:"素材id"`
+}
+
+func DeleteMaterialClassify(classifyIds []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` DELETE FROM material_classify WHERE classify_id IN(` + utils.GetOrmInReplace(len(classifyIds)) + `) `
+	_, err = o.Raw(sql, classifyIds).Exec()
+	return
+}
+
+// MoveMaterialClassifyReq 移动沙盘分类请求参数
+type MoveMaterialClassifyReq struct {
+	ClassifyId int `description:"分类id"`
+	//MaterialId       int `description:"沙盘ID"`
+	ParentClassifyId int `description:"目标父级分类id"`
+	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
+	NextClassifyId   int `description:"下一个兄弟节点分类id"`
+	//PrevType         int `description:"上一个兄弟节点类型 1分类 2沙盘 "`
+	//NextType         int `description:"上一个兄弟节点类型 1分类 2沙盘 "`
+}
+
+// UpdateMaterialClassifySortByParentId 根据沙盘父类id更新排序
+func UpdateMaterialClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` update material_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
+}
+
+// GetFirstMaterialClassifyByParentId 获取当前父级沙盘分类下的排序第一条的数据
+func GetFirstMaterialClassifyByParentId(parentId int) (item *MaterialClassify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM material_classify WHERE parent_id=? order by sort asc,classify_id asc limit 1`
+	err = o.Raw(sql, parentId).QueryRow(&item)
+	return
+}
+
+// Update 更新沙盘分类基础信息
+func (m *MaterialClassify) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+// GetMaterialClassifyAndInfoByParentId
+func GetMaterialClassifyAndInfoByParentId(parentId int) (items []*MaterialClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT *
+FROM
+	material_classify 
+WHERE
+	parent_id = ?
+ORDER BY
+	sort ASC,
+	classify_id ASC`
+	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	return
+}
+
+type SandboxLinkCheckReq struct {
+	EdbInfoIdList   []int `description:"指标id列表"`
+	ChartInfoIdList []int `description:"图库id列表"`
+	ReportIdList    []int `description:"报告id列表"`
+}
+
+type SandboxLinkCheckItem struct {
+	Id         int    `description:"id"`
+	Name       string `description:"名称"`
+	UniqueCode string `description:"唯一编码"`
+	ClassifyId int    `description:"分类id"`
+}
+
+type SandboxLinkCheckResp struct {
+	EdbInfoIdList   []*SandboxLinkCheckItem `description:"指标id列表"`
+	ChartInfoIdList []*SandboxLinkCheckItem `description:"图库id列表"`
+	ReportIdList    []*SandboxLinkCheckItem `description:"报告id列表"`
+}
+
+func GetMaterialClassifyByLevelPath(levelPath string) (items []*MaterialClassify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM material_classify where level_path like "` + levelPath + `%"`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}

+ 26 - 0
models/move_interface.go

@@ -0,0 +1,26 @@
+package models
+
+import "time"
+
+// SingleMoveNodeReq 移动请求参数
+type SingleMoveNodeReq struct {
+	NodeId       int `description:"id"`
+	ParentNodeId int `description:"父级id"`
+	PrevNodeId   int `description:"上一个兄弟节点id"`
+	NextNodeId   int `description:"下一个兄弟节点id"`
+	NodeType     int
+	/*ChartInfoId      int `description:"图表ID, 如果图表ID有值,则移动对象为图表,否则认为移动对象分类"`
+	PrevChartInfoId  int `description:"上一个图表ID"`
+	NextChartInfoId  int `description:"下一个图表ID"`*/
+}
+
+type NodeInfo struct {
+	NodeId     int `description:"id"`
+	NodeName   string
+	ParentId   int `description:"父级id"`
+	Sort       int
+	Level      int
+	LevelPath  string
+	ModifyTime time.Time
+	//Update     func([]string) (err error)
+}

+ 1 - 1
models/ppt_english/ppt_english_grant.go

@@ -99,7 +99,7 @@ type PptEnglishInfoGrantItem struct {
 	ReportCode    string    `description:"关联的报告code"`
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
-	PptPage       int       `description:"PPT页数"`
+	PptPage       int       `description:"PPT页数"`
 	//GrantId      int64     `orm:"column(grant_id);pk;auto" description:"自增序号"`
 	//PptId        int64     `description:"ppt ID"`
 	//DepartmentId int64     `description:"授权部门id"`

+ 11 - 11
models/ppt_english/ppt_english_group_mapping.go

@@ -43,17 +43,6 @@ func GetPptMappingListByGroupId(groupId int64) (list []*PptEnglishGroupMapping,
 	return
 }
 
-// GetPptMappingListByGroupIds 根据分组ID查找
-func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptEnglishGroupMapping, err error) {
-	_, err = orm.NewOrmUsingDB("rddp").
-		QueryTable("ppt_english_group_mapping").
-		Filter("group_id__in", groupIds).
-		OrderBy("-ppt_sort", "group_ppt_id").
-		All(&list)
-
-	return
-}
-
 // GetPptMappingByPptId 查询目录下, pptId对应的目录映射关系
 func GetPptMappingByPptId(pptId int64) (item *PptEnglishGroupMapping, err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -70,6 +59,17 @@ func GetPptMappingListByGroupIdDesc(groupId int64) (list []*PptEnglishGroupMappi
 	return
 }
 
+// GetPptMappingListByGroupIds 根据分组ID查找
+func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptEnglishGroupMapping, err error) {
+	_, err = orm.NewOrmUsingDB("rddp").
+		QueryTable("ppt_english_group_mapping").
+		Filter("group_id__in", groupIds).
+		OrderBy("-ppt_sort", "group_ppt_id").
+		All(&list)
+
+	return
+}
+
 // GetPptMappingByGroupPptId 查询根据映射ID,查询单个映射关系
 func GetPptMappingByGroupPptId(groupPptId int64, adminId int) (item *PptEnglishGroupMapping, err error) {
 	o := orm.NewOrmUsingDB("rddp")

+ 2 - 2
models/ppt_v2_group_mapping.go

@@ -38,7 +38,7 @@ func GetPptMappingCountByGroupId(groupId int64) (total int64, err error) {
 // GetPptMappingListByGroupId 查询目录下,ppt列表
 func GetPptMappingListByGroupId(groupId int64) (list []*PptV2GroupMapping, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_v2_group_mapping where group_id=? order by ppt_sort asc, group_ppt_id asc `
+	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_v2_group_mapping where group_id=? order by ppt_sort desc, group_ppt_id desc `
 	_, err = o.Raw(sql, groupId).QueryRows(&list)
 	return
 }
@@ -48,7 +48,7 @@ func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptV2GroupMapping, e
 	_, err = orm.NewOrmUsingDB("rddp").
 		QueryTable("ppt_v2_group_mapping").
 		Filter("group_id__in", groupIds).
-		OrderBy("-ppt_sort", "group_ppt_id").
+		OrderBy("-ppt_sort", "-group_ppt_id").
 		All(&list)
 
 	return

+ 10 - 1
models/report.go

@@ -919,6 +919,7 @@ type ElasticReportDetail struct {
 	ClassifyName       string `description:"最小单元的分类名称"`
 	Categories         string `description:"关联的品种名称(包括品种别名)"`
 	StageStr           string `description:"报告期数"`
+	BodyMd5            string `description:"MD5加密之后的内容"`
 }
 
 // GetLastPublishedDayWeekReport 获取上一篇已发布的晨周报
@@ -1504,7 +1505,6 @@ func GetReportLayoutByReportId(reportId int) (item ReportLayout, err error) {
 
 	sql := `SELECT id, report_layout  FROM report  WHERE id = ? `
 	err = o.Raw(sql, reportId).QueryRow(&item)
-
 	return
 }
 
@@ -1565,3 +1565,12 @@ func FindReportListByCondition(condition string, pars []interface{}) (items []*R
 	}
 	return
 }
+
+type ReportShartUrlReq struct {
+	Url      string `description:"分享链接"`
+	ReportId int    `description:"报告ID"`
+}
+
+type ReportShartUrlResp struct {
+	UrlToken string `description:"分享链接token"`
+}

+ 8 - 0
models/report_chapter.go

@@ -605,3 +605,11 @@ func GetCountReportChapterByCondition(condition string, pars []interface{}) (cou
 
 	return
 }
+
+// GetNewestPreReportChapterByClassifyIdAndTypeId 获取分类下往期中最新发布的系统章节
+func GetNewestPreReportChapterByClassifyIdAndTypeId(classifyId, typeId int) (item *ReportChapter, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter WHERE classify_id_first = ? AND type_id = ? AND publish_state = 2 ORDER BY stage DESC LIMIT 1`
+	err = o.Raw(sql, classifyId, typeId).QueryRow(&item)
+	return
+}

+ 1 - 1
models/report_v2.go

@@ -369,7 +369,7 @@ func GetReportListCountByAuthorized(condition string, pars []interface{}) (count
 func GetReportListByAuthorized(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 
-	sql := `SELECT id,classify_id_first,classify_name_first,classify_id_second,classify_name_second,classify_id_third,classify_name_third,title,stage,create_time,author,report_layout,collaborate_type,is_public_publish,abstract,has_chapter,publish_time FROM report as a WHERE 1=1  `
+	sql := `SELECT id,classify_id_first,classify_name_first,classify_id_second,classify_name_second,classify_id_third,classify_name_third,title,stage,create_time,state,author,report_layout,collaborate_type,is_public_publish,abstract,has_chapter,publish_time FROM report as a WHERE 1=1  `
 	if condition != "" {
 		sql += condition
 	}

+ 205 - 0
models/residual_analysis_model/calculate_residual_analysis_config.go

@@ -0,0 +1,205 @@
+package residual_analysis_model
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CalculateResidualAnalysisConfig struct {
+	CalculateResidualAnalysisConfigId int       `orm:"column(calculate_residual_analysis_config_id);pk;auto" description:"自增id"`
+	Config                            string    `orm:"column(config)" description:"计算参数配置"`
+	SysUserId                         int       `orm:"column(sys_user_id)" description:"操作人id"`
+	CreateTime                        time.Time `orm:"column(create_time)" description:"创建时间"`
+	ModifyTime                        time.Time `orm:"column(modify_time)" description:"修改时间"`
+}
+
+func init() {
+	orm.RegisterModel(new(CalculateResidualAnalysisConfig))
+}
+
+// ResidualAnalysisReq 残差分析预览请求
+type ResidualAnalysisReq struct {
+	EdbInfoIdA       int     `description:"指标A"`
+	EdbInfoIdB       int     `description:"指标B"`
+	EdbInfoId        int     `description:"残差指标id"`
+	ConfigId         int     `description:"配置id"`
+	QueryType        int     `description:"查询类型区分 避免查询过慢 1-查询第一个表格 2-查询需要计算的表格"`
+	ResidualType     int     `description:"残差类型: 1-映射残差 2-拟合残差"`
+	DateType         int     `description:"时间类型 -1-自定义时间 0-至今 n-枚举时间(近n年)"`
+	StartDate        string  `description:"自定义开始日期"`
+	EndDate          string  `description:"自定义结束日期"`
+	IsOrder          bool    `description:"true:正序,false:逆序"`
+	IndexType        int     `description:"1-标准指标 2-领先指标"`
+	LeadValue        int     `description:"领先值"`
+	LeadFrequency    string  `description:"领先频度"`
+	LeftIndexMin     float64 `description:"指标A左侧下限"`
+	LeftIndexMax     float64 `description:"指标A左侧上限"`
+	RightIndexMin    float64 `description:"指标B右侧下限"`
+	RightIndexMax    float64 `description:"指标B右侧上限"`
+	ResidualIndexMin float64 `description:"残差指标下限"`
+	ResidualIndexMax float64 `description:"残差指标上限"`
+	ContrastIndexMin float64 `description:"对比指标下限"`
+	ContrastIndexMax float64 `description:"对比指标上限"`
+}
+
+// ResidualAnalysisResp 残差分析预览响应
+type ResidualAnalysisResp struct {
+	OriginalChartData ChartResp `description:"原始图数据"`
+	MappingChartData  ChartResp `description:"映射图数据"`
+	ResidualChartData ChartResp `description:"残差图数据"`
+	A                 float64   `description:"斜率"`
+	B                 float64   `description:"截距"`
+	R                 float64   `description:"相关系数"`
+	R2                float64   `description:"决定系数"`
+}
+
+type ChartResp struct {
+	ChartInfo   ResidualAnalysisChartInfo
+	EdbInfoList []ResidualAnalysisChartEdbInfoMapping
+}
+
+type ResidualAnalysisChartInfo struct {
+	ChartName     string  `description:"来源名称"`
+	ChartNameEn   string  `description:"英文图表名称"`
+	Unit          string  `description:"中文单位名称"`
+	UnitEn        string  `description:"英文单位名称"`
+	UniqueCode    string  `description:"图表唯一编码"`
+	DateType      int     `description:"时间类型 0-自定义时间 1-至今 n-枚举时间(近n年)"`
+	StartDate     string  `description:"自定义开始日期"`
+	EndDate       string  `description:"自定义结束日期"`
+	ChartType     int     `description:"生成样式:1:曲线图,2:季节性图"`
+	ChartWidth    float64 `description:"线条大小"`
+	Calendar      string  `description:"公历/农历"`
+	Disabled      int     `description:"是否禁用,0:启用,1:禁用,默认:0"`
+	Source        int     `description:"1:ETA图库;2:商品价格曲线;3:相关性图表"`
+	ChartSource   string  `description:"图表来源str"`
+	ChartSourceEn string  `description:"图表来源(英文)"`
+	SourcesFrom   string  `description:"图表来源"`
+	Instructions  string  `description:"图表说明"`
+}
+
+type ResidualAnalysisChartEdbInfoMapping struct {
+	EdbInfoId           int     `description:"指标id"`
+	SourceName          string  `description:"来源名称"`
+	Source              int     `description:"来源id"`
+	EdbCode             string  `description:"指标编码"`
+	EdbName             string  `description:"指标名称"`
+	EdbNameEn           string  `description:"英文指标名称"`
+	EdbType             int     `description:"指标类型:1:基础指标,2:计算指标"`
+	Frequency           string  `description:"频率"`
+	FrequencyEn         string  `description:"英文频率"`
+	Unit                string  `description:"单位"`
+	UnitEn              string  `description:"英文单位"`
+	StartDate           string  `description:"起始日期"`
+	EndDate             string  `description:"终止日期"`
+	ModifyTime          string  `description:"指标最后更新时间"`
+	MaxData             float64 `description:"上限"`
+	MinData             float64 `description:"下限"`
+	IsOrder             bool    `description:"true:逆序:,false:正序"`
+	IsAxis              int     `description:"1:左轴,0:右轴"`
+	EdbInfoType         int     `description:"1:标准指标,0:领先指标"`
+	EdbInfoCategoryType int     `description:"0:普通指标,1:预测指标"`
+	LeadValue           int     `description:"领先值"`
+	LeadUnit            string  `description:"领先单位"`
+	LeadUnitEn          string  `description:"领先英文单位"`
+	ChartStyle          string  `description:"图表类型"`
+	ChartColor          string  `description:"颜色"`
+	PredictChartColor   string  `description:"预测数据的颜色"`
+	ChartWidth          float64 `description:"线条大小"`
+	ChartType           int     `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图,8:商品价格曲线图,9:相关性图"`
+	LatestDate          string  `description:"数据最新日期"`
+	LatestValue         float64 `description:"数据最新值"`
+	MinValue            float64 `description:"最小值"`
+	MaxValue            float64 `description:"最大值"`
+	DataList            interface{}
+}
+
+type ResidualAnalysisIndexSaveReq struct {
+	EdbInfoIdA   int                       `description:"指标A"`
+	EdbInfoIdB   int                       `description:"指标B"`
+	Source       int                       `description:"99-映射残差 100-拟合残差"`
+	EdbCode      string                    `description:"指标编码"`
+	EdbName      string                    `description:"指标名称"`
+	EdbNameEn    string                    `description:"英文指标名称"`
+	EdbType      int                       `description:"指标类型:1:基础指标,2:计算指标"`
+	Frequency    string                    `description:"频率"`
+	FrequencyEn  string                    `description:"英文频率"`
+	Unit         string                    `description:"单位"`
+	UnitEn       string                    `description:"英文单位"`
+	Calendar     string                    `description:"公历/农历"`
+	ClassifyId   int                       `description:"分类id"`
+	ConfigId     int                       `description:"残差配置id"`
+	ResidualType int                       `orm:"column(residual_type)" description:"残差类型: 1-映射残差 2-拟合残差"`
+	IndexType    int                       `orm:"column(index_type)" description:"指标类型:1-映射指标 2-残差指标 3-因变量指标 4-自变量指标"`
+	DataList     []edbDataResidualAnalysis `description:"指标数据"`
+}
+
+// ResidualAnalysisConfigVo 残差分析配置vo
+type ResidualAnalysisConfigVo struct {
+	DateType         int     `description:"时间类型 -1-自定义时间 0-至今 n-枚举时间(近n年)"`
+	StartDate        string  `description:"自定义开始日期"`
+	EndDate          string  `description:"自定义结束日期"`
+	IsOrder          bool    `description:"true:正序,false:逆序"`
+	IndexType        int     `description:"1-标准指标 2-领先指标"`
+	LeadValue        int     `description:"领先值"`
+	LeadFrequency    string  `description:"领先频度"`
+	LeftIndexMin     float64 `description:"指标A左侧下限"`
+	LeftIndexMax     float64 `description:"指标A左侧上限"`
+	RightIndexMin    float64 `description:"指标B右侧下限"`
+	RightIndexMax    float64 `description:"指标B右侧上限"`
+	ResidualIndexMin float64 `description:"残差指标下限"`
+	ResidualIndexMax float64 `description:"残差指标上限"`
+	ContrastIndexMin float64 `description:"对比指标下限"`
+	ContrastIndexMax float64 `description:"对比指标上限"`
+}
+
+type DetailEdbInfoList struct {
+	EdbInfoId   int    `orm:"column(edb_info_id);pk"`
+	EdbInfoType int    `description:"指标类型,0:普通指标,1:预测指标"`
+	IndexType   int    `orm:"column(index_type)" description:"指标类型:1-映射指标 2-残差指标 3-因变量指标 4-自变量指标"`
+	SourceName  string `description:"来源名称"`
+	Source      int    `description:"来源id"`
+	EdbCode     string `description:"指标编码"`
+	EdbNameEn   string `description:"英文指标名称"`
+	EdbName     string `description:"指标名称"`
+	Frequency   string `description:"频率"`
+	FrequencyEn string `description:"英文频率"`
+	Unit        string `description:"单位"`
+	UnitEn      string `description:"英文单位"`
+	ClassifyId  int    `description:"分类id"`
+}
+
+// ResidualAnalysisDetailResp 详情响应接口
+type ResidualAnalysisDetailResp struct {
+	ConfigInfo   *CalculateResidualAnalysisConfig
+	EdbInfoList  []*DetailEdbInfoList
+	ResidualType int `description:"残差类型: 1-映射残差 2-拟合残差"`
+}
+
+// GetResidualAnalysisConfigById 根据配置id查询配置信息
+func GetResidualAnalysisConfigById(configId int) (residualAnalysisConfig CalculateResidualAnalysisConfig, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM calculate_residual_analysis_config WHERE calculate_residual_analysis_config_id=?"
+	err = o.Raw(sql, configId).QueryRow(&residualAnalysisConfig)
+	return residualAnalysisConfig, nil
+}
+
+// UpdateResidualAnalysisConfig 更新配置信息
+func UpdateResidualAnalysisConfig(config CalculateResidualAnalysisConfig) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(&config)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// SaveResidualAnalysisConfig 保存配置信息
+func SaveResidualAnalysisConfig(config CalculateResidualAnalysisConfig) (id int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err = o.Insert(&config)
+	if err != nil {
+		return 0, err
+	}
+	return id, nil
+}

+ 50 - 0
models/residual_analysis_model/calculate_residual_analysis_config_mapping.go

@@ -0,0 +1,50 @@
+package residual_analysis_model
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CalculateResidualAnalysisConfigMapping struct {
+	CalculateResidualAnalysisConfigMappingId int       `orm:"column(calculate_residual_analysis_config_mapping_id);pk;auto" description:"自增id"`
+	CalculateResidualAnalysisConfigId        int       `orm:"column(calculate_residual_analysis_config_id)" description:"残差分析配置id"`
+	EdbInfoId                                int64     `orm:"column(edb_info_id)" description:"指标id"`
+	ResidualType                             int       `orm:"column(residual_type)" description:"残差类型: 1-映射残差 2-拟合残差"`
+	IndexType                                int       `orm:"column(index_type)" description:"指标类型:1-映射指标 2-残差指标 3-因变量指标 4-自变量指标"`
+	CreateTime                               time.Time `orm:"column(create_time)" description:"创建时间"`
+	ModifyTime                               time.Time `orm:"column(modify_time)" description:"修改时间"`
+}
+
+func init() {
+	orm.RegisterModel(new(CalculateResidualAnalysisConfigMapping))
+}
+
+// GetConfigMappingListByConfigId 根据配置配置id查询配置信息
+func GetConfigMappingListByConfigId(configId int) (items []CalculateResidualAnalysisConfigMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `select * from calculate_residual_analysis_config_mapping where calculate_residual_analysis_config_id = ?`
+
+	_, err = o.Raw(sql, configId).QueryRows(&items)
+	return items, nil
+}
+
+// GetConfigMappingListByCondition 通过条件查询指标配置映射
+func GetConfigMappingListByCondition(condition string, pars []interface{}) (items []CalculateResidualAnalysisConfigMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `select * from calculate_residual_analysis_config_mapping where 1=1 `
+
+	sql += condition
+
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return items, nil
+}
+
+// SaveConfigMapping 保存指标和配置的映射关系
+func SaveConfigMapping(mapping CalculateResidualAnalysisConfigMapping) (id int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err = o.Insert(&mapping)
+	if err != nil {
+		return 0, err
+	}
+	return id, nil
+}

+ 40 - 0
models/residual_analysis_model/edb_data_residual_analysis.go

@@ -0,0 +1,40 @@
+package residual_analysis_model
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type edbDataResidualAnalysis struct {
+	EdbDataId     int       `orm:"column(edb_data_id);pk;auto" description:"自增id"`
+	EdbInfoId     int       `orm:"column(edb_info_id)" description:"指标id"`
+	EdbCode       string    `orm:"column(edb_code)" description:"指标编码"`
+	DataTime      string    `orm:"column(data_time)" description:"数据日期"`
+	Value         float64   `orm:"column(value)" description:"数据值"`
+	CreateTime    time.Time `orm:"column(create_time)" description:"创建时间"`
+	ModifyTime    time.Time `orm:"column(modify_time)" description:"修改时间"`
+	DataTimeStamp int64     `orm:"column(data_timestamp)"`
+}
+
+func init() {
+	orm.RegisterModel(new(edbDataResidualAnalysis))
+}
+
+// DeleteResidualAnalysisDataByEdbCode 根据指标编码删除数据
+func DeleteResidualAnalysisDataByEdbCode(edbCode string) error {
+	o := orm.NewOrmUsingDB("data")
+	sql := `delete from edb_data_residual_analysis where edb_code = ?`
+	_, err := o.Raw(sql, edbCode).Exec()
+	return err
+}
+
+// AddResidualAnalysisData 新增指标数据
+func AddResidualAnalysisData(dataList []edbDataResidualAnalysis) (num int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	num, err = o.InsertMulti(len(dataList), dataList)
+	if err != nil {
+		return 0, err
+	}
+
+	return num, nil
+}

+ 4 - 0
models/resource.go

@@ -57,3 +57,7 @@ type ImageSvgToPngResp struct {
 	Ret         int64  `json:"Ret"`
 	Success     bool   `json:"Success"`
 }
+
+type UploadImgResp struct {
+	ResourceUrl string `description:"资源地址"`
+}

+ 26 - 26
models/sandbox/sandbox.go

@@ -411,6 +411,32 @@ func GetFirstSandboxByClassifyId(classifyId int) (item *Sandbox, err error) {
 	return
 }
 
+// UpdateSandboxContent 更新沙盘内容
+func UpdateSandboxContent(list []Sandbox) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//循环更新沙盘内容
+	for _, sandbox := range list {
+		_, err = to.Update(&sandbox, "Content", "ModifyTime")
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
 // ContentDataStruct 沙盘内容结构体
 type ContentDataStruct struct {
 	Cells []struct {
@@ -438,29 +464,3 @@ type DetailParams struct {
 	Id         int    `json:"id"`
 	ClassifyId int    `json:"classifyId"`
 }
-
-// UpdateSandboxContent 更新沙盘内容
-func UpdateSandboxContent(list []Sandbox) (err error) {
-	o := orm.NewOrmUsingDB("data")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	//循环更新沙盘内容
-	for _, sandbox := range list {
-		_, err = to.Update(&sandbox, "Content", "ModifyTime")
-		if err != nil {
-			return
-		}
-	}
-
-	return
-}

+ 15 - 2
models/smart_report/smart_report.go

@@ -419,11 +419,24 @@ func UpdateSmartReportsStateBySecondIds(oldState, newState int, secondIds []int)
 	return
 }
 
-
 // UpdatePdfUrlSmartReportById 清空pdf相关字段
 func UpdatePdfUrlSmartReportById(reportId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := `UPDATE smart_report SET detail_img_url = '',detail_pdf_url='',modify_time=NOW() WHERE smart_report_id = ? `
 	_, err = o.Raw(sql, reportId).Exec()
 	return
-}
+}
+
+func GetSmartReportFieldsByIds(ids []int, fields []string) (items []*SmartReport, err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	field := " * "
+	if len(fields) > 0 {
+		field = fmt.Sprintf(" %s ", strings.Join(fields, ","))
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM smart_report WHERE smart_report_id IN (%s)`, field, utils.GetOrmInReplace(len(ids)))
+	_, err = o.Raw(sql, ids).QueryRows(&items)
+	return
+}

+ 1 - 1
models/system/sys_user.go

@@ -55,7 +55,7 @@ type Admin struct {
 	OpenId                    string    `description:"弘则部门公众号的openid"`
 	UnionId                   string    `description:"微信公众平台唯一标识"`
 	EdbPermission             int8      `description:"指标库操作权限,0:只能操作 自己的,1:所有指标可操作"`
-	MysteelChemicalPermission int8      `description:"钢联化工指标操作权限,0:只能操作 自己的,1:所有指标可操作"`
+	MysteelChemicalPermission int8      `description:"上海钢联指标操作权限,0:只能操作 自己的,1:所有指标可操作"`
 	PredictEdbPermission      int8      `description:"预测指标库操作权限,0:只能操作 自己的,1:所有预测指标可操作"`
 	Province                  string    `description:"省"`
 	ProvinceCode              string    `description:"省编码"`

+ 464 - 14
routers/commentsRouter.go

@@ -3949,6 +3949,186 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "Classify",
+            Router: `/clarksons/classify`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "AddClassify",
+            Router: `/clarksons/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "DelClassify",
+            Router: `/clarksons/classify/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "EditClassify",
+            Router: `/clarksons/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "MoveClassify",
+            Router: `/clarksons/classify/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "DeleteClarksonsData",
+            Router: `/clarksons/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "AddCheck",
+            Router: `/clarksons/edb_info/add_check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "BatchAdd",
+            Router: `/clarksons/edb_info/batch_add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "BatchDelete",
+            Router: `/clarksons/edb_info/batch_delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "BatchEdit",
+            Router: `/clarksons/edb_info/batch_edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "NameCheck",
+            Router: `/clarksons/edb_info/name_check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "EditClarksons",
+            Router: `/clarksons/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "GetClarksonsIndexInfo",
+            Router: `/clarksons/get/index/info`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "ClarksonsData",
+            Router: `/clarksons/index/data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "IndexList",
+            Router: `/clarksons/index/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "IndexPageList",
+            Router: `/clarksons/index/page/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "MoveClarksonsData",
+            Router: `/clarksons/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "SearchList",
+            Router: `/clarksons/search_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "SingleData",
+            Router: `/clarksons/single_data`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ClarksonsDataController"],
+        beego.ControllerComments{
+            Method: "ExportClarksonsList",
+            Router: `/export/clarksonsList`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbBusinessController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbBusinessController"],
         beego.ControllerComments{
             Method: "AddCheck",
@@ -4480,6 +4660,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "ClassifyEdbInfoList",
+            Router: `/classify/edb/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
         beego.ControllerComments{
             Method: "ComTradeCountryList",
@@ -5272,6 +5461,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
+        beego.ControllerComments{
+            Method: "ModifyEdbList",
+            Router: `/modify/edbList`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:EdbInfoController"],
         beego.ControllerComments{
             Method: "BatchAdd",
@@ -6010,6 +6208,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ManualEdbController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ManualEdbController"],
+        beego.ControllerComments{
+            Method: "BatchSaveExcelData",
+            Router: `/target/edb/excel_style/batch_save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ManualEdbController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ManualEdbController"],
         beego.ControllerComments{
             Method: "EditExcelData",
@@ -6759,8 +6966,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
         beego.ControllerComments{
-            Method: "IcpiClassifyList",
-            Router: `/icpi/classify/list`,
+            Method: "ExportIcpiDataList",
+            Router: `/icpi/export/icpiDataList`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6768,8 +6975,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
         beego.ControllerComments{
-            Method: "ExportIcpiDataList",
-            Router: `/icpi/export/icpiDataList`,
+            Method: "Sci99ClassifyList",
+            Router: `/sci99/classify/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6777,8 +6984,8 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
         beego.ControllerComments{
-            Method: "IcpiData",
-            Router: `/icpi/index/data`,
+            Method: "ExportSci99DataList",
+            Router: `/sci99/export/sci99DataList`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -6786,26 +6993,26 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
         beego.ControllerComments{
-            Method: "Sci99ClassifyList",
-            Router: `/sci99/classify/list`,
+            Method: "Sci99Data",
+            Router: `/sci99/index/data`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"],
         beego.ControllerComments{
-            Method: "ExportSci99DataList",
-            Router: `/sci99/export/sci99DataList`,
+            Method: "IcpiClassifyList",
+            Router: `/icpi/classify/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"],
         beego.ControllerComments{
-            Method: "Sci99Data",
-            Router: `/sci99/index/data`,
+            Method: "IcpiData",
+            Router: `/icpi/index/data`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
@@ -7936,6 +8143,177 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "BatchAdd",
+            Router: `/batch/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "BatchChangeClassify",
+            Router: `/batch/changeClassify`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "BatchDelete",
+            Router: `/batch/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "BatchDownload",
+            Router: `/batch/download`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "ChangeClassify",
+            Router: `/changeClassify`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "AddMaterialClassify",
+            Router: `/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "DeleteMaterialClassify",
+            Router: `/classify/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "DeleteMaterialClassifyCheck",
+            Router: `/classify/del/check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "EditMaterialClassify",
+            Router: `/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "MaterialClassifyList",
+            Router: `/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "ClassifyMove",
+            Router: `/classify/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "Delete",
+            Router: `/del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "GetMaterialDetail",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "Download",
+            Router: `/download`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "MyChartSaveAsMaterial",
+            Router: `/my_chart/saveAs`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "Rename",
+            Router: `/rename`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "SaveAsMaterial",
+            Router: `/saveAs`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/material:MaterialController"],
+        beego.ControllerComments{
+            Method: "Upload",
+            Router: `/upload`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"],
         beego.ControllerComments{
             Method: "Approve",
@@ -8062,6 +8440,60 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "CheckResidualAnalysisExist",
+            Router: `/check/residual/analysis/exist`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "ContrastPreview",
+            Router: `/contrast/preview`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "ResidualAnalysisDetail",
+            Router: `/residual/analysis/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "ResidualAnalysisPreview",
+            Router: `/residual/analysis/preview`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "SaveResidualAnalysis",
+            Router: `/save/residual/analysis`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/residual_analysis:ResidualAnalysisController"],
+        beego.ControllerComments{
+            Method: "SaveResidualAnalysisConfig",
+            Router: `/save/residual/analysis/config`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/roadshow:CalendarController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/roadshow:CalendarController"],
         beego.ControllerComments{
             Method: "ResearcherList",
@@ -10492,6 +10924,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportCommonController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportCommonController"],
+        beego.ControllerComments{
+            Method: "ShareTransform",
+            Router: `/share/link`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "CheckDayWeekReportChapterVideo",
@@ -10915,6 +11356,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "ShareGenerate",
+            Router: `/share/generate`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "ThsSendTemplateMsg",

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است