Browse Source

Merge branch 'master' of http://8.136.199.33:3000/eta_server/eta_api into bzq1/stl

zqbao 3 months ago
parent
commit
6e6ce15167
100 changed files with 7524 additions and 522 deletions
  1. 12 6
      controllers/ai/ai_summary.go
  2. 1 0
      controllers/base_auth.go
  3. 1315 0
      controllers/bi_dashboard.go
  4. 55 5
      controllers/classify.go
  5. 902 19
      controllers/data_manage/ccf_data.go
  6. 31 1
      controllers/data_manage/chart_classify.go
  7. 27 26
      controllers/data_manage/chart_info.go
  8. 4 4
      controllers/data_manage/chart_theme.go
  9. 9 0
      controllers/data_manage/correlation/correlation_chart_classify.go
  10. 8 0
      controllers/data_manage/edb_classify.go
  11. 62 59
      controllers/data_manage/edb_info.go
  12. 3 0
      controllers/data_manage/excel/excel_classify.go
  13. 2 0
      controllers/data_manage/excel/excel_info.go
  14. 6 3
      controllers/data_manage/future_good/future_good_chart_classify.go
  15. 90 59
      controllers/data_manage/future_good/future_good_chart_info.go
  16. 8 5
      controllers/data_manage/line_equation/line_chart_classify.go
  17. 23 22
      controllers/data_manage/line_feature/chart_info.go
  18. 8 5
      controllers/data_manage/line_feature/classify.go
  19. 8 2
      controllers/data_manage/manual_edb.go
  20. 8 4
      controllers/data_manage/multiple_graph_config.go
  21. 57 72
      controllers/data_manage/mysteel_chemical_data.go
  22. 9 0
      controllers/data_manage/predict_edb_classify.go
  23. 6 6
      controllers/data_manage/predict_edb_info.go
  24. 9 0
      controllers/data_manage/range_analysis/chart_classify.go
  25. 6 5
      controllers/data_manage/supply_analysis/variety_edb.go
  26. 42 0
      controllers/data_stat/edb_terminal.go
  27. 6 1
      controllers/document_manage/document_manage_controller.go
  28. 398 0
      controllers/edb_monitor/edb_monitor.go
  29. 240 0
      controllers/edb_monitor/edb_monitor_classify.go
  30. 251 0
      controllers/edb_monitor/edb_monitor_message.go
  31. 22 13
      controllers/english_report/english_classify.go
  32. 36 5
      controllers/english_report/report.go
  33. 19 2
      controllers/message.go
  34. 118 33
      controllers/report_approve/report_approve.go
  35. 38 10
      controllers/report_approve/report_approve_flow.go
  36. 98 2
      controllers/report_chapter.go
  37. 1 1
      controllers/report_v2.go
  38. 10 1
      controllers/sandbox/sandbox.go
  39. 18 1
      controllers/sys_admin.go
  40. 26 18
      controllers/target.go
  41. 20 3
      go.mod
  42. 56 6
      go.sum
  43. 9 2
      models/ai_summary/ai_summary_classify.go
  44. 170 0
      models/bi_dashboard/bi_dashboard.go
  45. 136 0
      models/bi_dashboard/bi_dashboard_classify.go
  46. 77 0
      models/bi_dashboard/bi_dashboard_detail.go
  47. 75 0
      models/bi_dashboard/bi_dashboard_grant.go
  48. 46 0
      models/bi_dashboard/bi_dashboard_home_page.go
  49. 37 0
      models/binlog/binlog.go
  50. 64 0
      models/binlog/business_sys_interaction_log.go
  51. 13 0
      models/business_conf.go
  52. 60 1
      models/classify.go
  53. 97 0
      models/data_manage/base_from_ccf.go
  54. 2 0
      models/data_manage/base_from_sci.go
  55. 8 6
      models/data_manage/base_from_smm.go
  56. 42 6
      models/data_manage/chart_classify.go
  57. 19 7
      models/data_manage/chart_info.go
  58. 9 0
      models/data_manage/edb_info.go
  59. 8 0
      models/data_manage/edb_terminal.go
  60. 4 2
      models/data_manage/excel/request/mixed_table.go
  61. 2 0
      models/data_manage/excel/response/excel_info.go
  62. 12 0
      models/data_manage/mysteel_chemical_index.go
  63. 90 12
      models/data_manage/trade_analysis/trade_analysis.go
  64. 46 0
      models/db.go
  65. 5 2
      models/document_manage_model/outside_report.go
  66. 129 0
      models/edb_monitor/edb_monitor.go
  67. 191 0
      models/edb_monitor/edb_monitor_classify.go
  68. 79 0
      models/edb_monitor/edb_monitor_message.go
  69. 25 0
      models/edb_monitor/request/edb_monitor.go
  70. 19 0
      models/edb_monitor/request/edb_monitor_classify.go
  71. 5 0
      models/edb_monitor/request/edb_monitor_message.go
  72. 46 0
      models/edb_monitor/response/edb_monitor.go
  73. 8 0
      models/edb_monitor/response/edb_monitor_classify.go
  74. 19 0
      models/edb_monitor/response/edb_monitor_message.go
  75. 51 5
      models/english_report.go
  76. 8 0
      models/english_video.go
  77. 11 1
      models/permission.go
  78. 32 4
      models/report.go
  79. 7 3
      models/report_approve/report_approve.go
  80. 9 1
      models/sandbox/sandbox_classify.go
  81. 13 2
      models/system/sys_admin.go
  82. 22 0
      models/system/sys_menu.go
  83. 12 1
      models/system/sys_role.go
  84. 31 21
      models/target.go
  85. 68 0
      models/user_collect_classify.go
  86. 423 0
      routers/commentsRouter.go
  87. 13 0
      routers/router.go
  88. 53 0
      services/ai_summary/ai_summary.go
  89. 68 0
      services/bi_dashboard.go
  90. 271 0
      services/binlog/binlog.go
  91. 203 0
      services/binlog/handler.go
  92. 149 35
      services/classify.go
  93. 49 0
      services/data/base_from_ccf.go
  94. 56 3
      services/data/chart_classify.go
  95. 4 0
      services/data/chart_info.go
  96. 5 5
      services/data/chart_info_excel_balance.go
  97. 110 0
      services/data/correlation/correlation_chart_classify.go
  98. 54 0
      services/data/edb_classify.go
  99. 136 4
      services/data/edb_info.go
  100. 46 0
      services/data/edb_info_relation.go

+ 12 - 6
controllers/ai/ai_summary.go

@@ -11,9 +11,10 @@ import (
 	"eta/eta_api/services/aiser"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // AiSummaryClassifyItems
@@ -40,6 +41,13 @@ func (this *AiController) AiSummaryClassifyItems() {
 			br.ErrMsg = err.Error()
 			return
 		}
+		nodeAll, err := aiSummaryService.GetAiSummaryClassifyByIsShowMe(resp.AllNodes, aiSummaryClassifyId, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		resp.AllNodes = nodeAll
 
 		br.Ret = 200
 		br.Success = true
@@ -936,7 +944,7 @@ func (this *AiController) AiSummaryDetail() {
 		AiSummaryItems: detail,
 	}
 
-	if detail.SaDocId >0 {
+	if detail.SaDocId > 0 {
 		item := new(saModel.SaDoc)
 		e := item.GetItemById(detail.SaDocId)
 		if e != nil {
@@ -952,7 +960,6 @@ func (this *AiController) AiSummaryDetail() {
 		resp.SaDocClassifyId = item.ClassifyId
 	}
 
-
 	br.Data = resp
 	br.Ret = 200
 	br.Success = true
@@ -1017,7 +1024,7 @@ func (this *AiController) AddAiSummary() {
 		br.ErrMsg = "保存分类失败,Err:" + err.Error()
 		return
 	}
-	classify ,err := ai_summary.GetAiSummaryClassifyById(req.ClassifyId)
+	classify, err := ai_summary.GetAiSummaryClassifyById(req.ClassifyId)
 	if err != nil {
 		br.Msg = "获取分类信息失败"
 		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
@@ -1562,7 +1569,6 @@ func (this *AiController) GenerateAiSummary() {
 //	return
 //}
 
-
 // AiSummaryClassifyList
 // @Title 获取所有纪要分类接口-不包含沙盘
 // @Description 获取所有纪要分类接口-不包含沙盘
@@ -1604,4 +1610,4 @@ func (this *AiController) AiSummaryClassifyList() {
 	br.Success = true
 	br.Msg = "获取成功"
 	br.Data = resp
-}
+}

+ 1 - 0
controllers/base_auth.go

@@ -213,6 +213,7 @@ func (c *BaseAuthController) Prepare() {
 					api += v.Api + "&"
 				}
 			}
+			api += "&" + models.BusinessConfMap["PublicApi"]
 			//处理uri请求,去除前缀和参数
 			api = strings.TrimRight(api, "&")
 			uri = strings.Replace(uri, "/adminapi", "", 1)

+ 1315 - 0
controllers/bi_dashboard.go

@@ -0,0 +1,1315 @@
+package controllers
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_api/models"
+	"eta/eta_api/models/bi_dashboard"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type BIDaShboardController struct {
+	BaseAuthController
+}
+
+// GroupList
+// @Title 获取我的列表
+// @Description 获取我的列表接口
+// @Success 200 {object} models.RespGroupList
+// @router /my_list [get]
+func (this *BIDaShboardController) MyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	// 获取我的看板列表
+	privateCond := ` AND sys_admin_id = ? `
+	privatePars := []interface{}{this.SysUser.AdminId}
+	privateList, err := bi_dashboard.GetBiDashboardList(privateCond, privatePars)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = privateList
+	return
+}
+
+// AddDashboard
+// @Title 新增看板
+// @Description 新增看板接口
+// @Param	request	body models.AddDashboardReq true "type json string"
+// @Success 200 Ret=200 新增成功
+// @router /add [post]
+func (this *BIDaShboardController) AddDashboard() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.AddDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardName == "" {
+		br.Msg = "名称不能为空"
+		return
+	}
+	nameItem, err := bi_dashboard.GetDashboardByName(req.BiDashboardName, this.SysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+	if nameItem != nil && nameItem.BiDashboardId > 0 {
+		br.Msg = "名称重复"
+		return
+	}
+
+	item := &bi_dashboard.BiDashboard{
+		//BiDashboardClassifyId: req.ClassifyId,
+		BiDashboardName: req.BiDashboardName,
+		SysAdminId:      this.SysUser.AdminId,
+		SysAdminName:    this.SysUser.RealName,
+		//Sort:                  0,
+		CreateTime: time.Now(),
+		ModifyTime: time.Now(),
+		State:      1,
+	}
+	id, e := bi_dashboard.AddBiDashboard(item)
+	if e != nil {
+		err = e
+		br.Msg = "新增失败"
+		br.ErrMsg = "新增失败,Err:" + e.Error()
+		return
+	}
+	detailList := make([]*bi_dashboard.BiDashboardDetail, 0)
+	for i, v := range req.List {
+		item := &bi_dashboard.BiDashboardDetail{
+			BiDashboardId: int(id),
+			Type:          v.Type,
+			UniqueCode:    v.UniqueCode,
+			Sort:          i + 1,
+			CreateTime:    time.Now(),
+			ModifyTime:    time.Now(),
+		}
+		detailList = append(detailList, item)
+	}
+	err = bi_dashboard.AddBiDashboardDetailMulti(detailList)
+	if err != nil {
+		br.Msg = "新增详情失败"
+		br.ErrMsg = "新增详情失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "新增成功"
+	//br.Data =
+}
+
+// EditPpt
+// @Title 编辑看板
+// @Description 编辑看板接口
+// @Param	request	body bi_dashboard.EditDashboardReq true "type json string"
+// @Success 200 Ret=200 编辑成功
+// @router /edit [post]
+func (this *BIDaShboardController) EditDashboard() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.EditDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardName == "" {
+		br.Msg = "标题不能为空"
+		return
+	}
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+	
+	// 修改
+	item.BiDashboardName = req.BiDashboardName
+	item.ModifyTime = time.Now()
+
+	err = bi_dashboard.EditDashboard(item)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+
+	err = bi_dashboard.DeleteBiDashboardDetail(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "删除详情失败"
+		br.ErrMsg = "删除详情失败,Err:" + err.Error()
+		return
+	}
+
+	detailList := make([]*bi_dashboard.BiDashboardDetail, 0)
+	for _, v := range req.List {
+		item := &bi_dashboard.BiDashboardDetail{
+			BiDashboardId: req.BiDashboardId,
+			Type:          v.Type,
+			UniqueCode:    v.UniqueCode,
+			Sort:          v.Sort,
+			CreateTime:    time.Now(),
+			ModifyTime:    time.Now(),
+		}
+		detailList = append(detailList, item)
+	}
+	err = bi_dashboard.AddBiDashboardDetailMulti(detailList)
+	if err != nil {
+		br.Msg = "新增详情失败"
+		br.ErrMsg = "新增详情失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+	br.IsAddLog = true
+}
+
+// DeleteDashboard
+// @Title 删除看板
+// @Description 删除看板接口
+// @Param	request	body bi_dashboard.DelDashboardReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /delete [post]
+func (this *BIDaShboardController) DeleteDashboard() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.DelDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+	if item.SysAdminId != this.SysUser.AdminId {
+		br.Msg = "无权删除"
+		return
+	}
+	err = bi_dashboard.DelDashboard(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	//如果该看板存在共享记录,则删除共享
+	err = bi_dashboard.DeleteDashboardGrant(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "删除成功"
+}
+
+// DeleteDashboard
+// @Title 删除看板详情
+// @Description 删除看板详情接口
+// @Param	request	body bi_dashboard.DelDashboardDetailReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /detail/delete [post]
+func (this *BIDaShboardController) DeleteDashboardDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.DelDashboardDetailReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardDetailId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	err = bi_dashboard.DeleteBiDashboardDetailByDetailId(req.BiDashboardDetailId)
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "删除成功"
+}
+
+// DetailDashboard
+// @Title 获取看板详情
+// @Description 获取看板详情接口
+// @Param   PptId   query   int  true       "PptId"
+// @Success 200 {object} models.PptV2
+// @router /detail [get]
+func (this *BIDaShboardController) DetailDashboard() {
+	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
+	}
+	dashboardId, _ := this.GetInt("DashboardId")
+	resp := new(bi_dashboard.DashboardDetailResp)
+	dashboardItem, err := bi_dashboard.GetDashboardById(dashboardId)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		br.Msg = "我的看板列表查询出错"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	grantInfoList, err := bi_dashboard.GetDashboardGrantInfo(dashboardId)
+	if err != nil {
+		br.Msg = "信息获取失败"
+		br.ErrMsg = "共享信息获取失败,Err:" + err.Error()
+		return
+	}
+	if len(grantInfoList) > 0 {
+		resp.IsGrant = 1
+	}
+
+	detailList, err := bi_dashboard.GetBiDashboardDetailById(dashboardId)
+	if err != nil {
+		br.Msg = "详情获取失败"
+		br.ErrMsg = "详情获取失败,Err:" + err.Error()
+		return
+	}
+
+	editor, e := services.UpdateBiDashboardEditing(dashboardId, 0, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "编辑状态更新失败"
+		br.ErrMsg = "编辑状态更新失败,Err:" + e.Error()
+		return
+	}
+
+	resp.Editor = editor
+	resp.BiDashboard = dashboardItem
+	resp.List = detailList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// MoveDashboard
+// @Title 移动看板详情
+// @Description 移动看板详情接口
+// @Param	request	body bi_dashboard.MoveDashboardDetailReq true "type json string"
+// @Success 200 Ret=200 移动成功
+// @router /detail/move [post]
+func (this *BIDaShboardController) MoveDashboard() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.MoveDashboardDetailReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	if req.BiDashboardDetailId == req.OtherDetailId || req.BiDashboardDetailId <= 0 || req.OtherDetailId <= 0 {
+		br.Msg = "看板Id有误"
+		return
+	}
+	if req.Sort < 0 || req.OtherSort < 0 || req.Sort == req.OtherSort {
+		br.Msg = "排序有误"
+		return
+	}
+
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+
+	// 判断权限
+	if item.SysAdminId != this.SysUser.AdminId {
+		br.Msg = `无权移动`
+		return
+	}
+
+	// 修改
+	detailItem := &bi_dashboard.BiDashboardDetail{
+		BiDashboardDetailId: req.BiDashboardDetailId,
+		Sort:                req.OtherSort,
+		ModifyTime:          time.Now(),
+	}
+	err = bi_dashboard.EditBiDashboardDetail(detailItem)
+	if err != nil {
+		br.Msg = "编辑详情失败"
+		br.ErrMsg = "编辑详情失败,Err:" + err.Error()
+		return
+	}
+
+	otherItem := &bi_dashboard.BiDashboardDetail{
+		BiDashboardDetailId: req.OtherDetailId,
+		Sort:                req.Sort,
+		ModifyTime:          time.Now(),
+	}
+	err = bi_dashboard.EditBiDashboardDetail(otherItem)
+	if err != nil {
+		br.Msg = "编辑详情失败"
+		br.ErrMsg = "编辑详情失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+	br.IsAddLog = true
+}
+
+// ShareList
+// @Title 获取共享列表
+// @Description 获取共享列表接口
+// @Success 200 {object} models.RespGroupList
+// @router /share_list [get]
+func (this *BIDaShboardController) ShareList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	//myPptList := make([]*bi_dashboard.BiDashboard, 0)
+	//otherPptList := make([]*bi_dashboard.BiDashboard, 0)
+	grantList := bi_dashboard.RespGroupList{}
+
+	// 获取我的看板列表
+	ShareList, err := bi_dashboard.GetAllMyShareList(this.SysUser.AdminId)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		br.ErrMsg = err.Error()
+		br.Msg = "查询失败"
+		return
+	}
+	grantList.MyList = ShareList
+
+	//dashboardMap := make(map[int]*bi_dashboard.BiDashboard)
+	adminIdList := make([]int, 0)   //需要查询的创建人admin_id列表集合
+	adminIdMap := make(map[int]int) //需要查询的创建人admin_id集合,用来去重的,避免重复id
+	grantDashboardList, err := bi_dashboard.GetAllGrantList(this.SysUser.AdminId)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		br.ErrMsg = err.Error()
+		br.Msg = "查询失败"
+		return
+	}
+
+	publicAdminIdList := make([]int, 0)
+	publicDashboardListMap := make(map[int][]*bi_dashboard.BiDashboard)
+	for _, v := range grantDashboardList {
+		publicDashboardList, ok := publicDashboardListMap[v.SysAdminId]
+		if !ok {
+			publicDashboardList = make([]*bi_dashboard.BiDashboard, 0)
+			publicAdminIdList = append(publicAdminIdList, v.SysAdminId)
+			if _, ok := adminIdMap[v.SysAdminId]; !ok {
+				adminIdList = append(adminIdList, v.SysAdminId) //需要查询的创建人admin_id列表集合
+				adminIdMap[v.SysAdminId] = v.SysAdminId         //需要查询的创建人admin_id集合,用来去重的,避免重复id
+			}
+		}
+
+		tmp := &bi_dashboard.BiDashboard{
+			BiDashboardId:   v.BiDashboardId,
+			BiDashboardName: v.BiDashboardName,
+			CreateTime:      v.CreateTime,
+			ModifyTime:      v.ModifyTime,
+			Sort:            v.Sort,
+			State:           v.State,
+			SysAdminId:      v.SysAdminId,
+			SysAdminName:    v.SysAdminName,
+		}
+		publicDashboardList = append(publicDashboardList, tmp)
+		publicDashboardListMap[v.SysAdminId] = publicDashboardList
+	}
+	// 创建人信息
+	systemAdminMap := make(map[int]*system.Admin)
+	systemAdminList, err := system.GetAdminListByIdList(adminIdList)
+	if err != nil {
+		return
+	}
+	for _, v := range systemAdminList {
+		systemAdminMap[v.AdminId] = v
+	}
+
+	for _, v := range publicAdminIdList {
+		systemAdmin, ok := systemAdminMap[v]
+		if !ok {
+			continue
+		}
+
+		// 看板 列表信息
+		respGroupNameListItemList, ok := publicDashboardListMap[v]
+		if !ok {
+			respGroupNameListItemList = make([]*bi_dashboard.BiDashboard, 0)
+		}
+
+		// ppt 分组信息
+		tmpRespGroupListItem := &bi_dashboard.RespOtherGroupListItem{
+			GroupId:       int64(systemAdmin.AdminId),
+			GroupName:     systemAdmin.RealName,
+			AdminId:       systemAdmin.AdminId,
+			DashboardList: respGroupNameListItemList,
+		}
+		grantList.OtherList = append(grantList.OtherList, tmpRespGroupListItem)
+	}
+	//if len(dashboradIds) > 0 {
+	//	// 通过dashboradIds列表字段获取所有的看板信息
+	//	dashboradList, tmpErr := bi_dashboard.GetDashboradByIds(dashboradIds)
+	//	if tmpErr != nil {
+	//		err = errors.New("查询dashborad详情出错:" + err.Error())
+	//		br.Msg = "查询dashborad详情出错"
+	//		br.ErrMsg = err.Error()
+	//		return
+	//	}
+	//	for _, v := range dashboradList {
+	//		dashboardMap[v.BiDashboardId] = v
+	//	}
+	//}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = grantList
+	return
+}
+
+// PublicList
+// @Title 获取公共列表
+// @Description 获取公共列表接口
+// @Success 200 {object} models.RespGroupList
+// @router /public_list [get]
+func (this *BIDaShboardController) PublicList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	resp := make([]*bi_dashboard.RespPublicGroupListItem, 0)
+	// 获取公共看板列表
+	publicCond := ` AND state = 6 `
+	publicPars := make([]interface{}, 0)
+	publicList, err := bi_dashboard.GetBiDashboardList(publicCond, publicPars)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		return
+	}
+
+	//dashboardMap := make(map[int]*bi_dashboard.BiDashboard)
+	adminIdList := make([]int, 0)   //需要查询的创建人admin_id列表集合
+	adminIdMap := make(map[int]int) //需要查询的创建人admin_id集合,用来去重的,避免重复id
+
+	publicAdminIdList := make([]int, 0)
+	publicDashboardListMap := make(map[int][]*bi_dashboard.BiDashboard)
+	publicDashboardClassifyIdMap := make(map[int]int)
+	for _, v := range publicList {
+		publicDashboardList, ok := publicDashboardListMap[v.SysAdminId]
+		if !ok {
+			publicDashboardList = make([]*bi_dashboard.BiDashboard, 0)
+			publicAdminIdList = append(publicAdminIdList, v.SysAdminId)
+			if _, ok := adminIdMap[v.SysAdminId]; !ok {
+				adminIdList = append(adminIdList, v.SysAdminId) //需要查询的创建人admin_id列表集合
+				adminIdMap[v.SysAdminId] = v.SysAdminId         //需要查询的创建人admin_id集合,用来去重的,避免重复id
+			}
+		}
+
+		tmp := &bi_dashboard.BiDashboard{
+			BiDashboardId:         v.BiDashboardId,
+			BiDashboardClassifyId: v.BiDashboardClassifyId,
+			BiDashboardName:       v.BiDashboardName,
+			CreateTime:            v.CreateTime,
+			ModifyTime:            v.ModifyTime,
+			Sort:                  v.Sort,
+			State:                 v.State,
+			SysAdminId:            v.SysAdminId,
+			SysAdminName:          v.SysAdminName,
+		}
+		publicDashboardList = append(publicDashboardList, tmp)
+		publicDashboardListMap[v.SysAdminId] = publicDashboardList
+		publicDashboardClassifyIdMap[v.BiDashboardClassifyId] = v.BiDashboardClassifyId
+	}
+	// 创建人信息
+	systemAdminMap := make(map[int]*system.Admin)
+	systemAdminList, err := system.GetAdminListByIdList(adminIdList)
+	if err != nil {
+		return
+	}
+	for _, v := range systemAdminList {
+		systemAdminMap[v.AdminId] = v
+	}
+
+	for _, v := range adminIdList {
+		systemAdmin, ok := systemAdminMap[v]
+		if !ok {
+			continue
+		}
+
+		// 看板 列表信息
+		respGroupNameListItemList, ok := publicDashboardListMap[v]
+		if !ok {
+			respGroupNameListItemList = make([]*bi_dashboard.BiDashboard, 0)
+		}
+
+		// ppt 分组信息
+		tmpRespGroupListItem := &bi_dashboard.RespPublicGroupListItem{
+			GroupId:       int64(systemAdmin.AdminId),
+			GroupName:     systemAdmin.RealName,
+			AdminId:       systemAdmin.AdminId,
+			DashboardList: make([]*bi_dashboard.BiDashboard, 0),
+		}
+
+		for _, vv := range respGroupNameListItemList {
+			tmpRespGroupListItem.DashboardList = append(tmpRespGroupListItem.DashboardList, vv)
+		}
+		resp = append(resp, tmpRespGroupListItem)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = resp
+	return
+}
+
+// AddDashboardClassify
+// @Title 新增看板分类
+// @Description 新增看板分类接口
+// @Param	request	body bi_dashboard.AddDashboardClassifyReq true "type json string"
+// @Success 200 Ret=200 新增成功
+// @router /classify/add [post]
+func (this *BIDaShboardController) AddDashboardClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.AddDashboardClassifyReq
+	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
+	}
+	maxSort, err := bi_dashboard.GetBiDashboardClassifyMaxSort()
+	if err != nil {
+		br.Msg = "获取最大排序值失败"
+		br.ErrMsg = "获取最大排序值失败,Err:" + err.Error()
+		return
+	}
+	count, err := bi_dashboard.GetBiDashboardClassifyByName(req.ClassifyName)
+	if err != nil {
+		br.Msg = "获取分类名称失败"
+		br.ErrMsg = "获取分类名称失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "分类名称已存在"
+		return
+	}
+
+	item := &bi_dashboard.BiDashboardClassify{
+		BiDashboardClassifyName: req.ClassifyName,
+		Sort:                    maxSort + 1,
+		CreateTime:              time.Now(),
+		ModifyTime:              time.Now(),
+	}
+	_, e := bi_dashboard.AddBiDashboardClassify(item)
+	if e != nil {
+		err = e
+		br.Msg = "新增失败"
+		br.ErrMsg = "新增失败,Err:" + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "新增成功"
+	//br.Data =
+}
+
+// EditDashboardClassify
+// @Title 编辑看板分类
+// @Description 编辑看板分类接口
+// @Param	request	body bi_dashboard.EditDashboardReq true "type json string"
+// @Success 200 Ret=200 编辑成功
+// @router /classify/edit [post]
+func (this *BIDaShboardController) EditDashboardClassify() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.EditDashboardClassifyReq
+	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.BiDashboardClassifyId <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误, BiDashboardClassifyId: %d", req.BiDashboardClassifyId)
+		return
+	}
+	item, err := bi_dashboard.GetBiDashboardClassifyById(req.BiDashboardClassifyId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+
+	// 修改
+	item.BiDashboardClassifyName = req.ClassifyName
+	item.ModifyTime = time.Now()
+
+	err = bi_dashboard.EditDashboardClassify(item)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "编辑成功"
+	br.IsAddLog = true
+}
+
+// Grant
+// @Title 分配看板权限
+// @Description 分配看板权限接口
+// @Param	request	body models.GrantPptReq true "type json string"
+// @Success 200 Ret=200 分配成功
+// @router /grant [post]
+func (this *BIDaShboardController) Grant() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.GrantDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.AdminIdStr == "" {
+		br.Msg = "参数错误"
+		return
+	}
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	dashboardItem, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		br.Msg = "我的看板列表查询出错"
+		br.ErrMsg = err.Error()
+		return
+	}
+	if dashboardItem.SysAdminId != this.SysUser.AdminId {
+		br.Msg = "无权配置"
+		return
+	}
+
+	list := make([]*bi_dashboard.BiDashboardGrant, 0)
+
+	grantAdminIdStrList := strings.Split(req.AdminIdStr, ",")
+	lenGrantAdminIdStrList := len(grantAdminIdStrList) //指定用户的人数
+	for _, v := range grantAdminIdStrList {
+		grantAdminId, tmpErr := strconv.Atoi(v)
+		if tmpErr != nil {
+			br.Msg = "参数有误"
+			br.ErrMsg = fmt.Sprintf("参数有误,Err:%s", tmpErr.Error())
+			return
+		}
+
+		//如果只选择了自己作为指定的人,那么就提示他报错。如果多人,那么就过滤自己
+		if grantAdminId == this.SysUser.AdminId {
+			if lenGrantAdminIdStrList == 1 {
+				br.Msg = "不能指定自己为权限用户"
+				br.ErrMsg = fmt.Sprintf("参数有误,Err:%s", tmpErr.Error())
+				return
+			}
+			continue
+		}
+		tmpV := &bi_dashboard.BiDashboardGrant{
+			BiDashboardId: req.BiDashboardId,
+			GrantAdminId:  grantAdminId,
+			CreateTime:    time.Now(),
+		}
+		list = append(list, tmpV)
+	}
+
+	if len(list) <= 0 {
+		br.Msg = "参数有误"
+		br.ErrMsg = fmt.Sprintf("参数有误,Err:%s", "指定用户为空")
+		return
+	}
+
+	err = bi_dashboard.MultiAddDashboardGrant(req.BiDashboardId, list)
+	if err != nil {
+		br.Msg = "分配失败"
+		br.ErrMsg = fmt.Sprintf("分配失败,Err:%s", err.Error())
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "分配成功"
+}
+
+// Public
+// @Title
+// @Description 设置公共看板
+// @Param	request	body models.GrantPptReq true "type json string"
+// @Success 200 Ret=200 分配成功
+// @router /public [post]
+func (this *BIDaShboardController) Public() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.PublicDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+
+	item.State = 6
+
+	err = bi_dashboard.EditDashboard(item)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "分配成功"
+}
+
+// GroupList
+// @Title 获取分类列表
+// @Description 获取分类列表接口
+// @Success 200 {object} models.RespGroupList
+// @router /classify/list [get]
+func (this *BIDaShboardController) ClassifyList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	classifyList, err := bi_dashboard.GetBiDashboardClassifyAllList()
+	if err != nil {
+		br.Msg = "查询失败"
+		br.ErrMsg = "查询失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = classifyList
+	return
+}
+
+// CancelGrant
+// @Title 取消分配看板权限
+// @Description 取消分配看板权限
+// @Param	request	body bi_dashboard.DelDashboardReq true "type json string"
+// @Success 200 Ret=200 分配成功
+// @router /grant/cancel [post]
+func (this *BIDaShboardController) CancelGrant() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.DelDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "数据不存在"
+		br.ErrMsg = "数据不存在,Err:" + err.Error()
+		return
+	}
+	if item.SysAdminId != this.SysUser.AdminId {
+		br.Msg = "无权配置"
+		return
+	}
+
+	// 分配
+	err = bi_dashboard.DeleteDashboardGrant(req.BiDashboardId)
+	if err != nil {
+		br.Msg = "取消失败"
+		br.ErrMsg = "取消失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "取消成功"
+}
+
+// GrantInfo
+// @Title 获取分配ppt权限详情
+// @Description 获取分配ppt权限详情接口
+// @Param    BiDashboardId   query   int  true       "看板的id"
+// @Success 200 {object} models.GrantInfoResp
+// @router /grant/info [get]
+func (this *BIDaShboardController) GrantInfo() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	biDashboardId, _ := this.GetInt("BiDashboardId")
+	if biDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	item, err := bi_dashboard.GetDashboardById(biDashboardId)
+	if err != nil {
+		br.Msg = "数据不存在"
+		br.ErrMsg = "数据不存在,Err:" + err.Error()
+		return
+	}
+	if item.SysAdminId != this.SysUser.AdminId {
+		br.Msg = "无权配置"
+		return
+	}
+
+	grantInfoList, err := bi_dashboard.GetDashboardGrantInfo(biDashboardId)
+	if err != nil {
+		br.Msg = "信息获取失败"
+		br.ErrMsg = "信息获取失败,Err:" + err.Error()
+		return
+	}
+
+	if len(grantInfoList) <= 0 {
+		br.Msg = "未配置"
+		br.IsSendEmail = false
+		br.Success = true
+		br.Ret = 200
+		return
+	}
+
+	var adminIdStr string
+
+	adminIdsList := make([]string, 0)
+	for _, v := range grantInfoList {
+		adminIdsList = append(adminIdsList, strconv.Itoa(int(v.GrantAdminId)))
+	}
+	adminIdStr = strings.Join(adminIdsList, ",")
+
+	br.Ret = 200
+	br.Success = true
+	br.Data = adminIdStr
+	br.Msg = "查询成功"
+}
+
+// Public
+// @Title
+// @Description 撤销公共看板
+// @Param	request	body models.GrantPptReq true "type json string"
+// @Success 200 Ret=200 分配成功
+// @router /public/cancel [post]
+func (this *BIDaShboardController) PublicCancel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.DelDashboardReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	item, err := bi_dashboard.GetDashboardById(req.BiDashboardId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取数据异常!"
+		br.ErrMsg = "获取数据异常,Err:" + err.Error()
+		return
+	}
+
+	item.State = 1
+
+	err = bi_dashboard.EditDashboard(item)
+	if err != nil {
+		br.Msg = "编辑失败"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+	br.Msg = "撤销成功"
+}
+
+// GroupList
+// @Title 获取我的首页看板
+// @Description 获取我的首页看板接口
+// @Success 200 {object} models.RespGroupList
+// @router /home_page [get]
+func (this *BIDaShboardController) HomePage() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	item, err := bi_dashboard.GetBiDashboardHomePageById(this.SysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "数据不存在"
+		br.ErrMsg = "数据不存在,Err:" + err.Error()
+		return
+	}
+
+	publicCond := ` AND state = 6 AND bi_dashboard_classify_id > 0 `
+	publicPars := []interface{}{this.SysUser.AdminId}
+	publicList, err := bi_dashboard.GetBiDashboardList(publicCond, publicPars)
+	if err != nil {
+		err = errors.New("我的看板列表查询出错:" + err.Error())
+		return
+	}
+
+	if item.BiDashboardHomePageId == 0 && len(publicList) > 0 {
+		item = &bi_dashboard.BiDashboardHomePage{
+			AdminId:       publicList[0].SysAdminId,
+			BiDashboardId: publicList[0].BiDashboardId,
+			FromType:      3,
+		}
+	}
+
+	if item.BiDashboardId == 0 {
+		item = nil
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = item
+	return
+}
+
+// GroupList
+// @Title 保存我的看板首页
+// @Description保存我的看板首页接口
+// @Success 200 {object} models.RespGroupList
+// @router /home_page/save [post]
+func (this *BIDaShboardController) HomePageSave() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req bi_dashboard.SaveHomePageReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	item, err := bi_dashboard.GetBiDashboardHomePageById(this.SysUser.AdminId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "首页看板查询失败"
+		br.ErrMsg = "首页看板查询失败,Err:" + err.Error()
+		return
+	}
+
+	homePageItem := &bi_dashboard.BiDashboardHomePage{
+		BiDashboardId: req.BiDashboardId,
+		AdminId:       this.SysUser.AdminId,
+		CreateTime:    time.Now(),
+		ModifyTime:    time.Now(),
+		FromType:      req.FromType,
+	}
+
+	if item.BiDashboardHomePageId > 0 {
+		homePageItem.BiDashboardHomePageId = item.BiDashboardHomePageId
+	}
+
+	err = bi_dashboard.SaveBiDashboardHomePage(homePageItem)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	return
+}
+
+// Editing
+// @Title 标记/查询编辑状态
+// @Description 标记/查询编辑状态
+// @Param	request	body models.PPTEditingReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /editing [post]
+func (this *BIDaShboardController) Editing() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req bi_dashboard.BiDashboardEditingReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.BiDashboardId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	if req.Status < 0 {
+		br.Msg = "标记状态异常"
+		return
+	}
+
+	editor, e := services.UpdateBiDashboardEditing(req.BiDashboardId, req.Status, sysUser.AdminId, sysUser.RealName)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "更新编辑状态失败, err: " + e.Error()
+		return
+	}
+
+	br.Data = editor
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// GroupList
+// @Title 获取我拥有的图库表格菜单权限
+// @Description 获取我拥有的图库表格菜单权限接口
+// @Success 200 {object} models.RespGroupList
+// @router /chart_excel_permission [get]
+func (this *BIDaShboardController) ChartExcelPermission() {
+	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
+	}
+
+	roleId := sysUser.RoleId
+	//roleId=1
+	if roleId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	roleIds := strconv.Itoa(roleId)
+	//查询账号绑定的其他角色
+	otherRoles, err := system.GetRoleIdsByAdminId(sysUser.AdminId)
+	if err != nil {
+		br.Msg = "获取其他角色失败"
+		br.ErrMsg = "获取其他角色失败,Err:" + err.Error()
+		return
+	}
+	if len(otherRoles) > 0 {
+		for _, v := range otherRoles {
+			roleIds += "," + strconv.Itoa(v.RoleId)
+		}
+	}
+	groupId := 0
+	if utils.RunMode == "release" {
+		groupId = 37
+	} else {
+		groupId = 61
+	}
+	//共享客户组下的用户
+	shareSellerMap := make(map[int]bool, 0)
+	subAdmins, err := system.GetAdminByGroupId(groupId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取销售失败"
+		br.ErrMsg = "获取销售失败,Err:" + err.Error()
+		return
+	}
+	for _, admin := range subAdmins {
+		shareSellerMap[admin.AdminId] = true
+	}
+
+	list, err := system.GetMenuByRoleIds(roleIds)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	lenList := len(list)
+
+	menuList := make([]*system.SysMenuSimple, 0)
+
+	chartExcelTypes, e := models.GetBusinessConfByKey("ChartExcelType")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+	types := strings.Split(chartExcelTypes.ConfVal, ",")
+	typeMap := map[string]bool{}
+	for _, v := range types {
+		typeMap[v] = true
+	}
+
+	for i := 0; i < lenList; i++ {
+		item := list[i]
+		if !typeMap[item.LevelPath] && !typeMap[item.Path] {
+			continue
+		}
+		newItem := &system.SysMenuSimple{
+			MenuId:   item.MenuId,
+			ParentId: item.ParentId,
+			Name:     item.Name,
+			Sort:     item.Sort,
+			Path:     item.Path,
+			NameEn:   item.NameEn,
+		}
+		if item.IsLevel == 1 {
+			newItem.Path = item.LevelPath
+		}
+		menuList = append(menuList, newItem)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = menuList
+	return
+}

+ 55 - 5
controllers/classify.go

@@ -204,10 +204,6 @@ func (this *ClassifyController) Delete() {
 		return
 	}
 
-	br.Msg = "报告分类不允许删除"
-	br.IsSendEmail = false
-	return
-
 	item, err := models.GetClassifyById(req.ClassifyId)
 	if err != nil {
 		br.Msg = "获取信息失败"
@@ -218,7 +214,46 @@ func (this *ClassifyController) Delete() {
 		br.Msg = "分类不存在"
 		return
 	}
-	err = models.DeleteClassify(req.ClassifyId)
+	classifyList := &models.ClassifyList{Id: item.Id}
+	err = services.MarkEnableDeleteClassify([]*models.ClassifyList{classifyList})
+	if err != nil {
+		br.Msg = "删除失败"
+		br.ErrMsg = "标记失败,Err:" + err.Error()
+		return
+	}
+	if classifyList.IsEnableDelete == 0 {
+		br.Msg = "该分类有关联报告或审批流,不允许删除"
+		return
+	}
+
+	var childClassifyIds []int
+	if item.HasChild == 1 {
+		// 获取所有子分类
+		subClassifyMap := make(map[int][]int)
+		allClassify, err := models.GetAllClassifyWithDesc()
+		if err != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取信息失败,Err:" + err.Error()
+			return
+		}
+		for _, classify := range allClassify {
+			v, ok := subClassifyMap[classify.Id]
+			if !ok {
+				subClassifyMap[classify.Id] = []int{}
+			}
+			pv, pok := subClassifyMap[classify.ParentId]
+			if pok {
+				subClassifyMap[classify.ParentId] = append(pv, classify.Id)
+			} else {
+				subClassifyMap[classify.ParentId] = []int{classify.Id}
+			}
+			if ok {
+				subClassifyMap[classify.ParentId] = append(subClassifyMap[classify.ParentId], v...)
+			}
+		}
+		childClassifyIds = subClassifyMap[item.Id]
+	}
+	err = item.Delete(childClassifyIds)
 	if err != nil {
 		br.Msg = "删除失败"
 		br.ErrMsg = "删除失败,Err:" + err.Error()
@@ -505,6 +540,12 @@ func (this *ClassifyController) ListClassify() {
 		}
 	}
 
+	err = services.MarkEnableDeleteClassify(list)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "标记可删除分类失败,Err:" + err.Error()
+		return
+	}
 	// 先将分类列表排序
 	services.SortClassifyListBySortAndCreateTime(list)
 	// 接着转换结构
@@ -863,3 +904,12 @@ func (this *ClassifyController) ClassifyPermissionV2() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// 处理禅道bug6445,对数据进行补偿刷新
+/*func init() {
+	err := services.DealBug6445()
+	if err != nil {
+		return
+	}
+}
+*/

+ 902 - 19
controllers/data_manage/ccf_data.go

@@ -1,14 +1,19 @@
 package data_manage
 
 import (
+	"encoding/json"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"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"
 	"github.com/tealeg/xlsx"
 	"os"
 	"path/filepath"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -110,7 +115,8 @@ func (this *EdbInfoController) CCFIndexData() {
 		br.ErrMsg = "请选择分类"
 		return
 	}
-
+	// 增加频度请求入参
+	frequency := this.GetString("Frequency")
 	// 获取指标
 	var condition string
 	var pars []interface{}
@@ -118,7 +124,10 @@ func (this *EdbInfoController) CCFIndexData() {
 		condition += ` AND classify_id=? `
 		pars = append(pars, classifyId)
 	}
-
+	if frequency != "" {
+		condition += ` AND frequency=? `
+		pars = append(pars, frequency)
+	}
 	indexes, err := data_manage.GetCCFIndex(condition, pars)
 	if err != nil {
 		br.Msg = "获取数据失败"
@@ -130,7 +139,7 @@ func (this *EdbInfoController) CCFIndexData() {
 	for _, v := range indexes {
 		indexCodes = append(indexCodes, v.IndexCode)
 	}
-	indexCounts, e := data_manage.GetCCFIndexDataCountGroup(indexCodes)
+	/*indexCounts, e := data_manage.GetCCFIndexDataCountGroup(indexCodes)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取指标数据总量失败, Err:" + err.Error()
@@ -139,7 +148,53 @@ func (this *EdbInfoController) CCFIndexData() {
 	countMap := make(map[string]int)
 	for _, v := range indexCounts {
 		countMap[v.IndexCode] = v.Count
+	}*/
+	edbInfoMap := make(map[string]*data_manage.EdbInfo)
+	dataMap := make(map[string][]*data_manage.BaseFromCCFData)
+	total := 0
+	if len(indexCodes) > 0 {
+		edbInfoList, err := data_manage.GetEdbInfoByEdbCodeList(utils.DATA_SOURCE_CCF, indexCodes)
+		if err != nil {
+			br.Msg = "获取数据源失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range edbInfoList {
+			edbInfoMap[v.EdbCode] = v
+		}
+		// 首先对分类下的指标按照日期进行分页,再针对日期,进行排序
+		dataTimes, err := data_manage.GetCCFIndexDataTimePageByCodes(indexCodes, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据日期信息失败,Err:" + err.Error()
+			return
+		}
+		if len(dataTimes) > 0 {
+			startDate := dataTimes[len(dataTimes)-1]
+			endDate := dataTimes[0]
+			// 把截止日往后加1天
+			endDateT, _ := time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+			endDate = endDateT.AddDate(0, 0, 1).Format(utils.FormatDate)
+			dataList, e := data_manage.GetCCFIndexDataByDataTime(indexCodes, startDate, endDate)
+			if e != nil {
+				br.Msg = "获取数据失败"
+				br.ErrMsg = "获取指标数据失败,Err:" + e.Error()
+				return
+			}
+			//将数据按照指标进行分类
+			for _, v := range dataList {
+				dataMap[v.IndexCode] = append(dataMap[v.IndexCode], v)
+			}
+		}
+
+		total, err = data_manage.GetCCFIndexDataTimePageCount(indexCodes)
+		if err != nil {
+			br.Msg = "获取数据失败"
+			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+			return
+		}
 	}
+	page := paging.GetPaging(currentIndex, pageSize, total)
 
 	resultList := make([]*data_manage.BaseFromCCFIndexList, 0)
 	for _, v := range indexes {
@@ -152,19 +207,24 @@ func (this *EdbInfoController) CCFIndexData() {
 		product.Frequency = v.Frequency
 		product.CreateTime = v.CreateTime
 		product.ModifyTime = v.ModifyTime
-
-		total := countMap[v.IndexCode]
+		if edb, ok := edbInfoMap[v.IndexCode]; ok {
+			product.EdbInfoId = edb.EdbInfoId
+			product.EdbExist = 1
+		}
+		/*total := countMap[v.IndexCode]
 		page := paging.GetPaging(currentIndex, pageSize, total)
 		dataList, e := data_manage.GetCCFIndexData(v.IndexCode, startSize, pageSize)
 		if e != nil {
 			br.Msg = "获取数据失败"
 			br.ErrMsg = "获取指标数据失败,Err:" + e.Error()
 			return
+		}*/
+
+		dataListTmp, ok := dataMap[v.IndexCode]
+		if !ok {
+			dataListTmp = make([]*data_manage.BaseFromCCFData, 0)
 		}
-		if dataList == nil {
-			dataList = make([]*data_manage.BaseFromCCFData, 0)
-		}
-		product.DataList = dataList
+		product.DataList = dataListTmp
 		product.Paging = page
 		resultList = append(resultList, product)
 	}
@@ -350,27 +410,29 @@ func (this *EdbInfoController) ExportCCFList() {
 		br.Msg = "success"
 		return
 	}
-	sheetNew := new(xlsx.Sheet)
-	sheetNew, err = xlsxFile.AddSheet("CCF化纤")
+	//sheetNew := new(xlsx.Sheet)
+	//sheetNew, err = xlsxFile.AddSheet("CCF化纤")
 
 	//sheetNew.SetColWidth()
 	//获取指标数据
-	windRow := sheetNew.AddRow()
+	/*windRow := sheetNew.AddRow()
 	secNameRow := sheetNew.AddRow()
 	indexCodeRow := sheetNew.AddRow()
 	frequencyRow := sheetNew.AddRow()
 	unitRow := sheetNew.AddRow()
-	lastModifyDateRow := sheetNew.AddRow()
+	lastModifyDateRow := sheetNew.AddRow()*/
 	//获取分类下指标最大数据量
 	var dataMax int
-	setRowIndex := 6
-	indexCodeList := make([]string, 0)
+	//setRowIndex := 6
+	codeList := make([]string, 0)
+	frequenciesMap := make(map[string][]*data_manage.BaseFromCCFIndexList)
 	for _, v := range indexList {
-		indexCodeList = append(indexCodeList, v.IndexCode)
+		codeList = append(codeList, v.IndexCode)
+		frequenciesMap[v.Frequency] = append(frequenciesMap[v.Frequency], v)
 	}
 	dataListMap := make(map[string][]*data_manage.BaseFromCCFData)
 	if len(indexList) > 0 {
-		allDataList, e := data_manage.GetCCFIndexDataByCodes(indexCodeList)
+		allDataList, e := data_manage.GetCCFIndexDataByCodes(codeList)
 		if e != nil {
 			br.Msg = "获取数据失败"
 			br.ErrMsg = "获取数据失败,Err:" + e.Error()
@@ -385,8 +447,118 @@ func (this *EdbInfoController) ExportCCFList() {
 			}
 		}
 	}
+	// 按照频率分组排序
+	frequencies := []string{
+		"日度", "周度", "旬度", "月度", "季度", "半年度", "年度",
+	}
+	for _, frequency := range frequencies {
+		//获取指标
+		indexCodeList, ok := frequenciesMap[frequency]
+		if !ok {
+			continue
+		}
+		if len(indexCodeList) <= 0 {
+			fmt.Printf("sheet:%s, 不存在指标", frequency)
+			return
+		}
+		var sheetName string
+		switch frequency {
+		case "日度":
+			sheetName = "日度(Daily)"
+		case "周度":
+			sheetName = "周度(Weekly)"
+		case "旬度":
+			sheetName = "旬度(ten-day)"
+		case "月度":
+			sheetName = "月度(Monthly)"
+		case "季度":
+			sheetName = "季度(Quarterly)"
+		case "半年度":
+			sheetName = "半年度(Semi-annual)"
+		case "年度":
+			sheetName = "年度(Annual)"
+		default:
+			sheetName = "其他数据"
+		}
+		sheetNew, err := xlsxFile.AddSheet(sheetName)
+		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 _, idx := range frequenciesMap[frequency] {
+			indexIdList = append(indexIdList, idx.BaseFromCcfIndexId)
+		}
+		dataTimeList, err := data_manage.GetCCFDataDataTimeByIndexId(indexIdList)
+		if err != nil {
+			br.Msg = "下载失败"
+			br.ErrMsg = "获取数据时间失败,Err:" + err.Error()
+			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, icl := range indexCodeList {
+			// 获取数据
+			dataList, ok := dataListMap[icl.IndexCode]
+			if !ok {
+				continue
+			}
+			if k == 0 {
+				secNameRow.AddCell().SetValue("指标名称/Metric Name")
+				frequencyRow.AddCell().SetValue("频度/Frequency")
+				unitRow.AddCell().SetValue("单位/Unit")
+				lastModifyDateRow.AddCell().SetValue("更新时间/Update Time")
+				min := k * 3
+				sheetNew.SetColWidth(min, min, 15)
+			}
+			if len(dataList) == 0 {
+				continue
+			}
+			secNameRow.AddCell().SetValue(icl.IndexName)
+			frequencyRow.AddCell().SetValue(icl.Frequency)
+			unitRow.AddCell().SetValue(icl.Unit)
+
+			timeDate, err := time.Parse(utils.FormatDateTime, dataList[0].ModifyTime)
+			if err != nil {
+				continue
+			}
+			lastModifyDateRow.AddCell().SetValue(timeDate.Format(utils.FormatDate))
+			dataInfoMap := make(map[string]*data_manage.BaseFromCCFData)
+			for _, v := range dataList {
+				dataInfoMap[v.DataTime] = v
+			}
 
-	for k, sv := range indexList {
+			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)
+				}
+			}
+		}
+	}
+	/*for k, sv := range indexList {
 		//获取数据
 		dataList, ok := dataListMap[sv.IndexCode]
 		if !ok {
@@ -454,7 +626,7 @@ func (this *EdbInfoController) ExportCCFList() {
 				}
 			}
 		}
-	}
+	}*/
 
 	err = xlsxFile.Save(downFile)
 	if err != nil {
@@ -597,3 +769,714 @@ func (this *EdbInfoController) CCFStockTable() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// CCFIndexBatchSearch
+// @Title CCF化纤信息指标查询
+// @Description CCF化纤信息指标查询
+// @Param   ClassifyIds   query   string  true       "分类id, 多个分类用英文"
+// @Param   Keyword   query   string  true       "关键词, 指标ID/指标名称"
+// @Success 200 {object} data_manage.LzFrequency
+// @router /ccf/batch_search [get]
+func (this *EdbInfoController) CCFIndexBatchSearch() {
+	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
+	}
+	classifyIdStr := this.GetString("ClassifyIds")
+	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)
+	resp := data_manage.BaseFromCCFIndexSearchList{}
+	total := 0
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	var list = make([]*data_manage.BaseFromCCFIndexList, 0)
+	var condition string
+	var pars []interface{}
+	classifyIds := strings.Split(classifyIdStr, ",")
+	if len(classifyIds) > 0 && classifyIds[0] != `` {
+		condition += " AND classify_id IN (" + utils.GetOrmInReplace(len(classifyIds)) + " ) "
+		pars = append(pars, classifyIds)
+	}
+	keyword := this.GetString("Keyword")
+	if keyword != `` {
+		condition += " AND (index_name like ? OR index_code like ?) "
+		pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+	}
+	frequencies := this.GetString("Frequencies")
+	if frequencies != "" {
+		frequencyList := strings.Split(frequencies, ",")
+		condition += " AND frequency IN (" + utils.GetOrmInReplace(len(frequencyList)) + " ) "
+		pars = append(pars, frequencyList)
+	}
+	condition += ` AND index_code not in (SELECT edb_code FROM edb_info WHERE source=?) `
+	pars = append(pars, utils.DATA_SOURCE_CCF)
+	list, err := data_manage.GetCCFIndexPage(condition, pars, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	// 获取最新值
+	endTimeList := make([]string, 0)
+	endValMap := make(map[int]string)
+	indexIds := make([]int, 0)
+	for _, v := range list {
+		endTimeList = append(endTimeList, v.EndDate)
+		indexIds = append(indexIds, v.BaseFromCcfIndexId)
+	}
+
+	if len(indexIds) > 0 {
+		dataTmpList, e := data_manage.GetCCFIndexDataByIndexIdAndDataTime(indexIds, endTimeList)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取指标最新值失败,Err:" + e.Error()
+			return
+		}
+		for _, v := range dataTmpList {
+			endValMap[v.BaseFromCcfIndexId] = v.Value
+		}
+	}
+	for _, v := range list {
+		if val, ok := endValMap[v.BaseFromCcfIndexId]; ok {
+			v.EndValue = val
+		}
+	}
+	total, err = data_manage.GetCCFIndexPageCount(condition, pars)
+	if err != nil {
+		br.Msg = "获取数据失败"
+		br.ErrMsg = "获取指标数据失败,Err:" + err.Error()
+		return
+	}
+	page = paging.GetPaging(currentIndex, pageSize, total)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// CCFIndexBatchAdd
+// @Title CCF化纤信息批量新增
+// @Description CCF化纤信息批量新增
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /ccf/batch_add [post]
+func (this *EdbInfoController) CCFIndexBatchAdd() {
+	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_CCF_" + 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_manage.CCFIndexSource2EdbReq
+		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, e, errMsg, skip := data.CCFIndexSource2Edb(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
+}
+
+// CCFIndexNameCheck
+// @Title 加入指标库的重名检测
+// @Description 加入指标库的重名检测
+// @Param   ClassifyIds   query   string  true       "分类id, 多个分类用英文"
+// @Param   Keyword   query   string  true       "关键词, 指标ID/指标名称"
+// @Success 200 {object} NameCheckResult
+// @router /ccf/edb_info/name_check [post]
+func (this *EdbInfoController) CCFIndexNameCheck() {
+	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 []*data_manage.NameCheckEdbInfoReq
+	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
+	}
+	codeMaxT := 30
+	codeLen := len(req)
+	if codeLen > codeMaxT {
+		br.Msg = "批量添加指标数量不得超过30个"
+		return
+	}
+
+	indexNames := make([]string, 0)
+	resp := make([]*data_manage.EdbNameCheckResult, 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, &data_manage.EdbNameCheckResult{
+			EdbCode: v.EdbCode,
+			EdbName: v.EdbName,
+		})
+		dataItems, err := data_manage.GetEdbDataAllByEdbCode(v.EdbCode, utils.DATA_SOURCE_CCF, 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_CCF, 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
+}
+
+// CCFAddCheck
+// @Title 加入指标库指标Id检测
+// @Description 加入指标库指标Id检测
+// @Param	request	body request.BatchAddCheckReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /ccf/edb_info/add_check [post]
+func (c *EdbInfoController) CCFAddCheck() {
+	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.BatchAddCheckReq
+	if e := json.Unmarshal(c.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	codeMaxT := 30
+	codeLen := len(req.IndexCodes)
+
+	// 获取指标库已有指标
+	existsEdb, e := data_manage.GetEdbCodesBySource(utils.DATA_SOURCE_CCF)
+	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
+	}
+
+	if codeLen == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	if codeLen > codeMaxT {
+		br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMaxT)
+		return
+	}
+
+	// 查询选中的指标
+	cond := fmt.Sprintf(` AND index_code IN (%s)`, utils.GetOrmInReplace(codeLen))
+	pars := make([]interface{}, 0)
+	pars = append(pars, req.IndexCodes)
+	list, err := data_manage.GetCCFIndex(cond, pars)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取钢联已存在信息失败,Err:" + err.Error()
+		return
+	}
+
+	if len(list) > codeMaxT {
+		br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMaxT)
+		return
+	}
+
+	resp := make([]*data_manage.BaseFromCCFIndexList, 0)
+	for _, v := range list {
+		if edb, ok := existMap[v.IndexCode]; ok {
+			v.EdbInfoId = edb.EdbInfoId
+			// todo 验证下面三个字段的用处
+			//v.EdbClassifyId = edb.ClassifyId
+			//v.EdbUniqueCode = edb.UniqueCode
+			v.EdbExist = 1
+		}
+		resp = append(resp, v)
+	}
+
+	br.Data = resp
+	br.Msg = "校验成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// CCFEdbInfoAdd
+// @Title 新增指标接口
+// @Description 新增指标接口
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success Ret=200 保存成功
+// @router /ccf/edb_info/add [post]
+func (this *EdbInfoController) CCFEdbInfoAdd() {
+	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
+	}
+
+	count, err := data_manage.GetCCFIndexDataCount(req.EdbCode)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	if count == 0 {
+		br.Msg = "指标不存在"
+	}
+
+	// 指标入库
+	edbInfo, err, errMsg, isSendEmail := data.EdbInfoAdd(utils.DATA_SOURCE_CCF, 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)
+		}()
+	}
+
+	//新增操作日志
+	{
+		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
+}
+
+// GetFrequency
+// @Title CCF化纤信息数据频度
+// @Description CCF化纤信息数据频度接口
+// @Param   ClassifyId   query   string  true       "分类Id"
+// @Success 200 {object} data_manage.LzFrequency
+// @router /ccf/frequency [get]
+func (this *EdbInfoController) GetCCFFrequency() {
+	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")
+	if classifyId < 0 {
+		br.Msg = "请选择分类"
+		br.ErrMsg = "请选择分类"
+		return
+	}
+
+	frequencyList, err := data_manage.GetCCFFrequencyByClassifyId(classifyId)
+	if err != nil {
+		br.Msg = "获取频度失败"
+		br.ErrMsg = "获取频度失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = frequencyList
+}
+
+// BatchAddEdbCheck
+// @Title 新增校验
+// @Description 新增校验
+// @Param	request	body data_manage.BatchManualEdbReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /ccf/batch/add/check [post]
+func (c *EdbInfoController) BatchAddEdbCheck() {
+	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
+	}
+
+	// 最大批量添加的数量
+	codeMaxT := 31
+
+	var req data_manage.BatchCheckCCFEdbReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,Err:" + err.Error()
+		return
+	}
+	req.Keyword = strings.TrimSpace(req.Keyword)
+	classifyIdStr := req.ClassifyIds
+
+	var list = make([]*data_manage.BaseFromCCFIndexList, 0)
+	var condition string
+	var pars []interface{}
+
+	if req.ListAll {
+		classifyIds := strings.Split(classifyIdStr, ",")
+		if len(classifyIds) > 0 && classifyIds[0] != `` {
+			condition += " AND classify_id IN (" + utils.GetOrmInReplace(len(classifyIds)) + " ) "
+			pars = append(pars, classifyIds)
+		}
+		keyword := req.Keyword
+		if keyword != `` {
+			condition += " AND (index_name like ? OR index_code like ?) "
+			pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+		}
+		frequencies := req.Frequencies
+		if frequencies != "" {
+			frequencyList := strings.Split(frequencies, ",")
+			condition += " AND frequency IN (" + utils.GetOrmInReplace(len(frequencyList)) + " ) "
+			pars = append(pars, frequencyList)
+		}
+		codes := req.TradeCodeList
+		codeList := make([]string, 0)
+		if codes != "" {
+			codeList = strings.Split(codes, ",")
+		}
+		if len(codeList) > 0 {
+			condition += ` AND index_code not in (` + utils.GetOrmInReplace(len(codeList)) + `) `
+			pars = append(pars, codeList)
+		}
+	} else {
+		codes := req.TradeCodeList
+		codeList := make([]string, 0)
+		if codes != "" {
+			codeList = strings.Split(codes, ",")
+		}
+		if len(codeList) <= 0 {
+			br.Msg = "请选择指标"
+			br.ErrMsg = "请选择指标"
+			return
+		}
+		// 指标
+		condition += ` AND index_code in (` + utils.GetOrmInReplace(len(codeList)) + `) `
+		pars = append(pars, codeList)
+
+	}
+	condition += ` AND index_code not in (SELECT edb_code FROM edb_info WHERE source=?) `
+	pars = append(pars, utils.DATA_SOURCE_CCF)
+
+	list, err = data_manage.GetCCFIndexPage(condition, pars, 0, codeMaxT)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	if len(list) >= codeMaxT {
+		br.Msg = "批量添加指标数量不得超过30个"
+		return
+	}
+
+	br.Data = list
+	br.Msg = "校验成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 31 - 1
controllers/data_manage/chart_classify.go

@@ -251,6 +251,7 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 // ChartClassifyItems
 // @Title 获取所有图表分类接口-不包含图表
 // @Description 获取所有图表分类接口-不包含图表
+// @Param   IsShowMe   query   bool  true       "是否只看我的,true、false"
 // @Success 200 {object} data_manage.ChartClassifyListResp
 // @router /chart_classify/items [get]
 func (this *ChartClassifyController) ChartClassifyItems() {
@@ -259,6 +260,7 @@ func (this *ChartClassifyController) ChartClassifyItems() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
+	isShowMe, _ := this.GetBool("IsShowMe")
 
 	level, _ := this.GetInt(`Level`)
 	rootList, err := data_manage.GetChartClassifyByParentId(0, utils.CHART_SOURCE_DEFAULT)
@@ -290,6 +292,28 @@ func (this *ChartClassifyController) ChartClassifyItems() {
 		nodeAll = append(nodeAll, rootNode)
 	}
 
+	if isShowMe {
+		// 自己拥有的分类id列表
+		chartClassifyIdList, err := data_manage.GetChartClassifyIdListByAdminId(this.SysUser.AdminId, utils.CHART_SOURCE_DEFAULT)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+			return
+		}
+
+		tmpNodeAll := nodeAll
+		nodeAll = make([]*data_manage.ChartClassifyItems, 0)
+		for _, node := range tmpNodeAll {
+			if node.Children == nil || len(node.Children) <= 0 {
+				continue
+			}
+			isSelf := data.RemoveNotChartClassifyItemsMakeTree(node, chartClassifyIdList)
+			if isSelf {
+				nodeAll = append(nodeAll, node)
+			}
+		}
+	}
+
 	language := `CN`
 	// 指标显示的语言
 	{
@@ -1091,6 +1115,12 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 		}
 		// 移除没有权限的图表
 		allNodes := data.HandleNoPermissionChart(allChartInfo, noPermissionChartIdMap, this.SysUser.AdminId)
+		allNodes, err = data.GetChartClassifyByIsMe(sysUser.AdminId, chartClassifyId, utils.CHART_SOURCE_DEFAULT, allNodes)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
 		resp.AllNodes = allNodes
 
 		br.Ret = 200
@@ -1136,4 +1166,4 @@ func (this *ChartClassifyController) ChartClassifyChartListV3() {
 	br.Success = true
 	br.Msg = "获取成功"
 	br.Data = resp
-}
+}

+ 27 - 26
controllers/data_manage/chart_info.go

@@ -16,13 +16,14 @@ import (
 	etaTrialService "eta/eta_api/services/eta_trial"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"os"
 	"os/exec"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // 图表管理
@@ -1041,7 +1042,7 @@ func (this *ChartInfoController) ChartInfoDetail() {
 		}
 		extraConfigStr = chartInfo.BarConfig
 	}
-	yearMax := 0
+	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
 			if v.LatestDate != "" {
@@ -1051,14 +1052,14 @@ func (this *ChartInfoController) ChartInfoDetail() {
 					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
 	}
 	// 开始/结束日期
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, dateMax)
 
 	if chartInfo.HaveOperaAuth {
 		// 获取图表中的指标数据
@@ -1287,7 +1288,7 @@ func (this *ChartInfoController) PreviewChartInfoDetail() {
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
-	yearMax := 0
+	var dateMax time.Time
 	for k, v := range mappingList {
 		if tmpV, ok := edbInfoIdMapping[v.EdbInfoId]; ok {
 			v.EdbInfoType = tmpV.EdbInfoType
@@ -1311,8 +1312,8 @@ func (this *ChartInfoController) PreviewChartInfoDetail() {
 					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
@@ -1327,7 +1328,7 @@ func (this *ChartInfoController) PreviewChartInfoDetail() {
 	}
 
 	// 开始/结束日期
-	startDate, endDate := utils.GetDateByDateTypeV2(req.DateType, req.StartDate, req.EndDate, req.StartYear, yearMax)
+	startDate, endDate := utils.GetDateByDateTypeV2(req.DateType, req.StartDate, req.EndDate, req.StartYear, dateMax)
 	if startDate == "" {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取失败 时间格式错误"
@@ -1593,7 +1594,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 			dateType = 3
 		}
 	}
-	yearMax := 0
+	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
 			if v.LatestDate != "" {
@@ -1603,13 +1604,13 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
 	}
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, dateMax)
 
 	if chartInfo.ChartType == 2 {
 		chartInfo.StartDate = startDate
@@ -1755,7 +1756,7 @@ func (this *ChartInfoController) ChartInfoDetailV2() {
 	}
 
 	resp.ClassifyLevels = classifyLevels
-	
+
 	//图表操作权限
 	chartInfo.IsEdit = data.CheckOpChartPermission(sysUser, chartInfo.SysUserId, chartInfo.HaveOperaAuth)
 	chartInfo.Button = data_manage.ChartViewButton{
@@ -1891,13 +1892,13 @@ func (this *ChartInfoController) ChartInfoEdbInfoDetail() {
 		br.Msg = "获取失败,Err:" + err.Error()
 		return
 	}
-	maxYear := 0
+	var maxDate time.Time
 	if edbInfo.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxDate)
 	if startDate == "" {
 		br.Msg = "参数错误"
 		br.Msg = "参数错误,无效的查询日期"
@@ -2733,7 +2734,7 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 		return
 	}
 
-	yearMax := 0
+	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
 			if v.LatestDate != "" {
@@ -2743,13 +2744,13 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 					errMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
 	}
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, dateMax)
 
 	extraConfigStr := chartInfo.ExtraConfig //图表额外数据参数
 	var barConfig data_manage.BarChartInfoReq
@@ -4163,7 +4164,7 @@ func (this *ChartInfoController) ChartInfoConvertDetail() {
 			}
 			extraConfigStr = chartInfo.BarConfig
 		}
-		yearMax := 0
+		var dateMax time.Time
 		if dateType == utils.DateTypeNYears {
 			for _, v := range mappingList {
 				if v.LatestDate != "" {
@@ -4173,14 +4174,14 @@ func (this *ChartInfoController) ChartInfoConvertDetail() {
 						br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 						return
 					}
-					if lastDateT.Year() > yearMax {
-						yearMax = lastDateT.Year()
+					if lastDateT.After(dateMax) {
+						dateMax = lastDateT
 					}
 				}
 			}
 		}
 		// 开始/结束日期
-		startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+		startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, dateMax)
 
 		// 获取图表中的指标数据
 		edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetChartConvertEdbData(chartInfoId, chartType, calendar, startDate, endDate, mappingList, extraConfigStr, chartInfo.SeasonExtraConfig, isAxis)
@@ -5012,4 +5013,4 @@ func (this *ChartInfoController) ModifyChartList() {
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"
-}
+}

+ 4 - 4
controllers/data_manage/chart_theme.go

@@ -231,7 +231,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 	chartInfo.Source = chartThemeType.ChartSource
 	chartInfo.ChartType = chartThemeType.ChartType
 
-	yearMax := 0
+	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
 			if v.LatestDate != "" {
@@ -241,14 +241,14 @@ func (c *ChartThemeController) GetThemePreviewData() {
 					br.ErrMsg = "获取图表日期信息失败,Err:" + tErr.Error()
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
 	}
 	// 开始/结束日期
-	startDate, endDate := utils.GetDateByDateTypeV2(dateType, tmpStartDate, tmpEndDate, startYear, yearMax)
+	startDate, endDate := utils.GetDateByDateTypeV2(dateType, tmpStartDate, tmpEndDate, startYear, dateMax)
 
 	// 获取图表中的指标数据
 	edbList, xEdbIdValue, yDataList, dataResp, err, errMsg := data.GetThemePreviewChartEdbData(chartType, calendar, startDate, endDate, mappingList, extraConfigStr, chartInfo.SeasonExtraConfig)

+ 9 - 0
controllers/data_manage/correlation/correlation_chart_classify.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/data"
+	"eta/eta_api/services/data/correlation"
 	correlationServ "eta/eta_api/services/data/correlation"
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
@@ -135,6 +136,14 @@ func (this *CorrelationChartClassifyController) ChartClassifyList() {
 			return nodeAll[i].Sort < nodeAll[j].Sort
 		})
 	}
+	if isShowMe {
+		nodeAll, err = correlation.GetCorrelationClassifyByIsMe(this.SysUser.AdminId, parentId, source, nodeAll)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取我的分类失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	resp.AllNodes = nodeAll
 	br.Ret = 200

+ 8 - 0
controllers/data_manage/edb_classify.go

@@ -1058,6 +1058,14 @@ func (this *EdbClassifyController) SimpleList() {
 		sortList = nodeAll
 		sort.Sort(sortList)
 	}
+	if isOnlyMe {
+		sortList, err = data.GetEdbClassifyByIsMe(sysUserId, parentId, 0, sortList)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	language := `CN`
 	// 指标显示的语言

+ 62 - 59
controllers/data_manage/edb_info.go

@@ -85,9 +85,18 @@ func (this *EdbInfoController) EdbInfoSearch() {
 	//判断指标是否存在
 	var item *data_manage.EdbInfo
 	var err error
-	if source == utils.DATA_SOURCE_GL {
-		// 如果是钢联的话,那么就先判断是不是存在钢联化工
-		item, err = data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_MYSTEEL_CHEMICAL, edbCode)
+	if utils.InArrayByInt([]int{utils.DATA_SOURCE_GL, utils.DATA_SOURCE_MYSTEEL_CHEMICAL}, source) {
+		//source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
+		source, item, err = data.GetMySteelSourceByEdbCode(edbCode)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	if item == nil {
+		item, err = data_manage.GetEdbInfoByEdbCode(source, edbCode)
 		if err != nil {
 			if err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
@@ -95,50 +104,8 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				return
 			}
 		}
-		err = nil
-		if item != nil {
-			source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
-		} else {
-			// 判断是不是已经在钢联这边已经存在了
-			item, err = data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_GL, edbCode)
-			if err != nil {
-				if err.Error() != utils.ErrNoRow() {
-					br.Msg = "获取失败"
-					br.ErrMsg = "获取失败,Err:" + err.Error()
-					return
-				}
-			}
-			err = nil
-
-			// 如果在钢联来源也没找到,那么就需要再判断下是否处于 《钢联化工》 数据源里面
-			if item == nil {
-				tmpInfo, err := data_manage.GetBaseFromMysteelChemicalIndexByCode(edbCode)
-				if err != nil {
-					if err.Error() != utils.ErrNoRow() {
-						br.Msg = "获取失败"
-						br.ErrMsg = "获取失败,Err:" + err.Error()
-						return
-					}
-				}
-				err = nil
-				if tmpInfo != nil {
-					source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
-				}
-			}
-
-		}
 	}
 
-	if item == nil {
-		item, err = data_manage.GetEdbInfoByEdbCode(source, edbCode)
-	}
-	if err != nil {
-		if err.Error() != utils.ErrNoRow() {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取失败,Err:" + err.Error()
-			return
-		}
-	}
 	var isAdd bool
 	var isInEdb bool //是否在指标库中
 	if item != nil && item.EdbInfoId > 0 {
@@ -1897,7 +1864,7 @@ func (this *EdbInfoController) EdbInfoSearch() {
 				searchItem.Unit = indexInfo.Unit
 				searchItem.EdbName = indexInfo.IndexName
 			}
-		}  else if source == utils.DATA_SOURCE_HISUGAR { //泛糖科技
+		} else if source == utils.DATA_SOURCE_HISUGAR { //泛糖科技
 			dataItems, err := data_manage.GetEdbDataAllByEdbCode(edbCode, source, subSource, utils.EDB_DATA_LIMIT)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "获取失败"
@@ -2435,7 +2402,7 @@ func (this *EdbInfoController) EdbInfoAdd() {
 	//}
 
 	// 兼容钢联与钢联化工数据
-	if source == utils.DATA_SOURCE_GL {
+	if utils.InArrayByInt([]int{utils.DATA_SOURCE_GL, utils.DATA_SOURCE_MYSTEEL_CHEMICAL}, source) {
 		// 如果是钢联的话,那么就先判断是不是存在钢联化工
 		tmpInfo, err := data_manage.GetBaseFromMysteelChemicalIndexByCode(req.EdbCode)
 		if err != nil {
@@ -2448,6 +2415,9 @@ func (this *EdbInfoController) EdbInfoAdd() {
 		if tmpInfo != nil {
 			source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
 			req.Source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
+		} else {
+			source = utils.DATA_SOURCE_GL
+			req.Source = utils.DATA_SOURCE_GL
 		}
 	}
 
@@ -3926,12 +3896,11 @@ func (this *ChartInfoController) EdbInfoData() {
 	resp.DataList = make([]*data_manage.EdbDataList, 0)
 	// 数据获取
 	if fullEdb.HaveOperaAuth { // 有权限才获取数据
-		maxYear := 0
+		var latestDateT time.Time
 		if edbInfo.LatestDate != "" {
-			latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-			maxYear = latestDateT.Year()
+			latestDateT, _ = time.Parse(utils.FormatDate, edbInfo.LatestDate)
 		}
-		startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+		startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, latestDateT)
 		dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfoId, startDate, endDate)
 		if err != nil {
 			br.Msg = "获取失败"
@@ -4050,6 +4019,42 @@ func (this *ChartInfoController) EdbInfoReplace() {
 		return
 	}
 
+	if oldEdbInfo.EdbInfoType == 1 || newEdbInfo.EdbInfoType == 1 {
+		br.Msg = "预测指标不允许替换"
+		br.ErrMsg = "预测指标不允许替换"
+		return
+	}
+	// 判断指标是否循环引用
+	if oldEdbInfo.EdbType == 2 {
+		// 查询该计算指标的所有相关指标,如果相关指标中包含新指标,则提示
+		hasRelation, e := data.CheckTwoEdbInfoRelation(oldEdbInfo, newEdbInfo)
+		if e != nil {
+			br.Msg = "替换失败!"
+			br.ErrMsg = "查询指标引用关系失败,Err:" + e.Error()
+			return
+		}
+		if hasRelation {
+			br.Msg = "原指标与替换指标存在引用关系,不允许替换"
+			br.ErrMsg = "原指标与替换指标存在引用关系,不允许替换"
+			return
+		}
+	}
+
+	if newEdbInfo.EdbType == 2 {
+		// 查询该计算指标的所有相关指标,如果相关指标中包含新指标,则提示
+		hasRelation, e := data.CheckTwoEdbInfoRelation(newEdbInfo, oldEdbInfo)
+		if e != nil {
+			br.Msg = "替换失败!"
+			br.ErrMsg = "查询指标引用关系失败,Err:" + e.Error()
+			return
+		}
+		if hasRelation {
+			br.Msg = "原指标与替换指标存在引用关系,不允许替换"
+			br.ErrMsg = "原指标与替换指标存在引用关系,不允许替换"
+			return
+		}
+	}
+
 	sysAdminId := sysUser.AdminId
 	//replaceChartTotal, replaceCalculateTotal, err := data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
 	_, _, err = data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
@@ -4564,13 +4569,12 @@ func (this *ChartInfoController) EdbInfoDataTb() {
 		br.Msg = "获取失败,Err:" + err.Error()
 		return
 	}
-	maxYear := 0
+	var latestDateT time.Time
 	if edbInfo.LatestDate != "" {
-		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-		maxYear = latestDateT.Year()
+		latestDateT, _ = time.Parse(utils.FormatDate, edbInfo.LatestDate)
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, latestDateT)
 
 	var startDateTime time.Time
 	if startDate != `` {
@@ -4667,13 +4671,12 @@ func (this *ChartInfoController) EdbInfoDataSeasonal() {
 		br.Msg = "获取失败,Err:" + err.Error()
 		return
 	}
-	maxYear := 0
+	var latestDateT time.Time
 	if edbInfo.LatestDate != "" {
-		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-		maxYear = latestDateT.Year()
+		latestDateT, _ = time.Parse(utils.FormatDate, edbInfo.LatestDate)
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, latestDateT)
 
 	dataList, err := data.GetChartEdbSeasonalData(calendar, startDate, endDate, edbInfo)
 	if err != nil {

+ 3 - 0
controllers/data_manage/excel/excel_classify.go

@@ -153,6 +153,9 @@ func (this *ExcelClassifyController) List() {
 			nodeAll = append(nodeAll, v)
 		}
 	}
+	if isShowMe {
+		nodeAll = excel2.GetClassifyListRemoveNoExcel(nodeAll)
+	}
 
 	resp := response2.ExcelClassifyListResp{
 		AllNodes: nodeAll,

+ 2 - 0
controllers/data_manage/excel/excel_info.go

@@ -1675,6 +1675,8 @@ func (c *ExcelInfoController) GetExcelTableData() {
 		SourcesFrom:   excelInfo.SourcesFrom,
 		ExcelSource:   excelSource,
 		ExcelSourceEn: excelSourceEn,
+		ExcelInfoId:   excelInfo.ExcelInfoId,
+		Source:        excelInfo.Source,
 	}
 	br.Ret = 200
 	br.Success = true

+ 6 - 3
controllers/data_manage/future_good/future_good_chart_classify.go

@@ -124,16 +124,19 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 		chartInfoMap[v.ChartClassifyId] = append(chartInfoMap[v.ChartClassifyId], v)
 	}
 	rootChildMap := make(map[int][]*data_manage.ChartClassifyItems)
+	res := make([]*data_manage.ChartClassifyItems, 0)
 	for _, v := range rootList {
 		rootChildMap[v.ParentId] = append(rootChildMap[v.ParentId], v)
 		if existItems, ok := chartInfoMap[v.ChartClassifyId]; ok {
 			v.Children = existItems
 		} else {
-			items := make([]*data_manage.ChartClassifyItems, 0)
-			v.Children = items
+			// items := make([]*data_manage.ChartClassifyItems, 0)
+			// v.Children = items
+			continue
 		}
+		res = append(res, v)
 	}
-	resp.AllNodes = rootList
+	resp.AllNodes = res
 
 	return
 }

+ 90 - 59
controllers/data_manage/future_good/future_good_chart_info.go

@@ -16,13 +16,14 @@ import (
 	etaTrialService "eta/eta_api/services/eta_trial"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"os"
 	"os/exec"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // FutureGoodChartInfoController 商品价格图表管理
@@ -949,7 +950,7 @@ func (this *FutureGoodChartInfoController) ChartEnInfoEdit() {
 				return
 			}
 
-			list, _ := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfo.FutureGoodEdbInfoId)
+			/*list, _ := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfo.FutureGoodEdbInfoId)
 			for _, v := range list {
 				if v.FutureGoodEdbNameEn == `` {
 					v.FutureGoodEdbNameEn = strings.TrimPrefix(req.FutureGoodNameEn, " ")
@@ -959,7 +960,7 @@ func (this *FutureGoodChartInfoController) ChartEnInfoEdit() {
 					v.FutureGoodEdbNameEn = strings.TrimSuffix(req.FutureGoodNameEn, " ")
 				}
 				v.Update([]string{"FutureGoodEdbNameEn"})
-			}
+			}*/
 		}
 	case utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
 		err = data_manage.EditFutureGoodProfitChartEnInfoAndEdbEnInfo(req.ChartInfoId, req.ChartNameEn, edbInfo.EdbInfoId, req.EdbNameEn, req.UnitEn, req.ProfitNameEn)
@@ -1332,16 +1333,16 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 		return
 	}
 
-	maxYear := 0
+	var maxDate time.Time
 	for _, v := range edbInfoMappingList {
 		if v.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, v.LatestDate)
-			if maxYear < latestDateT.Year() {
-				maxYear = latestDateT.Year()
+			if latestDateT.After(maxDate) {
+				maxDate = latestDateT
 			}
 		}
 	}
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxDate)
 
 	// 商品价格曲线图的一些配置
 	var barConfig data_manage.FutureGoodBarChartInfoReq
@@ -1364,6 +1365,7 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 		// 默认取第一个现货指标
 		baseEdbInfoId = edbInfoMappingList[0].EdbInfoId
 		baseEdbInfoMapping = edbInfoMappingList[0]
+		barConfig.BaseEdbInfoId = baseEdbInfoId
 	} else {
 		baseEdbInfoMapping, err = data_manage.GetChartEdbMappingByEdbInfoId(baseEdbInfoId)
 		if err != nil {
@@ -1401,6 +1403,33 @@ func getFutureGoodChartInfo(chartInfo *data_manage.ChartInfoView, chartType, dat
 				}
 			}
 		}
+		if v.Source == 0 {
+			name := strings.Split(v.EdbName, "(")
+			if barConfig.FutureGoodEdbName != "" {
+				name[0] = barConfig.FutureGoodEdbName
+			}
+			if len(name) > 1 {
+				if barConfig.FutureGoodEdbName == "" {
+					barConfig.FutureGoodEdbName = name[0]
+				}
+				v.EdbName = name[0] + "(" + name[1]
+			}
+			//英文
+			// 编译正则表达式,匹配一个或多个数字
+
+			if v.EdbNameEn != "" {
+				name = strings.Split(v.EdbNameEn, "(")
+				if barConfig.FutureGoodEdbNameEn != "" {
+					name[0] = barConfig.FutureGoodEdbNameEn
+				}
+				if len(name) > 1 {
+					if barConfig.FutureGoodEdbNameEn == "" {
+						barConfig.FutureGoodEdbNameEn = name[0]
+					}
+					v.EdbNameEn = name[0] + "(" + name[1]
+				}
+			}
+		}
 	}
 	if len(warnEdbList) > 0 {
 		chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
@@ -1743,6 +1772,33 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 				}
 			}
 		}
+		if v.Source == 0 {
+			name := strings.Split(v.EdbName, "(")
+			if barConfig.FutureGoodEdbName != "" {
+				name[0] = barConfig.FutureGoodEdbName
+			}
+			if len(name) > 1 {
+				if barConfig.FutureGoodEdbName == "" {
+					barConfig.FutureGoodEdbName = name[0]
+				}
+				v.EdbName = name[0] + "(" + name[1]
+			}
+			//英文
+			// 编译正则表达式,匹配一个或多个数字
+
+			if v.EdbNameEn != "" {
+				name = strings.Split(v.EdbNameEn, "(")
+				if barConfig.FutureGoodEdbNameEn != "" {
+					name[0] = barConfig.FutureGoodEdbNameEn
+				}
+				if len(name) > 1 {
+					if barConfig.FutureGoodEdbNameEn == "" {
+						barConfig.FutureGoodEdbNameEn = name[0]
+					}
+					v.EdbNameEn = name[0] + "(" + name[1]
+				}
+			}
+		}
 	}
 	if len(warnEdbList) > 0 {
 		chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
@@ -1931,13 +1987,13 @@ func (this *FutureGoodChartInfoController) ChartInfoEdbInfoDetail() {
 		br.Msg = "获取失败,Err:" + err.Error()
 		return
 	}
-	maxYear := 0
+	var maxDate time.Time
 	if edbInfo.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxDate)
 	if startDate == "" {
 		br.Msg = "参数错误"
 		br.Msg = "参数错误,无效的查询日期"
@@ -3285,6 +3341,22 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			}
 			xDataList := barConfig.XDataList
 			length := len(xDataList)
+			oldFutureEdbName := barConfig.FutureGoodEdbName
+			oldFutureEdbNameEn := barConfig.FutureGoodEdbNameEn
+			if oldFutureEdbName == "" {
+				futureGoodEdbInfoMapping, err := data_manage.GetFutureGoodEdbChartEdbMapping(chartItem.ChartInfoId)
+				if err != nil {
+					br.Msg = "修改失败"
+					br.ErrMsg = "获取图表现货价格指标信息失败,指标信息失败,Err:" + err.Error()
+					return
+				}
+				list, _ := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfoMapping.EdbInfoId)
+				for _, v := range list {
+					oldFutureEdbName = v.FutureGoodEdbName
+					oldFutureEdbNameEn = v.FutureGoodEdbNameEn
+					break
+				}
+			}
 			switch this.Lang {
 			case utils.EnLangVersion:
 				for k, v := range req.XDataList {
@@ -3298,6 +3370,10 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 						}
 					}
 				}
+				if req.FutureGoodName != `` {
+					barConfig.FutureGoodEdbNameEn = req.FutureGoodName
+					barConfig.FutureGoodEdbName = oldFutureEdbName
+				}
 			default:
 				for k, v := range req.XDataList {
 					v = strings.TrimPrefix(v, " ")
@@ -3310,6 +3386,10 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 						}
 					}
 				}
+				if req.FutureGoodName != `` {
+					barConfig.FutureGoodEdbName = req.FutureGoodName
+					barConfig.FutureGoodEdbNameEn = oldFutureEdbNameEn
+				}
 			}
 			barConfig.XDataList = xDataList
 			barConfigByte, e := json.Marshal(barConfig)
@@ -3321,55 +3401,6 @@ func (this *FutureGoodChartInfoController) BaseInfoEdit() {
 			chartItem.BarConfig = string(barConfigByte)
 		}
 		err = data_manage.EditBaseFutureGoodChartInfoAndEdbEnInfo(chartItem, &req, this.Lang)
-		if req.FutureGoodName != `` {
-			futureGoodEdbInfoMapping, err := data_manage.GetFutureGoodEdbChartEdbMapping(chartItem.ChartInfoId)
-			if err != nil {
-				br.Msg = "修改失败"
-				br.ErrMsg = "获取图表现货价格指标信息失败,指标信息失败,Err:" + err.Error()
-				return
-			}
-			futureGoodEdbInfo, err := future_good.GetFutureGoodEdbInfo(futureGoodEdbInfoMapping.EdbInfoId)
-			if err != nil {
-				if err.Error() == utils.ErrNoRow() {
-					br.Msg = "图表不存在!"
-					br.ErrMsg = "图表指标不存在,futureGoodEdbInfo:" + strconv.Itoa(futureGoodEdbInfo.FutureGoodEdbInfoId)
-					return
-				} else {
-					br.Msg = "获取图表信息失败!"
-					br.ErrMsg = "获取图表的指标信息失败,Err:" + err.Error()
-					return
-				}
-			}
-			if futureGoodEdbInfo == nil {
-				br.Msg = "期货商品指标不存在!"
-				br.ErrMsg = "期货商品指标不存在,futureGoodEdbInfo:" + strconv.Itoa(futureGoodEdbInfo.FutureGoodEdbInfoId)
-				return
-			}
-
-			list, _ := future_good.GetFutureGoodEdbInfoListByParentId(futureGoodEdbInfo.FutureGoodEdbInfoId)
-			for _, v := range list {
-				switch this.Lang {
-				case utils.EnLangVersion:
-					if v.FutureGoodEdbNameEn == `` {
-						v.FutureGoodEdbNameEn = strings.TrimPrefix(req.FutureGoodName, " ")
-						v.FutureGoodEdbNameEn = strings.TrimSuffix(req.FutureGoodName, " ")
-					} else {
-						v.FutureGoodEdbNameEn = strings.TrimPrefix(strings.Replace(v.FutureGoodEdbNameEn, v.FutureGoodEdbNameEn, req.FutureGoodName, -1), " ")
-						v.FutureGoodEdbNameEn = strings.TrimSuffix(req.FutureGoodName, " ")
-					}
-					v.Update([]string{"FutureGoodEdbNameEn"})
-				default:
-					if v.FutureGoodEdbName == `` {
-						v.FutureGoodEdbName = strings.TrimPrefix(req.FutureGoodName, " ")
-						v.FutureGoodEdbName = strings.TrimSuffix(req.FutureGoodName, " ")
-					} else {
-						v.FutureGoodEdbName = strings.TrimPrefix(strings.Replace(v.FutureGoodEdbName, v.FutureGoodEdbName, req.FutureGoodName, -1), " ")
-						v.FutureGoodEdbName = strings.TrimSuffix(req.FutureGoodName, " ")
-					}
-					v.Update([]string{"FutureGoodEdbName"})
-				}
-			}
-		}
 	case utils.CHART_SOURCE_FUTURE_GOOD_PROFIT:
 		if len(req.XDataList) > 0 {
 			// 处理横轴名称

+ 8 - 5
controllers/data_manage/line_equation/line_chart_classify.go

@@ -129,16 +129,19 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	for _, v := range allChartInfo {
 		chartInfoMap[v.ChartClassifyId] = append(chartInfoMap[v.ChartClassifyId], v)
 	}
-	for k, v := range rootList {
+	res := make([]*data_manage.ChartClassifyItems, 0)
+	for _, v := range rootList {
 		if existItems, ok := chartInfoMap[v.ChartClassifyId]; ok {
 			v.Children = existItems
 		} else {
-			items := make([]*data_manage.ChartClassifyItems, 0)
-			v.Children = items
+			// items := make([]*data_manage.ChartClassifyItems, 0)
+			// v.Children = items
+			continue
 		}
-		rootList[k] = v
+		res = append(res, v)
+		// rootList[k] = v
 	}
-	resp.AllNodes = rootList
+	resp.AllNodes = res
 
 	return
 }

+ 23 - 22
controllers/data_manage/line_feature/chart_info.go

@@ -15,10 +15,11 @@ import (
 	lineFeatureServ "eta/eta_api/services/data/line_feature"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // LineFeaturesChartInfoController 统计特征图表管理
@@ -170,12 +171,12 @@ func (this *LineFeaturesChartInfoController) MultipleGraphPreview() {
 
 	// 曲线图表信息
 	curveConf := req.Curve
-	maxYear := 0
+	var maxDate time.Time
 	if edbInfoMapping.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfoMapping.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
-	startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxYear)
+	startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxDate)
 	{
 		tmpChartInfo := *chartInfo
 		// 获取图表中的指标数据
@@ -434,12 +435,12 @@ func (this *LineFeaturesChartInfoController) MultipleGraphPreviewCurve() {
 		tmpChartInfo := *chartInfo
 
 		curveConf := req.Curve
-		maxYear := 0
+		var maxDate time.Time
 		if edbInfoMapping.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, edbInfoMapping.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
-		startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxDate)
 
 		// 获取图表中的指标数据
 		edbList, _, _, _, err, errMsg := data.GetChartEdbData(tmpChartInfo.ChartInfoId, tmpChartInfo.ChartType, tmpChartInfo.Calendar, startDate, endDate, []*data_manage.ChartEdbInfoMapping{edbInfoMapping}, tmpChartInfo.ExtraConfig, tmpChartInfo.SeasonExtraConfig)
@@ -584,12 +585,12 @@ func (this *LineFeaturesChartInfoController) MultipleGraphConfigSaveChart() {
 	isSendEmail := true
 
 	curveConf := req.Curve
-	maxYear := 0
+	var maxDate time.Time
 	if edbInfoMapping.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfoMapping.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
-	startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxYear)
+	startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxDate)
 	switch req.Source {
 	case utils.CHART_MULTIPLE_GRAPH_CURVE: // 曲线图
 		curveConf := req.Curve
@@ -1830,12 +1831,12 @@ func (this *LineFeaturesChartInfoController) Detail() {
 			br.ErrMsg = "格式化配置项失败,Err:" + err.Error()
 			return
 		}
-		maxYear := 0
+		var maxDate time.Time
 		if edbMapping.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, edbMapping.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
-		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxDate)
 		edbList, resultResp, err, errMsg = lineFeatureServ.GetStandardDeviationData(0, startDate, endDate, edbMapping, calculateValue)
 	case utils.CHART_SOURCE_LINE_FEATURE_PERCENTILE:
 		var percentileConfig request.Percentile
@@ -1845,12 +1846,12 @@ func (this *LineFeaturesChartInfoController) Detail() {
 			br.ErrMsg = "格式化配置项失败,Err:" + err.Error()
 			return
 		}
-		maxYear := 0
+		var maxDate time.Time
 		if edbMapping.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, edbMapping.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
-		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxDate)
 		edbList, resultResp, err, errMsg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit, percentileConfig.PercentType)
 	case utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		var frequencyDistributionConfig request.FrequencyDistribution
@@ -2459,12 +2460,12 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 			errMsg = "格式化配置项失败,Err:" + tmpErr.Error()
 			return
 		}
-		maxYear := 0
+		var maxDate time.Time
 		if edbMapping.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, edbMapping.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
-		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxDate)
 		edbList, resultResp, err, msg = lineFeatureServ.GetStandardDeviationData(0, startDate, endDate, edbMapping, calculateValue)
 	case utils.CHART_SOURCE_LINE_FEATURE_PERCENTILE:
 		var percentileConfig request.Percentile
@@ -2474,12 +2475,12 @@ func GetChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCa
 			errMsg = "格式化配置项失败,Err:" + err.Error()
 			return
 		}
-		maxYear := 0
+		var maxDate time.Time
 		if edbMapping.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, edbMapping.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
-		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(chartInfo.DateType, chartInfo.StartDate, chartInfo.EndDate, chartInfo.StartYear, maxDate)
 		edbList, resultResp, err, msg = lineFeatureServ.GetPercentileData(0, startDate, endDate, edbMapping, percentileConfig.CalculateValue, percentileConfig.CalculateUnit, percentileConfig.PercentType)
 	case utils.CHART_SOURCE_LINE_FEATURE_FREQUENCY:
 		var frequencyDistributionConfig request.FrequencyDistribution

+ 8 - 5
controllers/data_manage/line_feature/classify.go

@@ -129,16 +129,19 @@ func getChartClassifyListForMe(adminInfo system.Admin, resp *data_manage.ChartCl
 	for _, v := range allChartInfo {
 		chartInfoMap[v.ChartClassifyId] = append(chartInfoMap[v.ChartClassifyId], v)
 	}
-	for k, v := range rootList {
+	res := make([]*data_manage.ChartClassifyItems, 0)
+	for _, v := range rootList {
 		if existItems, ok := chartInfoMap[v.ChartClassifyId]; ok {
 			v.Children = existItems
 		} else {
-			items := make([]*data_manage.ChartClassifyItems, 0)
-			v.Children = items
+			// items := make([]*data_manage.ChartClassifyItems, 0)
+			// v.Children = items
+			continue
 		}
-		rootList[k] = v
+		res = append(res, v)
+		// rootList[k] = v
 	}
-	resp.AllNodes = rootList
+	resp.AllNodes = res
 
 	return
 }

+ 8 - 2
controllers/data_manage/manual_edb.go

@@ -10,12 +10,13 @@ import (
 	etaTrialService "eta/eta_api/services/eta_trial"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"github.com/shopspring/decimal"
 	"os"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/shopspring/decimal"
 )
 
 // ManualEdbController 手工指标服务(鉴权)
@@ -585,6 +586,11 @@ func (c *ManualEdbController) EditExcelData() {
 	dateValueMap := make(map[string]string)
 	//取到所有数据
 	for _, dateValue := range req.Data {
+		// 检验时间格式
+		_, err := time.Parse(utils.FormatDate, dateValue.Date)
+		if err != nil {
+			continue
+		}
 		dateValueMap[dateValue.Date] = strconv.FormatFloat(dateValue.Value, 'f', -1, 64)
 	}
 

+ 8 - 4
controllers/data_manage/multiple_graph_config.go

@@ -191,7 +191,7 @@ func (this *ChartInfoController) MultipleGraphPreview() {
 		br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 		return
 	}
-	maxYear := 0
+	var maxDate time.Time
 	var edbInfoMappingA, edbInfoMappingB *data_manage.ChartEdbInfoMapping
 	for _, v := range mappingList {
 		if v.EdbInfoId == req.EdbInfoIdA {
@@ -202,7 +202,7 @@ func (this *ChartInfoController) MultipleGraphPreview() {
 		}
 		if v.LatestDate != "" {
 			latestDateT, _ := time.Parse(utils.FormatDate, v.LatestDate)
-			maxYear = latestDateT.Year()
+			maxDate = latestDateT
 		}
 	}
 	if edbInfoMappingA == nil {
@@ -242,7 +242,7 @@ func (this *ChartInfoController) MultipleGraphPreview() {
 			}
 		}
 
-		startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxYear)
+		startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxDate)
 		// 获取图表中的指标数据
 		edbList, _, _, _, err, errMsg := data.GetChartEdbData(tmpChartInfo.ChartInfoId, tmpChartInfo.ChartType, tmpChartInfo.Calendar, startDate, endDate, mappingList, tmpChartInfo.ExtraConfig, tmpChartInfo.SeasonExtraConfig)
 		if err != nil {
@@ -362,7 +362,7 @@ func (this *ChartInfoController) MultipleGraphPreview() {
 
 			// 数据的开始/结束日期
 			curveConf := req.Curve
-			startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxYear)
+			startDate, endDate := utils.GetDateByDateTypeV2(curveConf.DateType, curveConf.StartDate, curveConf.EndDate, curveConf.StartYear, maxDate)
 
 			rollingCorrelationData := make([]interface{}, 0)
 			for _, rollingCorrelationConf := range rollingCorrelationConfList {
@@ -513,6 +513,10 @@ func (this *ChartInfoController) MultipleGraphPreviewCurve() {
 			startDate = "2020-01-01"
 		case 11:
 			startDate = "2022-01-01"
+		case 12:
+			startDate = "2023-01-01"
+		case 13:
+			startDate = "2024-01-01"
 		}
 
 		edbInfoType := 0

+ 57 - 72
controllers/data_manage/mysteel_chemical_data.go

@@ -666,23 +666,20 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 	}
 
 	var frequencies []string
+	frequencieSet := make(map[string]struct{})
 	frequencyList, err := data_manage.GetMysteelChemicalFrequency(condition, pars)
-	for _, v := range frequencyList {
-		frequencies = append(frequencies, v.Frequency)
+	if err != nil {
+		br.Msg = "获取频度失败"
+		br.ErrMsg = "获取频度失败,Err:" + err.Error()
+		return
 	}
-
-	fileName := `钢联化工数据`
-	if frequencies == nil {
-		sheet, err := xlsxFile.AddSheet("无数据")
-		if err != nil {
-			br.Msg = "新增Sheet失败"
-			br.ErrMsg = "新增Sheet失败,Err:" + err.Error()
-			return
+	for _, v := range frequencyList {
+		if _, ok := frequencieSet[v.Frequency]; !ok {
+			frequencies = append(frequencies, v.Frequency)
+			frequencieSet[v.Frequency] = struct{}{}
 		}
-		rowSecName := sheet.AddRow()
-		celSecName := rowSecName.AddCell()
-		celSecName.SetValue("")
 	}
+	secNameList := make([]*data_manage.MysteelChemicalList, 0)
 	for _, frequency := range frequencies {
 		//获取指标
 		var tmpCondition string
@@ -706,7 +703,7 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 			pars = utils.GetLikeKeywordPars(pars, keyword, 2)
 		}
 		//获取指标
-		secNameList, err := data_manage.GetMysteelChemicalIndex(tmpCondition, tmpPars)
+		secNameList, err = data_manage.GetMysteelChemicalIndex(tmpCondition, tmpPars)
 		if err != nil {
 			fmt.Println("获取数据失败,Err:" + err.Error())
 			return
@@ -730,14 +727,31 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 		frequencyRow := sheetNew.AddRow()
 		unitRow := sheetNew.AddRow()
 		lastModifyDateRow := sheetNew.AddRow()
-		//获取分类下指标最大数据量
-		dataMax, err := data_manage.GetBaseFromMysteelChemicalDataMaxCount(classifyId)
+
+		var indexIdList []int
+		for _, sv := range secNameList {
+			indexIdList = append(indexIdList, sv.Id)
+		}
+		dataTimeList, err := data_manage.GetBaseFromMysteelChemicalDataTimeByIndexId(indexIdList)
 		if err != nil {
-			fmt.Println("获取指标最大数据量失败", err.Error())
+			fmt.Println("获取数据时间失败", err.Error())
 			return
 		}
-		fmt.Println("dataMax:", dataMax)
+
+		//获取分类下指标最大数据量
 		setRowIndex := 6
+		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.GetMysteelChemicalIndexDataByCode(sv.IndexCode)
@@ -746,7 +760,7 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 				br.ErrMsg = "获取数据失败,Err:" + err.Error()
 				return
 			}
-			if len(dataList) > 0 {
+			if k == 0 {
 				windRow.AddCell().SetValue("钢联")
 				secNameRow.AddCell().SetValue("指标名称")
 				indexCodeRow.AddCell().SetValue("指标ID")
@@ -754,58 +768,29 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 				unitRow.AddCell().SetValue("单位")
 				lastModifyDateRow.AddCell().SetValue("更新时间")
 
-				secNameRow.AddCell().SetValue(sv.IndexName)
-				indexCodeRow.AddCell().SetValue(sv.IndexCode)
-				frequencyRow.AddCell().SetValue(sv.FrequencyName)
-
-				unitRow.AddCell().SetValue(sv.UnitName)
-				lastModifyDateRow.AddCell().SetValue(sv.UpdateTime)
-
-				windRow.AddCell()
-				windRow.AddCell()
-				secNameRow.AddCell()
-				indexCodeRow.AddCell()
-				frequencyRow.AddCell()
-				unitRow.AddCell()
-				lastModifyDateRow.AddCell()
-				min := k * 3
-				sheetNew.SetColWidth(min, min, 15)
-
-				if len(dataList) <= 0 {
-					for n := 0; n < dataMax; n++ {
-						rowIndex := setRowIndex + n
-						row := sheetNew.Row(rowIndex)
-						row.AddCell()
-						row.AddCell()
-						row.AddCell()
-					}
-				} else {
-					endRowIndex := 0
-					for rk, dv := range dataList {
-						rowIndex := setRowIndex + rk
-						row := sheetNew.Row(rowIndex)
-						displayDate, _ := time.Parse(utils.FormatDate, dv.DataTime)
-						displayDateCell := row.AddCell()
-						style := new(xlsx.Style)
-						style.ApplyAlignment = true
-						style.Alignment.WrapText = true
-						displayDateCell.SetStyle(style)
-						displayDateCell.SetDate(displayDate)
-
-						row.AddCell().SetValue(dv.InputValue)
-						row.AddCell()
-						endRowIndex = rowIndex
-					}
-					if len(dataList) < dataMax {
-						dataLen := dataMax - len(dataList)
-						for n := 0; n < dataLen; n++ {
-							rowIndex := (endRowIndex + 1) + n
-							row := sheetNew.Row(rowIndex)
-							row.AddCell()
-							row.AddCell()
-							row.AddCell()
-						}
-					}
+			}
+			if len(dataList) == 0 {
+				continue
+
+			}
+			secNameRow.AddCell().SetValue(sv.IndexName)
+			indexCodeRow.AddCell().SetValue(sv.IndexCode)
+			frequencyRow.AddCell().SetValue(sv.FrequencyName)
+			unitRow.AddCell().SetValue(sv.UnitName)
+			lastModifyDateRow.AddCell().SetValue(sv.UpdateTime)
+
+			dataInfoMap := make(map[string]*data_manage.MysteelChemicalData)
+			for _, dv := range dataList {
+				dataInfoMap[dv.DataTime] = dv
+			}
+
+			for rk, dtv := range dataTimeList {
+				rowIndex := setRowIndex + rk
+				row := sheetNew.Row(rowIndex)
+				displayDateCell := row.AddCell()
+				tmpData, ok := dataInfoMap[dtv]
+				if ok {
+					displayDateCell.SetValue(tmpData.InputValue)
 				}
 			}
 		}
@@ -830,7 +815,7 @@ func (this *EdbClassifyController) MysteelChemicalExport() {
 			return
 		}
 	}
-
+	fileName := "上海钢联"
 	fileName += time.Now().Format("06.01.02") + `.xlsx` //文件名称
 	this.Ctx.Output.Download(downLoadnFilePath, fileName)
 	defer func() {

+ 9 - 0
controllers/data_manage/predict_edb_classify.go

@@ -792,6 +792,15 @@ func (this *PredictEdbClassifyController) SimpleList() {
 		sort.Sort(sortList)
 	}
 
+	if isOnlyMe {
+		sortList, err = data.GetEdbClassifyByIsMe(sysUserId, parentId, 1, sortList)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取只看我的分类列表失败,err:" + err.Error()
+			return
+		}
+	}
+
 	// 是否允许添加一级分类
 	canOpClassify := true
 	button := data.GetPredictEdbClassifyOpButton(this.SysUser, 0, true)

+ 6 - 6
controllers/data_manage/predict_edb_info.go

@@ -1407,13 +1407,13 @@ func (this *PredictEdbInfoController) DataList() {
 		}
 	}
 
-	maxYear := 0
+	var maxDate time.Time
 	if edbInfo.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, edbInfo.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxDate)
 	if endDate == "" {
 		endDate = time.Now().Format(utils.FormatDate)
 	}
@@ -1638,13 +1638,13 @@ func (this *PredictEdbInfoController) ChartDataList() {
 		return
 	}
 	// todo 确认预测指标是否用的是来源指标的最新日期
-	maxYear := 0
+	var maxDate time.Time
 	if sourceEdbInfoItem.LatestDate != "" {
 		latestDateT, _ := time.Parse(utils.FormatDate, sourceEdbInfoItem.LatestDate)
-		maxYear = latestDateT.Year()
+		maxDate = latestDateT
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxYear)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, maxDate)
 	if endDate == "" {
 		endDate = time.Now().Format(utils.FormatDate)
 	}

+ 9 - 0
controllers/data_manage/range_analysis/chart_classify.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/models/system"
 	"eta/eta_api/services/data"
 	"eta/eta_api/services/data/data_manage_permission"
+	"eta/eta_api/services/data/range_analysis"
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
@@ -127,6 +128,14 @@ func (this *RangeChartClassifyController) ChartClassifyList() {
 			nodeAll = append(nodeAll, v)
 		}
 	}
+	if isShowMe {
+		nodeAll, err = range_analysis.GetClassifyListByIsShowMe(this.SysUser.AdminId, parentId, source, nodeAll)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	// 整体排序
 	if len(nodeAll) > 0 {

+ 6 - 5
controllers/data_manage/supply_analysis/variety_edb.go

@@ -11,12 +11,13 @@ import (
 	supply_analysisServ "eta/eta_api/services/data/supply_analysis"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/tealeg/xlsx"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/tealeg/xlsx"
 )
 
 // EdbList
@@ -96,7 +97,7 @@ func (this *VarietyController) EdbList() {
 
 		if tmpItem, ok := edbInfoAndClassifyMap[v.EdbInfoId]; ok {
 			classifyNameList := make([]string, 0)
- 
+
 			// 所属分类
 			{
 				classifyList, tmpErr, errMsg := data.GetFullClassifyByClassifyId(tmpItem.ClassifyId)
@@ -620,7 +621,7 @@ func (this *VarietyController) EdbInfoDataTb() {
 		Calendar:         "",
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate.Year())
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate)
 
 	var startDateTime time.Time
 	if startDate != `` {
@@ -749,7 +750,7 @@ func (this *VarietyController) EdbInfoDataSeasonal() {
 		Calendar:         "",
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate.Year())
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate)
 
 	dataList, minVal, maxVal, err := supply_analysisServ.GetChartEdbSeasonalData(varietyEdbId, calendar, startDate, endDate, edbInfo.LatestDate)
 	if err != nil {
@@ -848,7 +849,7 @@ func (this *VarietyController) EdbDataListV2() {
 		Calendar:         "",
 	}
 
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate.Year())
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, varietyEdbInfo.EndDate)
 
 	var startDateTime time.Time
 	if startDate != `` {

+ 42 - 0
controllers/data_stat/edb_terminal.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/services/data_stat"
 	"eta/eta_api/utils"
+	"fmt"
 )
 
 // EdbTerminalController 数据源终端管理
@@ -198,3 +199,44 @@ func (this *EdbTerminalController) TerminalCodeList() {
 	br.Msg = "获取成功"
 	br.Data = resp
 }
+
+// TerminalIndexDirInfo
+// @Title 获取指标终端文件夹信息
+// @Description 获取指标终端文件夹信息
+// @Success 200 {object} data_manage.EdbTerminalDirInfo
+// @router /terminal/index_dir [get]
+func (this *EdbTerminalController) TerminalIndexDirInfo() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	source, _ := this.GetInt("Source")
+	indexId, _ := this.GetInt("IndexId")
+	if source <= 0 || indexId <= 0 {
+		br.Msg = "请选择数据源和指标ID"
+		return
+	}
+	info := new(data_manage.EdbTerminalDirInfo)
+	var err error
+	info, err = data_stat.GetEdbTerminalDirInfo(indexId, source)
+	if err != nil {
+		utils.FileLog.Info(fmt.Sprintf("获取终端文件夹信息失败indexId:%d,source:%d,Err:%s", indexId, source, err.Error()))
+		//br.Msg = "获取终端文件夹信息失败"
+		//br.ErrMsg = "获取终端文件夹信息失败 ErrMsg:" + err.Error()
+		//return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = info
+}

+ 6 - 1
controllers/document_manage/document_manage_controller.go

@@ -193,6 +193,11 @@ func (this *DocumentManageController) RuiSiReportList() {
 	classifyIdFirst, _ := this.GetInt("ClassifyIdFirst", 0)
 	classifyIdSecond, _ := this.GetInt("ClassifyIdSecond", 0)
 	classifyIdThird, _ := this.GetInt("ClassifyIdThird", 0)
+	chartPermissionIdString := this.GetString("ChartPermissionIdList")
+	var chartPermissionIdList []string
+	if strings.TrimSpace(chartPermissionIdString) != "" {
+		chartPermissionIdList = strings.Split(chartPermissionIdString, ",")
+	}
 
 	keyword := this.GetString("Keyword")
 	orderField := this.GetString("OrderField")
@@ -206,7 +211,7 @@ func (this *DocumentManageController) RuiSiReportList() {
 	if currentIndex <= 0 {
 		currentIndex = 1
 	}
-	RuiSiReportPage, err := document_manage_service.RuiSiReportList(classifyIdFirst, classifyIdSecond, classifyIdThird, keyword, orderField, orderType, currentIndex, pageSize)
+	RuiSiReportPage, err := document_manage_service.RuiSiReportList(classifyIdFirst, classifyIdSecond, classifyIdThird, chartPermissionIdList, keyword, orderField, orderType, currentIndex, pageSize)
 	if err != nil {
 		br.Msg = "获取报告列表失败"
 		br.ErrMsg = "获取报告列表失败,Err:" + err.Error()

+ 398 - 0
controllers/edb_monitor/edb_monitor.go

@@ -0,0 +1,398 @@
+package edb_monitor
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/edb_monitor/request"
+	edbmonitor "eta/eta_api/services/edb_monitor"
+	"strings"
+)
+
+type EdbMonitorController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 预警管理列表
+// @Description 预警管理列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   ClassifyId   query   string  true       "分类ID,多选用逗号分隔"
+// @Param   Level   query   string  true       "预警等级,多选用逗号分隔"
+// @Param   State   query   string  true       "预警状态,多选用逗号分隔"
+// @Param   UserId   query   string  true       "创建人ID,多选用逗号分隔"
+// @Success 200 {object} response.EdbMonitorInfoListResp
+// @router /list [get]
+func (m *EdbMonitorController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	pageSize, _ := m.GetInt("PageSize")
+	currentIndex, _ := m.GetInt("CurrentIndex")
+	classifyId := m.GetString("ClassifyId")
+	level := m.GetString("Level")
+	state := m.GetString("State")
+	userId := m.GetString("UserId")
+
+	resp, msg, err := edbmonitor.GetMonitorList(classifyId, level, state, userId, pageSize, currentIndex)
+	if err != nil {
+		if msg == "" {
+			msg = "获取列表失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Data = resp
+	br.Msg = "获取列表成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Add
+// @Title 预警管理添加
+// @Description 预警管理添加
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /add [post]
+func (m *EdbMonitorController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorInfoSaveReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择分类"
+		return
+	}
+	switch req.MonitorType {
+	case edbmonitor.EDB_MONITOR_TYPE_DOWN, edbmonitor.EDB_MONITOR_TYPE_UP:
+	default:
+		br.Msg = "请选择预警等级"
+		return
+	}
+	req.MonitorData = strings.TrimSpace(req.MonitorData)
+	if req.MonitorData == "" {
+		br.Msg = "请输入预警值"
+		return
+	}
+	req.EdbMonitorName = strings.TrimSpace(req.EdbMonitorName)
+	if req.EdbMonitorName == "" {
+		br.Msg = "请输入预警名称"
+		return
+	}
+
+	msg, err := edbmonitor.SaveEdbMonitorInfo(req, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "添加失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "添加成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// edit
+// @Title 预警管理编辑
+// @Description 预警管理编辑
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /edit [post]
+func (m *EdbMonitorController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorInfoSaveReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	if req.EdbMonitorId <= 0 {
+		br.Msg = "请选择预警"
+		return
+	}
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择分类"
+		return
+	}
+	switch req.MonitorType {
+	case edbmonitor.EDB_MONITOR_TYPE_DOWN, edbmonitor.EDB_MONITOR_TYPE_UP:
+	default:
+		br.Msg = "请选择预警等级"
+		return
+	}
+	req.MonitorData = strings.TrimSpace(req.MonitorData)
+	if req.MonitorData == "" {
+		br.Msg = "请输入预警值"
+		return
+	}
+	req.EdbMonitorName = strings.TrimSpace(req.EdbMonitorName)
+	if req.EdbMonitorName == "" {
+		br.Msg = "请输入预警名称"
+		return
+	}
+
+	msg, err := edbmonitor.SaveEdbMonitorInfo(req, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "编辑失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "编辑成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// delete
+// @Title 预警管理编辑
+// @Description 预警管理编辑
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /delete [post]
+func (m *EdbMonitorController) Delete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorInfoDeleteReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	if req.EdbMonitorId <= 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	msg, err := edbmonitor.DeleteEdbMonitorInfo(req, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "删除失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "删除成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Close
+// @Title 预警管理关闭
+// @Description 预警管理关闭
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /close [post]
+func (m *EdbMonitorController) Close() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorInfoCloseReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	if req.EdbMonitorId <= 0 {
+		br.Msg = "请选择预警"
+		return
+	}
+
+	msg, err := edbmonitor.CloseEdbMonitorInfo(req, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "关闭失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "关闭成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Restart
+// @Title 预警管理重启
+// @Description 预警管理重启
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /restart [post]
+func (m *EdbMonitorController) Restart() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorInfoRestartReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+	if req.EdbMonitorId <= 0 {
+		br.Msg = "请选择预警"
+		return
+	}
+
+	msg, err := edbmonitor.RestartEdbMonitorInfo(req, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "重启失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "重启成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// GetMonitorLevel
+// @Title 预警管理等级列表
+// @Description 预警管理等级列表
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /monitor_level/list [get]
+func (m *EdbMonitorController) GetMonitorLevel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	list, msg, err := edbmonitor.GetEdbMonitorLevelList()
+	if err != nil {
+		if msg == "" {
+			msg = "获取预警等级失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Data = list
+	br.Msg = "获取成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// GetMonitorUser
+// @Title 预警管理用户列表
+// @Description 预警管理用户列表
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /monitor_user/list [get]
+func (m *EdbMonitorController) GetMonitorUser() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	resp, msg, err := edbmonitor.GetEdbMonitorInfoUserList()
+	if err != nil {
+		if msg == "" {
+			msg = "获取用户列表失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Data = resp
+	br.Msg = "获取成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 240 - 0
controllers/edb_monitor/edb_monitor_classify.go

@@ -0,0 +1,240 @@
+package edb_monitor
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/edb_monitor/request"
+	edbmonitor "eta/eta_api/services/edb_monitor"
+	"strings"
+)
+
+type EdbMonitorClassifyController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 预警管理分类列表
+// @Description 预警管理分类列表
+// @Success 200 {object} response.EdbMonitorClassifyTree
+// @router /classify/list [get]
+func (c *EdbMonitorClassifyController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	resp, msg, err := edbmonitor.GetEdbMonitorClassifyTree()
+	if err != nil {
+		if msg == "" {
+			msg = "获取分类列表失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Data = resp
+	br.Msg = "获取成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Add
+// @Title 预警管理分类添加
+// @Description 预警管理分类添加
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /classify/add [post]
+func (c *EdbMonitorClassifyController) Add() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.EdbMonitorClassifySaveReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	req.ClassifyName = strings.TrimSpace(req.ClassifyName)
+	if req.ClassifyName == "" {
+		br.Msg = "分类名称不能为空"
+		return
+	}
+	if req.Level <= 0 || req.ClassifyId > 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	msg, err := edbmonitor.SaveEdbMonitorClassify(req)
+	if err != nil {
+		if msg == "" {
+			msg = "分类添加失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "分类添加成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Edit
+// @Title 预警管理分类编辑
+// @Description 预警管理分类编辑
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @router /classify/edit [post]
+func (c *EdbMonitorClassifyController) Edit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.EdbMonitorClassifySaveReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "分类不存在,请刷新页面"
+		return
+	}
+	req.ClassifyName = strings.TrimSpace(req.ClassifyName)
+	if req.ClassifyName == "" {
+		br.Msg = "分类名称不能为空"
+		return
+	}
+	if req.Level <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	msg, err := edbmonitor.SaveEdbMonitorClassify(req)
+	if err != nil {
+		if msg == "" {
+			msg = "分类添加失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "分类编辑成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Delete
+// @Title 预警管理分类删除
+// @Description 预警管理分类删除
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @router /classify/delete [post]
+func (c *EdbMonitorClassifyController) Delete() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.EdbMonitorClassifyDeleteReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "分类不存在,请刷新页面"
+		return
+	}
+
+	msg, err := edbmonitor.DeleteEdbMonitorClassify(req)
+	if err != nil {
+		if msg == "" {
+			msg = "分类删除失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "分类删除成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Move
+// @Title 预警分类移动接口
+// @Description 预警分类移动接口
+// @Param   request body request.MoveEdbMonitorClassifyReq  true  "每页数据条数"
+// @router /classify/move [post]
+func (c *EdbMonitorClassifyController) Move() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	var req request.MoveEdbMonitorClassifyReq
+	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数解析失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "参数错误"
+		br.ErrMsg = "分类id小于等于0"
+		return
+	}
+	msg, err := edbmonitor.MoveEdbMonitorClassify(req)
+	if err != nil {
+		if msg == "" {
+			msg = "分类移动失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Msg = "分类移动成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 251 - 0
controllers/edb_monitor/edb_monitor_message.go

@@ -0,0 +1,251 @@
+package edb_monitor
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/edb_monitor/request"
+	edbmonitor "eta/eta_api/services/edb_monitor"
+	"eta/eta_api/utils"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gorilla/websocket"
+)
+
+type EdbMonitorMessageController struct {
+	controllers.BaseAuthController
+}
+
+var upgrader = websocket.Upgrader{
+	ReadBufferSize:  1024,
+	WriteBufferSize: 1024,
+	CheckOrigin: func(r *http.Request) bool {
+		return true
+	},
+}
+
+// GetMonitorLevel
+// @Title 预警管理消息
+// @Description 预警管理消息
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /message/connect [get]
+func (m *EdbMonitorMessageController) Connect() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var conn *websocket.Conn
+	connKey := edbmonitor.EDB_MONITOR_MESSAGE_CONNECT_CACHE + strconv.Itoa(sysUser.AdminId)
+	ok := utils.Rc.IsExist(connKey)
+	if !ok {
+		conn = edbmonitor.MonitorMessageConn[sysUser.AdminId]
+		if conn != nil {
+			conn.Close()
+		}
+	}
+	err := utils.Rc.Put(connKey, "1", time.Minute*1)
+	if err != nil {
+		br.Msg = "系统错误"
+		br.ErrMsg = "连接失败,err:" + err.Error()
+		return
+	}
+	conn, err = upgrader.Upgrade(m.Ctx.ResponseWriter, m.Ctx.Request, nil)
+	if err != nil {
+		br.Msg = "连接失败"
+		br.ErrMsg = "连接失败,err:" + err.Error()
+		return
+	}
+	defer conn.Close()
+
+	edbmonitor.MonitorMessageConn[sysUser.AdminId] = conn
+	conn.SetCloseHandler(func(code int, text string) error {
+		delete(edbmonitor.MonitorMessageConn, sysUser.AdminId)
+		utils.Rc.Delete(connKey)
+		return nil
+	})
+
+	go func() {
+		// 心跳检测
+		for {
+			isClose, err := edbmonitor.EdbMonitorMessageHealth(sysUser.AdminId)
+			if err != nil {
+				utils.FileLog.Error("指标预警信息健康检查失败,err:%s, adminId:%d", err.Error(), sysUser.AdminId)
+				return
+			}
+			if isClose {
+				return
+			}
+		}
+	}()
+
+	messageList, err := edbmonitor.GetHistoryMessages(sysUser.AdminId)
+	if err != nil {
+		utils.FileLog.Error("获取指标预警信息历史失败,err:%s, adminId:%d", err.Error(), sysUser.AdminId)
+	}
+	success := make(chan int, 10)
+	go func() {
+		defer close(success)
+		for i, msg := range messageList {
+			if i == 0 {
+				// 多条消息仅发送最新一条
+				err = edbmonitor.SendMessages(sysUser.AdminId, msg.EdbInfoId, msg.EdbInfoType, msg.EdbClassifyId, msg.EdbUniqueCode, msg.Message, msg.TriggerTime)
+				if err != nil {
+					utils.FileLog.Error("指标预警信息发送失败,err:%s, adminId:%d", err.Error(), sysUser.AdminId)
+				} else {
+					success <- msg.EdbMonitorMessageId
+				}
+			} else {
+				success <- msg.EdbMonitorMessageId
+			}
+		}
+	}()
+	go func() {
+		readList := make([]int, 0)
+		for {
+			msgId, ok := <-success
+			if !ok {
+				break
+			}
+			readList = append(readList, msgId)
+		}
+		_, err = edbmonitor.ReadEdbMonitorMessageList(readList, sysUser.AdminId)
+		if err != nil {
+			utils.FileLog.Error("指标预警信息已读失败,err:%s, adminId:%d", err.Error(), sysUser.AdminId)
+		}
+	}()
+
+	for {
+		ok = utils.Rc.IsExist(connKey)
+		if !ok {
+			br.Msg = "连接已断开"
+			br.Ret = 200
+			br.Success = true
+			return
+		}
+		time.Sleep(10 * time.Second)
+	}
+}
+
+// Close
+// @Title 预警管理消息
+// @Description 预警管理消息
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /message/close [post]
+func (m *EdbMonitorMessageController) Close() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	conn := edbmonitor.MonitorMessageConn[sysUser.AdminId]
+	if conn != nil {
+		conn.Close()
+	}
+
+	br.Msg = "关闭成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// List
+// @Title 预警管理消息列表
+// @Description 预警管理消息列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Success 200 {object} response.EdbMonitorClassifyTree
+// @router /message/list [get]
+func (c *EdbMonitorMessageController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	pageSize, _ := c.GetInt("PageSize")
+	currentIndex, _ := c.GetInt("CurrentIndex")
+	resp, err := edbmonitor.GetMessageList(sysUser.AdminId, currentIndex, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	br.Data = resp
+	br.Msg = "获取成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// Read
+// @Title 预警管理消息已读
+// @Description 预警管理消息已读
+// @Param   request body request.EdbMonitorSaveRequest  true  "每页数据条数"
+// @Success 200 {object} models.EnglishReportEmailPageListResp
+// @router /message/read [post]
+func (m *EdbMonitorMessageController) Read() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		m.Data["json"] = br
+		m.ServeJSON()
+	}()
+
+	sysUser := m.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req request.EdbMonitorMessageReadReq
+	if err := json.Unmarshal(m.Ctx.Input.RequestBody, &req); err != nil {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,err:" + err.Error()
+		return
+	}
+	if req.EdbMonitorMessageId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+
+	msg, err := edbmonitor.ReadEdbMonitorMessage(req.EdbMonitorMessageId, sysUser.AdminId)
+	if err != nil {
+		if msg == "" {
+			msg = "系统错误"
+		}
+		br.Msg = msg
+		br.ErrMsg = "读取消息失败,err:" + err.Error()
+		return
+	}
+
+	br.Msg = "已读成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 22 - 13
controllers/english_report/english_classify.go

@@ -79,6 +79,7 @@ func (this *EnglishReportController) ListClassify() {
 	// 三级分类-品种权限
 	permissionMap := make(map[int][]int)
 
+	var secondClassify []*models.EnglishClassifyList
 	if len(idList) > 0 {
 		childIdMap := make(map[int]struct{}, 0)
 		for _, v := range idList {
@@ -97,6 +98,7 @@ func (this *EnglishReportController) ListClassify() {
 			br.ErrMsg = "获取二级分类失败,Err:" + err.Error()
 			return
 		}
+		secondClassify = tmpList
 		for _, v := range tmpList {
 			if _, ok := rootMap[v.ParentId]; !ok {
 				thirdIds = append(thirdIds, v.Id)
@@ -145,6 +147,13 @@ func (this *EnglishReportController) ListClassify() {
 			}
 		}
 	}
+	// 标记可删除的英文分类
+	err = services.MarkEnableDeleteEnlishClassify(rootList, secondClassify)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "标记可删除分类失败,Err:" + err.Error()
+		return
+	}
 
 	//处理一级分类
 	var sortList models.RSClassifyList
@@ -483,18 +492,18 @@ func (this *EnglishReportController) DelClassify() {
 		return
 	}
 
-	count, err := models.GetEnglishClassifyChildCounts(classifyId)
-	if err != nil && err.Error() != utils.ErrNoRow() {
-		br.Msg = "获取信息失败"
-		br.ErrMsg = "获取失败,Err:" + err.Error()
-		return
-	}
+	// count, err := models.GetEnglishClassifyChildCounts(classifyId)
+	// if err != nil && err.Error() != utils.ErrNoRow() {
+	// 	br.Msg = "获取信息失败"
+	// 	br.ErrMsg = "获取失败,Err:" + err.Error()
+	// 	return
+	// }
 
-	if count > 0 {
-		br.Msg = "请先删除该分类下关联分类"
-		br.Ret = 403
-		return
-	}
+	// if count > 0 {
+	// 	br.Msg = "请先删除该分类下关联分类"
+	// 	br.Ret = 403
+	// 	return
+	// }
 	reportCount, e := models.GetEnglishReportCounts(classifyId, classifyInfo.ParentId)
 	if e != nil && e.Error() != utils.ErrNoRow() {
 		br.Msg = "获取信息失败"
@@ -536,8 +545,8 @@ func (this *EnglishReportController) DelClassify() {
 		br.Ret = 403
 		return
 	}
-
-	if err = models.DeleteEnglishClassify(classifyId); err != nil {
+	err = classifyInfo.Delete()
+	if err != nil {
 		br.Msg = "删除失败"
 		br.ErrMsg = "删除报告失败, Err: " + err.Error()
 		return

+ 36 - 5
controllers/english_report/report.go

@@ -12,11 +12,12 @@ import (
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"html"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // EnglishReportController 研报活动模块
@@ -90,9 +91,19 @@ func (this *EnglishReportController) Add() {
 		br.ErrMsg = "期数获取失败,Err:" + err.Error()
 		return
 	}
+	reportClassify, e := models.GetEnglishReportClassifyById(req.ClassifyIdFirst)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告所在分类异常"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取分类失败, Err: " + e.Error()
+		return
+	}
 
 	// 根据审批开关及审批流判断当前报告状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird, models.ReportOperateAdd)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportClassify.RootId, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -1299,9 +1310,19 @@ func (this *EnglishReportController) SubmitApprove() {
 		br.ErrMsg = "获取报告失败, Err: " + e.Error()
 		return
 	}
+	reportClassify, e := models.GetEnglishReportClassifyById(reportItem.ClassifyIdFirst)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告所在分类异常"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取分类失败, Err: " + e.Error()
+		return
+	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateSubmitApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportClassify.RootId, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
@@ -1324,7 +1345,7 @@ func (this *EnglishReportController) SubmitApprove() {
 	}
 
 	// 提交审批
-	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, sysUser.AdminId, sysUser.RealName)
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.Title, reportClassify.RootId, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "提交审批失败, Err: " + e.Error()
@@ -1390,9 +1411,19 @@ func (this *EnglishReportController) CancelApprove() {
 		br.ErrMsg = "获取报告失败, Err: " + e.Error()
 		return
 	}
+	reportClassify, e := models.GetEnglishReportClassifyById(reportItem.ClassifyIdFirst)
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告所在分类异常"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取分类失败, Err: " + e.Error()
+		return
+	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateCancelApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportClassify.RootId, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()

+ 19 - 2
controllers/message.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage/data_manage_permission"
+	edbmonitor "eta/eta_api/models/edb_monitor"
 	"eta/eta_api/models/report_approve"
 	"fmt"
 )
@@ -35,7 +36,7 @@ func (c *MessageController) UnReadMessageNum() {
 		return
 	}
 
-	var unReadReportNum, unReadDataPermissionNum int
+	var unReadReportNum, unReadDataPermissionNum, unReadEdbMonitorNum int
 
 	// 获取报告审批消息
 	{
@@ -75,9 +76,25 @@ func (c *MessageController) UnReadMessageNum() {
 		}
 		unReadDataPermissionNum = unreadTotal
 	}
+	// 获取预警消息
+	{
+		pars := make([]interface{}, 0)
+		cond := ` AND admin_id = ? AND is_read = ?`
+		pars = append(pars, sysUser.AdminId, 0)
+
+		// 未读消息数
+		messageOb := new(edbmonitor.EdbMonitorMessage)
+		unreadTotal, e := messageOb.GetCountByCondition(cond, pars)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取资产消息列表总数失败, Err: " + e.Error()
+			return
+		}
+		unReadEdbMonitorNum = unreadTotal
+	}
 
 	// 汇总数
-	num := unReadReportNum + unReadDataPermissionNum
+	num := unReadReportNum + unReadDataPermissionNum + unReadEdbMonitorNum
 
 	br.Data = num
 	br.Ret = 200

+ 118 - 33
controllers/report_approve/report_approve.go

@@ -8,11 +8,12 @@ import (
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // ReportApproveController 报告审批
@@ -29,6 +30,7 @@ type ReportApproveController struct {
 // @Param   ReportType			query   int     false	"报告类型:1-中文研报;2-英文研报;3-智能研报"
 // @Param   ClassifyIdFirst		query	int		false	"一级分类ID"
 // @Param   ClassifyIdSecond	query	int		false	"二级分类ID"
+// @Param   ClassifyIdThird		query	int		false	"三级级分类ID"
 // @Param   Keyword				query	string	false	"搜索关键词"
 // @Param   ApproveState		query	int		false	"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"
 // @Param   TimeType			query	int		false	"时间类型:1-提交时间;2-处理时间;3-审批时间"
@@ -114,9 +116,21 @@ func (this *ReportApproveController) List() {
 		order := ""
 
 		// 筛选条件
-		if params.ReportType > 0 && params.ClassifySecondId > 0 {
-			cond += fmt.Sprintf(` AND b.%s = ? AND b.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
-			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		if params.ReportType > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ReportType)
+			pars = append(pars, params.ReportType)
+		}
+		if params.ClassifyFirstId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifyFirstId)
+			pars = append(pars, params.ClassifyFirstId)
+		}
+		if params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ClassifySecondId)
+		}
+		if params.ClassifyThirdId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifyThirdId)
+			pars = append(pars, params.ClassifyThirdId)
 		}
 		if params.TimeType <= 0 {
 			params.TimeType = 1
@@ -180,9 +194,21 @@ func (this *ReportApproveController) List() {
 		order := ""
 
 		// 筛选条件
-		if params.ReportType > 0 && params.ClassifySecondId > 0 {
-			cond += fmt.Sprintf(` AND b.%s = ? AND b.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
-			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		if params.ReportType > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ReportType)
+			pars = append(pars, params.ReportType)
+		}
+		if params.ClassifyFirstId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifyFirstId)
+			pars = append(pars, params.ClassifyFirstId)
+		}
+		if params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ClassifySecondId)
+		}
+		if params.ClassifyThirdId > 0 {
+			cond += fmt.Sprintf(` AND b.%s = ?`, report_approve.ReportApproveCols.ClassifyThirdId)
+			pars = append(pars, params.ClassifyThirdId)
 		}
 		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
 			_, e := time.Parse(utils.FormatDate, params.StartTime)
@@ -253,10 +279,23 @@ func (this *ReportApproveController) List() {
 		order := ""
 
 		// 筛选条件
-		if params.ReportType > 0 && params.ClassifySecondId > 0 {
-			cond += fmt.Sprintf(` AND a.%s = ? AND a.%s = ?`, report_approve.ReportApproveCols.ReportType, report_approve.ReportApproveCols.ClassifySecondId)
-			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		if params.ReportType > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ReportType)
+			pars = append(pars, params.ReportType)
+		}
+		if params.ClassifyFirstId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ClassifyFirstId)
+			pars = append(pars, params.ClassifyFirstId)
+		}
+		if params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ClassifySecondId)
+			pars = append(pars, params.ClassifySecondId)
 		}
+		if params.ClassifyThirdId > 0 {
+			cond += fmt.Sprintf(` AND a.%s = ?`, report_approve.ReportApproveCols.ClassifyThirdId)
+			pars = append(pars, params.ClassifyThirdId)
+		}
+
 		if params.TimeType > 0 && params.StartTime != "" && params.EndTime != "" {
 			_, e := time.Parse(utils.FormatDate, params.StartTime)
 			if e != nil {
@@ -365,17 +404,36 @@ func (this *ReportApproveController) List() {
 	for _, v := range ormList {
 		t := report_approve.FormatReportApproveOrm2Item(v)
 		if v.ReportType == report_approve.FlowReportTypeEnglish {
-			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], enClassifyIdName[v.ClassifyFirstId], enClassifyIdName[v.ClassifySecondId])
+			var classifyPath []string
+			if v.ReportType > 0 {
+				classifyPath = append(classifyPath, report_approve.FlowReportTypeMap[v.ReportType])
+			}
+			if v.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifyFirstId])
+			}
+			if v.ClassifySecondId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifySecondId])
+			}
+			if v.ClassifyThirdId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifyThirdId])
+			}
+			t.ReportClassify = strings.Join(classifyPath, "/")
 		} else {
 			//t.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId], cnClassifyIdName[v.ClassifySecondId])
-			reportClassify := fmt.Sprintf("%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId])
+			var classifyPath []string
+			if v.ReportType > 0 {
+				classifyPath = append(classifyPath, report_approve.FlowReportTypeMap[v.ReportType])
+			}
+			if v.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifyFirstId])
+			}
 			if v.ClassifySecondId > 0 {
-				reportClassify = fmt.Sprintf("%s/%s", reportClassify, cnClassifyIdName[v.ClassifySecondId])
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifySecondId])
 			}
 			if v.ClassifyThirdId > 0 {
-				reportClassify = fmt.Sprintf("%s/%s", reportClassify, cnClassifyIdName[v.ClassifyThirdId])
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifyThirdId])
 			}
-			t.ReportClassify = reportClassify
+			t.ReportClassify = strings.Join(classifyPath, "/")
 		}
 
 		k := fmt.Sprintf("%d-%d", t.ReportType, t.ReportId)
@@ -568,26 +626,53 @@ func (this *ReportApproveController) Detail() {
 	detail.Report.ReportLayout = 1
 
 	// 报告分类路由
-	if approveItem.ReportType == report_approve.FlowReportTypeChinese {
-		reportInfo, e := models.GetReportLayoutByReportId(approveItem.ReportId)
-		if e != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取报告失败, Err: " + e.Error()
-			return
+	{
+		if approveItem.ReportType == report_approve.FlowReportTypeChinese {
+			reportInfo, e := models.GetReportLayoutByReportId(approveItem.ReportId)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取报告失败, Err: " + e.Error()
+				return
+			}
+			detail.Report.ReportLayout = reportInfo.ReportLayout
+
+			detail.Report.ReportCode = utils.MD5(strconv.Itoa(approveItem.ReportId))
+		}
+		if approveItem.ReportType == report_approve.FlowReportTypeEnglish {
+			detail.Report.ReportCode = utils.MD5(strconv.Itoa(approveItem.ReportId))
+		}
+		if approveItem.ReportType == report_approve.FlowReportTypeSmart {
+			detail.Report.ReportLayout = 2
+			detail.Report.ReportCode = utils.MD5(fmt.Sprint("smart_", approveItem.ReportId))
 		}
-		detail.Report.ReportLayout = reportInfo.ReportLayout
 
-		detail.Report.ReportCode = utils.MD5(strconv.Itoa(approveItem.ReportId))
-		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], cnClassifyIdName[approveItem.ClassifyFirstId], cnClassifyIdName[approveItem.ClassifySecondId])
-	}
-	if approveItem.ReportType == report_approve.FlowReportTypeEnglish {
-		detail.Report.ReportCode = utils.MD5(strconv.Itoa(approveItem.ReportId))
-		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], enClassifyIdName[enRootIdMap[approveItem.ClassifySecondId]], enClassifyIdName[approveItem.ClassifyFirstId], enClassifyIdName[approveItem.ClassifySecondId])
-	}
-	if approveItem.ReportType == report_approve.FlowReportTypeSmart {
-		detail.Report.ReportLayout = 2
-		detail.Report.ReportCode = utils.MD5(fmt.Sprint("smart_", approveItem.ReportId))
-		detail.Report.ReportClassify = fmt.Sprintf("%s/%s/%s", report_approve.FlowReportTypeMap[approveItem.ReportType], cnClassifyIdName[approveItem.ClassifyFirstId], cnClassifyIdName[approveItem.ClassifySecondId])
+		var classifyPath []string
+		if approveItem.ReportType > 0 {
+			classifyPath = append(classifyPath, report_approve.FlowReportTypeMap[approveItem.ReportType])
+		}
+		if approveItem.ReportType == report_approve.FlowReportTypeEnglish {
+			if approveItem.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[approveItem.ClassifyFirstId])
+			}
+			if approveItem.ClassifySecondId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[approveItem.ClassifySecondId])
+			}
+			if approveItem.ClassifyThirdId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[approveItem.ClassifyThirdId])
+			}
+			detail.Report.ReportClassify = strings.Join(classifyPath, "/")
+		} else {
+			if approveItem.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, cnClassifyIdName[approveItem.ClassifyFirstId])
+			}
+			if approveItem.ClassifySecondId > 0 {
+				classifyPath = append(classifyPath, cnClassifyIdName[approveItem.ClassifySecondId])
+			}
+			if approveItem.ClassifyThirdId > 0 {
+				classifyPath = append(classifyPath, cnClassifyIdName[approveItem.ClassifyThirdId])
+			}
+			detail.Report.ReportClassify = strings.Join(classifyPath, "/")
+		}
 	}
 
 	br.Data = detail

+ 38 - 10
controllers/report_approve/report_approve_flow.go

@@ -8,10 +8,11 @@ import (
 	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"sync"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // ReportApproveFlowController 报告审批流
@@ -66,13 +67,21 @@ func (this *ReportApproveFlowController) List() {
 			cond += fmt.Sprintf(` AND %s LIKE ?`, report_approve.ReportApproveFlowCols.FlowName)
 			pars = append(pars, kw)
 		}
-		if params.ReportType > 0 && params.ClassifySecondId > 0 {
-			cond += fmt.Sprintf(` AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifySecondId)
-			pars = append(pars, params.ReportType, params.ClassifySecondId)
+		if params.ReportType > 0 {
+			cond += fmt.Sprintf(` AND %s = ? `, report_approve.ReportApproveFlowCols.ReportType)
+			pars = append(pars, params.ReportType)
+		}
+		if params.ClassifyFirstId > 0 {
+			cond += fmt.Sprintf(` AND %s = ? `, report_approve.ReportApproveFlowCols.ClassifyFirstId)
+			pars = append(pars, params.ClassifyFirstId)
+		}
+		if params.ClassifySecondId > 0 {
+			cond += fmt.Sprintf(` AND %s = ?`, report_approve.ReportApproveFlowCols.ClassifySecondId)
+			pars = append(pars, params.ClassifySecondId)
 		}
 		if params.ClassifyThirdId > 0 {
 			cond += fmt.Sprintf(` AND %s = ? `, report_approve.ReportApproveFlowCols.ClassifyThirdId)
-			pars = append(pars, params.ReportType, params.ClassifyThirdId)
+			pars = append(pars, params.ClassifyThirdId)
 		}
 		if params.SortRule > 0 {
 			orderMap := map[int]string{1: "ASC", 2: "DESC"}
@@ -141,16 +150,35 @@ func (this *ReportApproveFlowController) List() {
 	for _, v := range list {
 		t := report_approve.FormatReportApproveFlow2Item(v)
 		if v.ReportType == report_approve.FlowReportTypeEnglish {
-			t.ReportClassify = fmt.Sprintf("%s/%s/%s/%s", report_approve.FlowReportTypeMap[v.ReportType], enClassifyIdName[enRootIdMap[v.ClassifySecondId]], enClassifyIdName[v.ClassifyFirstId], enClassifyIdName[v.ClassifySecondId])
+			var classifyPath []string
+			if v.ReportType > 0 {
+				classifyPath = append(classifyPath, report_approve.FlowReportTypeMap[v.ReportType])
+			}
+			if v.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifyFirstId])
+			}
+			if v.ClassifySecondId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifySecondId])
+			}
+			if v.ClassifyThirdId > 0 {
+				classifyPath = append(classifyPath, enClassifyIdName[v.ClassifyThirdId])
+			}
+			t.ReportClassify = strings.Join(classifyPath, "/")
 		} else {
-			reportClassify := fmt.Sprintf("%s/%s", report_approve.FlowReportTypeMap[v.ReportType], cnClassifyIdName[v.ClassifyFirstId])
+			var classifyPath []string
+			if v.ReportType > 0 {
+				classifyPath = append(classifyPath, report_approve.FlowReportTypeMap[v.ReportType])
+			}
+			if v.ClassifyFirstId > 0 {
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifyFirstId])
+			}
 			if v.ClassifySecondId > 0 {
-				reportClassify = fmt.Sprintf("%s/%s", reportClassify, cnClassifyIdName[v.ClassifySecondId])
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifySecondId])
 			}
 			if v.ClassifyThirdId > 0 {
-				reportClassify = fmt.Sprintf("%s/%s", reportClassify, cnClassifyIdName[v.ClassifyThirdId])
+				classifyPath = append(classifyPath, cnClassifyIdName[v.ClassifyThirdId])
 			}
-			t.ReportClassify = reportClassify
+			t.ReportClassify = strings.Join(classifyPath, "/")
 		}
 		resp.List = append(resp.List, t)
 	}

+ 98 - 2
controllers/report_chapter.go

@@ -372,11 +372,19 @@ func (this *ReportController) EditDayWeekChapter() {
 		br.IsSendEmail = false
 		return
 	}
+	if reportChapterInfo.PublishState == 2 {
+		br.Msg = "该报告章节已发布,不允许编辑"
+		br.ErrMsg = "该报告章节已发布,不允许编辑"
+		br.IsSendEmail = false
+		return
+	}
+
 	// 报告的最后编辑人
 	reportInfo.LastModifyAdminId = sysUser.AdminId
 	reportInfo.LastModifyAdminName = sysUser.RealName
 	reportInfo.ModifyTime = time.Now()
 
+	updateCols := make([]string, 0)
 	reqTickerList := req.TickerList
 	// 更新章节及指标
 	contentSub := ""
@@ -405,6 +413,7 @@ func (this *ReportController) EditDayWeekChapter() {
 
 	if req.Title != "" {
 		reportChapterInfo.Title = req.Title
+		updateCols = append(updateCols, "Title")
 	}
 	//reportChapterInfo.AddType = req.AddType
 	reportChapterInfo.Author = req.Author
@@ -414,6 +423,7 @@ func (this *ReportController) EditDayWeekChapter() {
 	reportChapterInfo.ModifyTime = time.Now()
 	if req.CreateTime != `` {
 		reportChapterInfo.CreateTime = req.CreateTime
+		updateCols = append(updateCols, "CreateTime")
 	}
 
 	reportChapterInfo.LastModifyAdminId = sysUser.AdminId
@@ -421,8 +431,7 @@ func (this *ReportController) EditDayWeekChapter() {
 	reportChapterInfo.ContentModifyTime = time.Now()
 	reportChapterInfo.ContentStruct = html.EscapeString(req.ContentStruct)
 
-	updateCols := make([]string, 0)
-	updateCols = append(updateCols, "Title", "AddType", "Author", "Content", "ContentSub", "IsEdit", "CreateTime", "ModifyTime")
+	updateCols = append(updateCols, "Author", "Content", "ContentSub", "IsEdit", "ModifyTime")
 
 	updateCols = append(updateCols, "LastModifyAdminId", "LastModifyAdminName", "ContentModifyTime", "ContentStruct")
 
@@ -1630,3 +1639,90 @@ func (this *ReportController) EditChapterTitle() {
 	br.Success = true
 	br.Msg = "保存成功"
 }
+
+// CancelPublishReportChapter
+// @Title 取消发布章节
+// @Description 取消发布章节
+// @Param	request	body models.PublishReportChapterReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /chapter/publish/cancel [post]
+func (this *ReportController) CancelPublishReportChapter() {
+	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 models.PublishReportChapterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportChapterId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+
+	// 获取章节详情
+	chapterInfo, err := models.GetReportChapterInfoById(req.ReportChapterId)
+	if err != nil {
+		br.Msg = "章节信息有误"
+		br.ErrMsg = "获取章节信息失败, Err: " + err.Error()
+		return
+	}
+	// 章节发布状态校验
+	if chapterInfo.PublishState == 1 {
+		br.Msg = "该章节未发布,不能重复撤销"
+		br.ErrMsg = "该章节未发布,不能重复撤销"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(chapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "查询报告有误"
+		br.ErrMsg = "查询报告信息失败, Err: " + err.Error()
+		return
+	}
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许撤销章节"
+		br.ErrMsg = "该报告已发布,不允许撤销章节"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 更新章节信息
+	chapterInfo.PublishState = 1
+	chapterInfo.PublishTime = time.Time{}
+	chapterInfo.LastModifyAdminId = this.SysUser.AdminId
+	chapterInfo.LastModifyAdminName = this.SysUser.RealName
+	chapterInfo.ModifyTime = time.Now()
+
+	updateCols := make([]string, 0)
+	updateCols = append(updateCols, "PublishState", "PublishTime", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime")
+	err = chapterInfo.UpdateChapter(updateCols)
+	if err != nil {
+		br.Msg = "发布失败"
+		br.ErrMsg = "报告章节内容保存失败, Err: " + err.Error()
+		return
+	}
+
+	// 更新章节ES
+	{
+		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "撤销成功"
+}

+ 1 - 1
controllers/report_v2.go

@@ -886,7 +886,7 @@ func (this *ReportController) AuthorizedListReport() {
 	}
 	if classifyIdThird > 0 {
 		condition += ` AND a.classify_id_third = ? `
-		pars = append(pars, classifyIdSecond)
+		pars = append(pars, classifyIdThird)
 	}
 
 	if keyword != `` {

+ 10 - 1
controllers/sandbox/sandbox.go

@@ -12,8 +12,9 @@ import (
 	sandboxService "eta/eta_api/services/sandbox"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // versionSize 版本列表第一页数据约定是:3条
@@ -847,6 +848,14 @@ func (this *SandboxController) SandboxClassifyItems() {
 		//allNodes := sandboxService.HandleNoPermissionSandbox(resp.AllNodes, nil)
 		//resp.AllNodes = allNodes
 
+		nodeAll, err := sandboxService.GetSandboxClassifyByIsShowMe(resp.AllNodes, sandboxClassifyId, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		resp.AllNodes = nodeAll
+
 		br.Ret = 200
 		br.Success = true
 		br.Msg = "获取成功"

+ 18 - 1
controllers/sys_admin.go

@@ -120,6 +120,7 @@ func (this *SysAdminController) ListSysuser() {
 	}
 
 	var list []*system.AdminItem
+	var roleIdList []int
 	adminIdArr := make([]int, 0)
 	if teamId <= 0 {
 		//if groupId > 0 {
@@ -151,6 +152,7 @@ func (this *SysAdminController) ListSysuser() {
 			item := list[i]
 			//adminIdArr = append(adminIdArr, strconv.Itoa(item.AdminId))
 			adminIdArr = append(adminIdArr, item.AdminId)
+			roleIdList = append(roleIdList, item.RoleId)
 			var secondName *string
 			if item.GroupId != 0 {
 				pid, err := company.GetParentIdFromGroup(item.GroupId)
@@ -225,7 +227,7 @@ func (this *SysAdminController) ListSysuser() {
 			item := list[i]
 			//adminIdArr = append(adminIdArr, strconv.Itoa(item.AdminId))
 			adminIdArr = append(adminIdArr, item.AdminId)
-
+			roleIdList = append(roleIdList, item.RoleId)
 			if item.DepartmentName != "" {
 				if item.GroupName == "" {
 					list[i].DepartmentGroup = item.DepartmentName
@@ -289,6 +291,21 @@ func (this *SysAdminController) ListSysuser() {
 		}
 	}
 
+	roles, err := system.GetSysRoleByIdList(roleIdList)
+	if err != nil {
+		br.ErrMsg = "获取角色信息失败,Err:" + err.Error()
+	} else {
+		roleMap := make(map[int]string)
+		for _, v := range roles {
+			roleMap[v.RoleId] = v.RoleName
+		}
+		for _, v := range list {
+			if mv, ok := roleMap[v.RoleId]; ok {
+				v.RoleName = mv
+			}
+		}
+	}
+
 	fmt.Println("teamId:", teamId)
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(system.SysuserListResp)

+ 26 - 18
controllers/target.go

@@ -767,34 +767,42 @@ func (this *TargetController) ClassifyList() {
 		return
 	}
 
-	classifyIdStrList := make([]string, 0)
+	classifyIdList := make([]int, 0)
 	for _, classifyList := range list {
 		if classifyList.Child != nil {
 			for _, classify := range classifyList.Child {
-				classifyIdStrList = append(classifyIdStrList, strconv.Itoa(classify.ClassifyId))
+				classifyIdList = append(classifyIdList, classify.ClassifyId)
 			}
 		}
 	}
-	if len(classifyIdStrList) > 0 {
-		edbInfoGroupCountList, err := models.GetEdbInfoGroupCountByClassifyIds(strings.Join(classifyIdStrList, ","))
-		if err != nil {
-			br.Msg = "获取失败"
-			br.ErrMsg = "获取分类下有数据的指标数量失败,Err:" + err.Error()
-			return
-		}
-
-		edbInfoGroupCountMap := make(map[int]int)
-		for _, edbInfoGroupCount := range edbInfoGroupCountList {
-			edbInfoGroupCountMap[edbInfoGroupCount.ClassifyId] = edbInfoGroupCount.Count
-		}
+	if len(classifyIdList) > 0 {
+		//edbInfoGroupCountList, err := models.GetEdbInfoGroupCountByClassifyIds(classifyIdList)
+		//if err != nil {
+		//	br.Msg = "获取失败"
+		//	br.ErrMsg = "获取分类下有数据的指标数量失败,Err:" + err.Error()
+		//	return
+		//}
+		//
+		//edbInfoGroupCountMap := make(map[int]int)
+		//for _, edbInfoGroupCount := range edbInfoGroupCountList {
+		//	edbInfoGroupCountMap[edbInfoGroupCount.ClassifyId] = edbInfoGroupCount.Count
+		//}
+		//for _, classifyList := range list {
+		//	classifyList.UniqueCode = utils.MD5(fmt.Sprint(classifyList.ClassifyId))
+		//	if classifyList.Child != nil {
+		//		for _, classify := range classifyList.Child {
+		//			if total, ok := edbInfoGroupCountMap[classify.ClassifyId]; ok {
+		//				classify.EdbInfoTotal = total
+		//				classify.UniqueCode = utils.MD5(fmt.Sprint(classify.ClassifyId))
+		//			}
+		//		}
+		//	}
+		//}
 		for _, classifyList := range list {
 			classifyList.UniqueCode = utils.MD5(fmt.Sprint(classifyList.ClassifyId))
 			if classifyList.Child != nil {
 				for _, classify := range classifyList.Child {
-					if total, ok := edbInfoGroupCountMap[classify.ClassifyId]; ok {
-						classify.EdbInfoTotal = total
-						classify.UniqueCode = utils.MD5(fmt.Sprint(classify.ClassifyId))
-					}
+					classify.UniqueCode = utils.MD5(fmt.Sprint(classify.ClassifyId))
 				}
 			}
 		}

+ 20 - 3
go.mod

@@ -20,10 +20,12 @@ require (
 	github.com/beevik/etree v1.3.0
 	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.0
+	github.com/go-sql-driver/mysql v1.7.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
 	github.com/gorilla/websocket v1.5.1
 	github.com/h2non/filetype v1.1.3
 	github.com/jung-kurt/gofpdf v1.16.2
@@ -51,6 +53,8 @@ require (
 )
 
 require (
+	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
 	github.com/alibabacloud-go/debug v1.0.0 // indirect
 	github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
@@ -69,6 +73,7 @@ require (
 	github.com/bradfitz/gomemcache v0.0.0-20220106215444-fb4bf637b56d // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/clbanning/mxj/v2 v2.5.5 // indirect
+	github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
 	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
@@ -76,6 +81,7 @@ require (
 	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/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.1 // indirect
@@ -85,7 +91,6 @@ require (
 	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/google/uuid v1.6.0 // indirect
 	github.com/gorilla/css v1.0.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -94,7 +99,7 @@ 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.6 // indirect
+	github.com/klauspost/compress v1.17.8 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.6 // indirect
 	github.com/leodido/go-urn v1.2.0 // indirect
 	github.com/magiconair/properties v1.8.1 // indirect
@@ -110,16 +115,23 @@ require (
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/pelletier/go-toml v1.9.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/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/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
@@ -136,7 +148,11 @@ require (
 	github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect
 	github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
+	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/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
@@ -146,6 +162,7 @@ require (
 	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
+	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	xorm.io/builder v0.3.6 // indirect

+ 56 - 6
go.sum

@@ -16,9 +16,13 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 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=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 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=
@@ -115,6 +119,7 @@ github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkY
 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/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=
@@ -149,6 +154,8 @@ github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:sr
 github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
+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=
@@ -191,6 +198,8 @@ github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHj
 github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-mysql-org/go-mysql v1.9.1 h1:W2ZKkHkoM4mmkasJCoSYfaE4RQNxXTb6VqiaMpKFrJc=
+github.com/go-mysql-org/go-mysql v1.9.1/go.mod h1:+SgFgTlqjqOQoMc98n9oyUWEgn2KkOL1VmXDoq2ONOs=
 github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
@@ -206,14 +215,16 @@ 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.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
-github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
+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-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/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=
@@ -352,8 +363,8 @@ github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53/go.mod h1
 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.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
-github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/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=
@@ -458,6 +469,16 @@ github.com/pelletier/go-toml v1.9.2/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
 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=
+github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+github.com/pingcap/errors v0.11.5-0.20221009092201-b66cddb77c32 h1:m5ZsBa5o/0CkzZXfXLaThzKuR85SnHHetqBCpzQ30h8=
+github.com/pingcap/errors v0.11.5-0.20221009092201-b66cddb77c32/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
+github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c h1:CgbKAHto5CQgWM9fSBIvaxsJHuGP0uM74HXtv3MyyGQ=
+github.com/pingcap/failpoint v0.0.0-20220801062533-2eaa32854a6c/go.mod h1:4qGtCB0QK0wBzKtFEGDhxXnSnbQApw1gc9siScUl8ew=
+github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22 h1:2SOzvGvE8beiC1Y4g9Onkvu6UmuBBOeWRGQEjJaT/JY=
+github.com/pingcap/log v1.1.1-0.20230317032135-a0d097d16e22/go.mod h1:DWQW5jICDR7UJh4HtxXSM20Churx4CQL0fwL/SoOSA4=
+github.com/pingcap/tidb/pkg/parser v0.0.0-20231103042308-035ad5ccbe67 h1:m0RZ583HjzG3NweDi4xAcK54NBBPJh+zXp5Fp60dHtw=
+github.com/pingcap/tidb/pkg/parser v0.0.0-20231103042308-035ad5ccbe67/go.mod h1:yRkiqLFwIqibYg2P7h4bclHjHcJiIFRLKhGRyBcKYus=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -498,6 +519,8 @@ github.com/qiniu/qmgo v1.1.8/go.mod h1:QvZkzWNEv0buWPx0kdZsSs6URhESVubacxFPlITmv
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rdlucklib/rdluck_tools v1.0.3 h1:iOtK2QPlPQ6CL6c1htCk5VnFCHzyG6DCfJtunrMswK0=
 github.com/rdlucklib/rdluck_tools v1.0.3/go.mod h1:9Onw9o4w19C8KE5lxb8GyxgRBbZweRVkQSc79v38EaA=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
+github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
 github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
 github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
@@ -517,6 +540,7 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 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=
@@ -524,6 +548,10 @@ github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9Nz
 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/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=
+github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07 h1:oI+RNwuC9jF2g2lP0u0cVEEZrc/AYBCuFdvwrLWM/6Q=
+github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
 github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
 github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
 github.com/silenceper/wechat/v2 v2.1.6 h1:2br2DxNzhksmvIBJ+PfMqjqsvoZmd/5BnMIfjKYUBgc=
@@ -554,8 +582,9 @@ github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5q
 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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 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=
@@ -631,10 +660,23 @@ 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.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+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=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+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=
@@ -660,6 +702,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
 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=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -820,6 +864,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
 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=
@@ -892,6 +938,9 @@ 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=
@@ -905,6 +954,7 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 9 - 2
models/ai_summary/ai_summary_classify.go

@@ -2,9 +2,10 @@ package ai_summary
 
 import (
 	"fmt"
+	"time"
+
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
-	"time"
 )
 
 type AiSummaryClassify struct {
@@ -29,6 +30,7 @@ func AddAiSummaryClassify(item *AiSummaryClassify) (lastId int64, err error) {
 
 type AiSummaryClassifyItems struct {
 	AiSummaryClassifyId int
+	Title               string    `description:"标题" json:"-"`
 	ClassifyName        string    `description:"分类名称"`
 	ParentId            int       `description:"父级id"`
 	HasData             int       `description:"是否含有指标数据"`
@@ -328,4 +330,9 @@ func GetAiSummaryClassifyAll() (items []*AiSummaryClassifyItems, err error) {
 	return
 }
 
-
+func GetAiSummaryClassifyAllIncludeParent() (items []*AiSummaryClassifyItems, err error) {
+	o := orm.NewOrm()
+	sql := ` SELECT * FROM ai_summary_classify order by sort asc,ai_summary_classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}

+ 170 - 0
models/bi_dashboard/bi_dashboard.go

@@ -0,0 +1,170 @@
+package bi_dashboard
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BiDashboard struct {
+	BiDashboardId         int       `gorm:"primaryKey;autoIncrement;column:bi_dashboard_id"` // bi看板id
+	BiDashboardClassifyId int       `gorm:"column:bi_dashboard_classify_id" `                // 看板分类id
+	BiDashboardName       string    `gorm:"column:bi_dashboard_name;size:255"`               // 看板名称
+	SysAdminId            int       `gorm:"column:sys_admin_id" `                            // 创建人ID
+	SysAdminName          string    `gorm:"column:sys_admin_name;size:128" `                 // 创建人姓名
+	Sort                  int       `gorm:"column:sort" `                                    // 排序字段
+	CreateTime            time.Time `gorm:"column:create_time" `                             // 创建时间
+	ModifyTime            time.Time `gorm:"column:modify_time"`                              // 更新时间
+	State                 int       `gorm:"column:state"`                                    // 状态 1:未公开; 4-待审批;5-已驳回;6-已通过
+}
+
+// tableName
+func (m *BiDashboard) TableName() string {
+	return "bi_dashboard"
+}
+
+func (m *BiDashboard) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+// AddBiDashboard 新增看板
+func AddBiDashboard(item *BiDashboard) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+// GetShareDashboard 获取公开分享的看板
+func GetShareDashboard() (items []*BiDashboard, err error) {
+	//o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM bi_dashboard WHERE 1=1 AND state = 6 `
+
+	sql += `ORDER BY create_time DESC`
+	//sql += `ORDER BY create_time DESC LIMIT ?,?`
+	//_, err = o.Raw(sql).QueryRows(&items)
+	//err = global.DEFAULT_DmSQL.Raw(sql).Find(&items).Error
+	return
+}
+
+func GetBiDashboardList(condition string, pars []interface{}) (items []*BiDashboard, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM bi_dashboard WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	//
+	sql += `ORDER BY modify_time DESC `
+	//sql += `ORDER BY create_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, pars...).QueryRows(&items)
+	return
+}
+
+// GetDashboardById 获取看板
+func GetDashboardById(id int) (item *BiDashboard, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM bi_dashboard WHERE bi_dashboard_id = ? limit 1`
+
+	//sql += `ORDER BY create_time DESC LIMIT ?,?`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// del
+func DelDashboard(id int) (err error) {
+	o := orm.NewOrm()
+	sql := `DELETE FROM bi_dashboard WHERE bi_dashboard_id = ?`
+	_, err = o.Raw(sql, id).Exec()
+	return
+}
+
+// BiDashboardEditingCache PPT编辑缓存信息
+type BiDashboardEditingCache struct {
+	IsEditing bool   `description:"是否有人编辑"`
+	AdminId   int    `description:"编辑者ID"`
+	Editor    string `description:"编辑者姓名"`
+	Tips      string `description:"提示信息"`
+}
+
+// DashboardDetailResp 详情响应体
+type DashboardDetailResp struct {
+	*BiDashboard
+	IsGrant   int                     `description:"是否共享,0:不是,1:是"`
+	Editor    BiDashboardEditingCache `description:"编辑人信息"`
+	List      []*BiDashboardDetail
+}
+
+type AddDashboardReq struct {
+	List            []*AddDashboardListReq
+	BiDashboardName string `description:"看板名称"`
+}
+
+type AddDashboardListReq struct {
+	Type       int
+	UniqueCode string
+	Sort       int
+}
+
+type EditDashboardReq struct {
+	List            []*AddDashboardListReq
+	BiDashboardId   int    `description:"看板id"`
+	BiDashboardName string `description:"看板名称"`
+}
+
+// update
+func EditDashboard(item *BiDashboard) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE bi_dashboard SET bi_dashboard_name=?,modify_time=?,state=? WHERE bi_dashboard_id=?`
+	_, err = o.Raw(sql, item.BiDashboardName, time.Now(),item.State, item.BiDashboardId).Exec()
+	return
+}
+
+type DelDashboardReq struct {
+	BiDashboardId int `description:"看板id"`
+}
+
+func GetDashboradByIds(dashboradIds []int) (list []*BiDashboard, err error) {
+
+	//err = global.DEFAULT_DmSQL.Table("bi_dashboard").Where("bi_dashboard_id IN ?", dashboradIds).Find(&list).Error
+
+	return
+}
+
+// GetAllGrantList 获取已经有权限的看板列表
+func GetAllGrantList(sysUserId int) (list []*BiDashboard, err error) {
+	sql := `SELECT a.* FROM bi_dashboard a JOIN bi_dashboard_grant b on a.bi_dashboard_id=b.bi_dashboard_id 
+ WHERE b.grant_admin_id=?`
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, sysUserId).QueryRows(&list)
+	return
+}
+
+func SaveDashboard(item *BiDashboard) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Insert(item)
+	return
+}
+
+
+// BiDashboardEditingReq 标记编辑中请求体
+type BiDashboardEditingReq struct {
+	BiDashboardId  int `description:"看板主键ID"`
+	Status int `description:"标记状态: 1-编辑中; 2-编辑完成"`
+}
+
+// GetAllMyShareList 获取我共享的看板
+func GetAllMyShareList(sysUserId int) (list []*BiDashboard, err error) {
+	sql := `SELECT a.* FROM bi_dashboard a JOIN bi_dashboard_grant b on a.bi_dashboard_id=b.bi_dashboard_id 
+WHERE a.sys_admin_id = ? GROUP BY a.bi_dashboard_id   `
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, sysUserId).QueryRows(&list)
+	return
+}
+
+// getByName
+func GetDashboardByName(name string,adminId int) (item *BiDashboard, err error) {
+	sql := `SELECT * FROM bi_dashboard WHERE bi_dashboard_name = ? and sys_admin_id =? limit 1`
+	o := orm.NewOrm()
+	err = o.Raw(sql, name, adminId).QueryRow(&item)
+	return
+}

+ 136 - 0
models/bi_dashboard/bi_dashboard_classify.go

@@ -0,0 +1,136 @@
+package bi_dashboard
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BiDashboardClassify struct {
+	BiDashboardClassifyId   int       `gorm:"primaryKey;autoIncrement;column:bi_dashboard_classify_id"` // bi看板分类id
+	BiDashboardClassifyName string    `gorm:"column:bi_dashboard_classify_name;size:255;not null" `     // 看板分类名称
+	Sort                    int       `gorm:"column:sort" `                                             // 排序字段
+	CreateTime              time.Time `gorm:"column:create_time" `                                      // 创建时间
+	ModifyTime              time.Time `gorm:"column:modify_time"`                                       // 更新时间
+}
+type BiDashboardClassifyItem struct {
+	BiDashboardClassifyId   int    // bi看板分类id
+	BiDashboardClassifyName string // 看板分类名称
+	Sort                    int    // 排序字段
+	CreateTime              string // 创建时间
+	ModifyTime              string // 更新时间
+}
+
+// tableName
+func (m *BiDashboardClassify) TableName() string {
+	return "bi_dashboard_classify"
+}
+
+// add
+func AddBiDashboardClassify(item *BiDashboardClassify) (lastId int64, err error) {
+	o := orm.NewOrm()
+	lastId, err = o.Insert(item)
+	return
+}
+
+// update
+func EditDashboardClassify(item *BiDashboardClassify) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Raw("UPDATE bi_dashboard_classify SET bi_dashboard_classify_name=?,sort=?,modify_time=? WHERE bi_dashboard_classify_id=?", item.BiDashboardClassifyName, item.Sort, item.ModifyTime, item.BiDashboardClassifyId).Exec()
+	return
+}
+
+type RespGroupList struct {
+	MyList    []*BiDashboard
+	OtherList []*RespOtherGroupListItem
+}
+
+type RespMyGroupListItem struct {
+	GroupId       int64  `description:"目录id"`
+	GroupName     string `description:"目录名称"`
+	AdminId       int    `description:"目录创建者账号ID"`
+	DashboardList []*BiDashboard
+}
+
+type RespOtherGroupListItem struct {
+	GroupId       int64  `description:"目录id"`
+	GroupName     string `description:"目录名称"`
+	AdminId       int    `description:"目录创建者账号ID"`
+	DashboardList []*BiDashboard
+}
+
+type RespGroupDashboardListItem struct {
+	GroupPptId    int64  `description:"目录和ppt绑定序号"`
+	PptId         int64  `description:"ppt ID"`
+	Title         string `description:"标题"`
+	AdminId       int    `description:"移动ppt到该目录的系统用户id"`
+	AdminRealName string `description:"系统用户名称"`
+	PptVersion    int8   `description:"是否ppt的旧版本;1:旧的,2:新的"`
+	IsSingleShare int8   `description:"是否是单个共享ppt,0未单个共享,1共享"`
+	PptxUrl       string `description:"pptx下载地址"`
+	ReportId      int    `description:"关联的报告ID"`
+	ReportCode    string `description:"关联的报告code"`
+	PptCreateTime string `description:"ppt创建时间"`
+	PptModifyTime string `description:"ppt修改时间"`
+	PublishTime   string `description:"发布时间"`
+	PptPage       int    `description:"PPT总页数"`
+	IsReceived    int8   `description:"是否收到的共享,0:不是,1:是"`
+	IsGrant       int8   `description:"是否分配了权限,0:不是,1:是"`
+	TitleSetting  string `description:"PPT标题设置"`
+}
+
+func GetBiDashboardClassifyAllList() (list []*BiDashboardClassify, err error) {
+	//err = global.DEFAULT_DmSQL.Select("*").Find(&list).Error
+	o := orm.NewOrm()
+	_, err = o.Raw("SELECT * FROM bi_dashboard_classify").QueryRows(&list)
+	return
+}
+
+func GetBiDashboardClassifyById(id int) (item *BiDashboardClassify, err error) {
+	//err = global.DEFAULT_DmSQL.Where("bi_dashboard_classify_id = ?", id).First(&item).Error
+	o := orm.NewOrm()
+	err = o.Raw("SELECT * FROM bi_dashboard_classify where bi_dashboard_classify_id=?", id).QueryRow(&item)
+	return
+}
+
+type AddDashboardClassifyReq struct {
+	ClassifyName string `description:"看板名称"`
+}
+
+type EditDashboardClassifyReq struct {
+	BiDashboardClassifyId int    `description:"看板id"`
+	ClassifyName          string `description:"看板名称"`
+}
+
+type DelDashboardClassifyReq struct {
+	BiDashboardClassifyId int `description:"看板id"`
+}
+
+// GetBiDashboardClassifyMaxSort 获取看板分类下最大的排序数
+func GetBiDashboardClassifyMaxSort() (sort int, err error) {
+	sql := `SELECT COALESCE(Max(sort), 0) AS sort FROM bi_dashboard_classify `
+	//err = global.DEFAULT_DmSQL.Raw(sql).First(&sort).Error
+	o := orm.NewOrm()
+	err = o.Raw(sql).QueryRow(&sort)
+	return
+}
+
+// del
+//func DelBiDashboardClassify(id int) (err error) {
+//	return global.DEFAULT_DmSQL.Where("bi_dashboard_classify_id = ?", id).Delete(&BiDashboardClassify{}).Error
+//}
+
+type RespPublicGroupListItem struct {
+	GroupId       int64  `description:"目录id"`
+	GroupName     string `description:"目录名称"`
+	AdminId       int    `description:"目录创建者账号ID"`
+	DashboardList []*BiDashboard
+	Children      []*RespPublicGroupListItem
+}
+
+// getByName
+func GetBiDashboardClassifyByName(classifyName string) (count int64, err error) {
+	//err = global.DEFAULT_DmSQL.Model(&BiDashboardClassify{}).Where("bi_dashboard_classify_name = ?", classifyName).Count(&count).Error
+	o := orm.NewOrm()
+	err = o.Raw("SELECT count(1) FROM bi_dashboard_classify where bi_dashboard_classify_name=?", classifyName).QueryRow(&count)
+	return
+}

+ 77 - 0
models/bi_dashboard/bi_dashboard_detail.go

@@ -0,0 +1,77 @@
+package bi_dashboard
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BiDashboardDetail struct {
+	BiDashboardDetailId int       `gorm:"primaryKey;autoIncrement;column:bi_dashboard_detail_id" ` // bi看板id
+	BiDashboardId       int       `gorm:"column:bi_dashboard_id" `                                 // 看板id
+	Type                int       `gorm:"column:type" `                                            // 1图表 2表格
+	UniqueCode          string    `gorm:"column:unique_code;size:32;not null" `                    // 报告唯一编码
+	Sort                int       `gorm:"column:sort" `                                            // 排序字段
+	CreateTime          time.Time `gorm:"column:create_time" `                                     // 创建时间
+	ModifyTime          time.Time `gorm:"column:modify_time" `                                     // 更新时间
+}
+
+// tableName
+func (m *BiDashboardDetail) TableName() string {
+	return "bi_dashboard_detail"
+}
+
+// add
+//func AddBiDashboardDetail(item *BiDashboardDetail) (err error) {
+	//err = global.DEFAULT_DmSQL.Create(item).Error
+	//return
+//}
+
+func GetBiDashboardDetailById(id int) (list []*BiDashboardDetail, err error) {
+	//err = global.DEFAULT_DmSQL.Table("bi_dashboard_detail").Where("bi_dashboard_id IN ?", id).Find(&list).Error
+	o := orm.NewOrm()
+	_, err = o.Raw("SELECT * FROM bi_dashboard_detail where bi_dashboard_id = ?", id).QueryRows(&list)
+	return
+}
+
+// multiAdd
+func AddBiDashboardDetailMulti(items []*BiDashboardDetail) (err error) {
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+// del
+func DeleteBiDashboardDetail(id int) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Raw("DELETE from bi_dashboard_detail where bi_dashboard_id=?", id).Exec()
+	return
+}
+
+type MoveDashboardDetailReq struct {
+	BiDashboardId       int `description:"看板id"`
+	BiDashboardDetailId int `description:"看板详情id"`
+	Sort                int `description:"排序"`
+	OtherDetailId       int `description:"交换的详情id"`
+	OtherSort           int `description:"交换的排序"`
+}
+
+// update
+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()
+	return
+}
+
+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
+}

+ 75 - 0
models/bi_dashboard/bi_dashboard_grant.go

@@ -0,0 +1,75 @@
+package bi_dashboard
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BiDashboardGrant struct {
+	GrantId       int       `gorm:"primaryKey;autoIncrement;column:grant_id"` // 授权id
+	BiDashboardId int       `gorm:"column:bi_dashboard_id" `                  // 看板id
+	GrantAdminId  int       `gorm:"column:grant_admin_id"`                    // 授权的用户id
+	CreateTime    time.Time `gorm:"column:create_time"`                       // 授权时间
+}
+
+// tableName
+func (m *BiDashboardGrant) TableName() string {
+	return "bi_dashboard_grant"
+}
+
+// GrantDashboardReq 分配看板权限
+type GrantDashboardReq struct {
+	BiDashboardId int    `description:"看板id" `
+	AdminIdStr    string `description:"指定成员id,多个成员用英文,隔开"`
+}
+
+// MultiAddDashboardGrant 批量添加授权记录
+func MultiAddDashboardGrant(boardId int, list []*BiDashboardGrant) (err error) {
+	o := orm.NewOrm()
+	to, err := o.Begin()
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := "DELETE from bi_dashboard_grant where bi_dashboard_id=?"
+	_, err = to.Raw(sql, boardId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 新增授权记录
+	if len(list) > 0 {
+		_, tmpErr := to.InsertMulti(len(list), list)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+
+	return
+}
+
+// PublicDashboardReq 设置公共看板权限
+type PublicDashboardReq struct {
+	BiDashboardId int `description:"看板id" `
+}
+
+// del
+func DeleteDashboardGrant(biDashboardId int) (err error) {
+	//return global.DEFAULT_DmSQL.Where("bi_dashboard_id=?", biDashboardId).Delete(&BiDashboardGrant{}).Error
+	o := orm.NewOrm()
+	_, err = o.Raw("DELETE from bi_dashboard_grant where bi_dashboard_id=?", biDashboardId).Exec()
+	return
+}
+
+// get
+func GetDashboardGrantInfo(biDashboardId int) (list []*BiDashboardGrant, err error) {
+	//return list, global.DEFAULT_DmSQL.Where("bi_dashboard_id=?", biDashboardId).Find(&list).Error
+	o := orm.NewOrm()
+	_, err = o.Raw("SELECT * FROM bi_dashboard_grant where bi_dashboard_id=?", biDashboardId).QueryRows(&list)
+	return
+}

+ 46 - 0
models/bi_dashboard/bi_dashboard_home_page.go

@@ -0,0 +1,46 @@
+package bi_dashboard
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type BiDashboardHomePage struct {
+	BiDashboardHomePageId int       `gorm:"primaryKey;autoIncrement;comment:'bi首页看板id'"`
+	BiDashboardId         int       `gorm:"type:int(10);default:null;comment:'看板id'"`
+	AdminId               int       `gorm:"type:int(10);default:null;"`
+	CreateTime            time.Time `gorm:"type:datetime;comment:'创建时间'"`
+	ModifyTime            time.Time `gorm:"type:datetime;comment:'更新时间'"`
+	FromType              int       `gorm:"type:int(10);default:null;comment:'来源,前端跳转用 1我的 2共享 3公共"`
+}
+
+// tableName
+func (m *BiDashboardHomePage) TableName() string {
+	return "bi_dashboard_home_page"
+}
+
+// get
+func GetBiDashboardHomePageById(id int) (item *BiDashboardHomePage, err error) {
+	sql := ` SELECT a.* FROM bi_dashboard_home_page AS a INNER JOIN bi_dashboard AS b 
+ON a.bi_dashboard_id = b.bi_dashboard_id WHERE a.admin_id = ? `
+	o := orm.NewOrm()
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// save
+func SaveBiDashboardHomePage(item *BiDashboardHomePage) (err error) {
+	//return global.DEFAULT_DmSQL.Save(item).Error
+	o := orm.NewOrm()
+	if item.BiDashboardHomePageId > 0 {
+		_, err = o.Raw("UPDATE bi_dashboard_home_page SET bi_dashboard_id=?,modify_time=? WHERE bi_dashboard_home_page_id=?", item.BiDashboardId, item.ModifyTime, item.BiDashboardHomePageId).Exec()
+	} else {
+		_, err = o.Insert(item)
+	}
+	return
+}
+
+type SaveHomePageReq struct {
+	BiDashboardId int `description:"看板id"`
+	FromType      int `description:"来源,前端跳转用 1我的 2共享 3公共"`
+}

+ 37 - 0
models/binlog/binlog.go

@@ -0,0 +1,37 @@
+package binlog
+
+import "github.com/beego/beego/v2/client/orm"
+
+// BinlogFormatStruct
+// @Description: 数据库的binlog格式
+type BinlogFormatStruct struct {
+	VariableName string `orm:"column(Variable_name)"`
+	Value        string `orm:"column(Value)"`
+}
+
+// GetBinlogFormat
+// @Description: 获取数据库的binlog格式
+// @return item
+// @return err
+func GetBinlogFormat() (item *BinlogFormatStruct, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SHOW VARIABLES LIKE 'binlog_format'`
+	err = o.Raw(sql).QueryRow(&item)
+	return
+}
+
+type BinlogFileStruct struct {
+	File     string `orm:"column(File)"`
+	Position uint32 `orm:"column(Position)"`
+}
+
+// GetShowMaster
+// @Description: 获取master的状态
+// @return item
+// @return err
+func GetShowMaster() (item *BinlogFileStruct, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `show master status`
+	err = o.Raw(sql).QueryRow(&item)
+	return
+}

+ 64 - 0
models/binlog/business_sys_interaction_log.go

@@ -0,0 +1,64 @@
+package binlog
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+// BusinessSysInteractionLog 商家系统交互记录表
+type BusinessSysInteractionLog struct {
+	ID             uint32    `orm:"column(id);pk"`
+	InteractionKey string    // 记录Key
+	InteractionVal string    // 记录值
+	Remark         string    // 备注
+	ModifyTime     time.Time // 修改日期
+	CreateTime     time.Time // 创建时间
+}
+
+// TableName get sql table name.获取数据库表名
+func (m *BusinessSysInteractionLog) TableName() string {
+	return "business_sys_interaction_log"
+}
+
+// BusinessSysInteractionLogColumns get sql column name.获取数据库列名
+var BusinessSysInteractionLogColumns = struct {
+	ID             string
+	InteractionKey string
+	InteractionVal string
+	Remark         string
+	ModifyTime     string
+	CreateTime     string
+}{
+	ID:             "id",
+	InteractionKey: "interaction_key",
+	InteractionVal: "interaction_val",
+	Remark:         "remark",
+	ModifyTime:     "modify_time",
+	CreateTime:     "create_time",
+}
+
+// Create 添加数据
+func (m *BusinessSysInteractionLog) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Insert(m)
+	return
+}
+
+// Update 更新数据
+func (m *BusinessSysInteractionLog) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+var BinlogFileNameKey = "binlog_edb_info_filename" // binlog文件名
+var BinlogPositionKey = "binlog_edb_info_position" // binlog位置
+
+// GetBusinessSysInteractionLogByKey 根据记录key获取数据
+func GetBusinessSysInteractionLogByKey(key string) (item *BusinessSysInteractionLog, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM business_sys_interaction_log WHERE interaction_key = ?"
+	err = o.Raw(sql, key).QueryRow(&item)
+	return
+}

+ 13 - 0
models/business_conf.go

@@ -9,6 +9,9 @@ import (
 	"time"
 )
 
+var (
+	BusinessConfMap map[string]string
+)
 const (
 	BusinessConfUseXf                     = "UseXf"
 	BusinessConfXfAppid                   = "XfAppid"
@@ -50,6 +53,8 @@ const (
 	BusinessConfSmsJhgjVariable              = "SmsJhgjVariable"              // 聚合国际短信变量
 
 	BusinessConfEdbStopRefreshRule = "EdbStopRefreshRule" // 是否停止指标刷新规则
+	BusinessConfReport2ImgUrl      = "Report2ImgUrl"      // 报告转长图地址(用于兼容内外网环境的)
+	BusinessConfReportViewUrl      = "ReportViewUrl"      // 报告详情地址
 )
 
 const (
@@ -253,3 +258,11 @@ func InitUseMongoConf() {
 		utils.UseMongo = true
 	}
 }
+
+func InitBusinessConf() {
+	var e error
+	BusinessConfMap, e = GetBusinessConf()
+	if e != nil {
+		return
+	}
+}

+ 60 - 1
models/classify.go

@@ -3,9 +3,10 @@ package models
 import (
 	"eta/eta_api/utils"
 	"fmt"
+	"time"
+
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
-	"time"
 )
 
 type Classify struct {
@@ -90,6 +91,55 @@ type ClassifyAddReq struct {
 	RelateVideo           int                    `description:"是否在路演视频中可选: 0-否; 1-是"`*/
 }
 
+func (c *Classify) Delete(childIds []int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	// 删除自身
+	_, err = tx.Delete(c)
+	if err != nil {
+		return
+	}
+	// 删除子分类
+	if len(childIds) > 0 {
+		sql := `DELETE FROM classify WHERE id IN (` + utils.GetOrmInReplace(len(childIds)) + `)`
+		_, err = tx.Raw(sql, childIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 检查是否需要更新父类
+	if c.ParentId > 0 {
+		var count int
+		sql := `SELECT COUNT(*) FROM classify WHERE parent_id=? `
+		err = tx.Raw(sql, c.ParentId).QueryRow(&count)
+		if err != nil {
+			return
+		}
+		if count == 0 {
+			sql = `UPDATE classify SET has_child=0 WHERE id=? `
+			_, err = tx.Raw(sql, c.ParentId).Exec()
+			if err != nil {
+				return
+			}
+		}
+	}
+
+	deleteImgSql := `DELETE FROM banner WHERE classify_id=? `
+	_, err = tx.Raw(deleteImgSql, c.Id).Exec()
+	return
+}
+
 func GetClassifyByName(classifyName string, parentId int) (item *Classify, err error) {
 	sql := `SELECT * FROM classify WHERE classify_name=? AND parent_id=? `
 	o := orm.NewOrmUsingDB("rddp")
@@ -216,6 +266,7 @@ type ClassifyList struct {
 	ChartPermissionIdList []int `description:"绑定的权限ID"`
 	Level                 int   `description:"层级"`
 	HasChild              int   `description:"是否有子级别,0:下面没有子分类,1:下面有子分类;默认:0"`
+	IsEnableDelete        int   `description:"是否允许删除: 0-否; 1-是"`
 }
 
 type ClassifyItem struct {
@@ -376,6 +427,14 @@ func GetAllClassify() (list []*Classify, err error) {
 	return
 }
 
+// GetAllClassifyWithDesc 获取所有倒序分类
+func GetAllClassifyWithDesc() (list []*Classify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM classify ORDER BY id DESC `
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
 // GetClassifyByKeyword 名称获取分类
 func GetClassifyByKeyword(keyword string) (item Classify, err error) {
 	o := orm.NewOrmUsingDB("rddp")

+ 97 - 0
models/data_manage/base_from_ccf.go

@@ -21,6 +21,7 @@ type BaseFromCCFIndex struct {
 
 type BaseFromCCFIndexList struct {
 	BaseFromCcfIndexId int `orm:"column(base_from_ccf_index_id);pk"`
+	EdbInfoId          int
 	ClassifyId         int
 	IndexCode          string
 	IndexName          string
@@ -29,6 +30,9 @@ type BaseFromCCFIndexList struct {
 	Sort               int
 	CreateTime         string
 	ModifyTime         string
+	EndDate            string
+	EndValue           string
+	EdbExist           int `description:"指标库是否已添加:0-否;1-是"`
 	DataList           []*BaseFromCCFData
 	Paging             *paging.PagingItem `description:"分页数据"`
 }
@@ -142,3 +146,96 @@ func GetBaseFromCCFIndexByIndexCode(indexCode string) (list *BaseFromCCFIndex, e
 	err = o.Raw(sql, indexCode).QueryRow(&list)
 	return
 }
+
+func GetCCFIndexPage(condition string, pars interface{}, startSize, pageSize int) (items []*BaseFromCCFIndexList, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM base_from_ccf_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY sort ASC, base_from_ccf_index_id asc LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetCCFIndexPageCount(condition string, pars interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(1) AS count  FROM base_from_ccf_index WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+type BaseFromCCFIndexSearchList struct {
+	List   []*BaseFromCCFIndexList
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type CCFIndexSource2EdbReq struct {
+	EdbCode       string
+	EdbName       string
+	Frequency     string
+	Unit          string
+	ClassifyId    int
+	AdminId       int
+	AdminRealName string
+}
+
+// BatchCheckCCFEdbReq 指标数据结构体
+type BatchCheckCCFEdbReq struct {
+	//IsJoinEdb      int      `form:"IsJoinEdb" description:"是否加到指标库,0:未加到指标库"`
+	Frequencies   string `description:"频度;枚举值:日度、周度、月度、季度、半年度、年度"`
+	Keyword       string `description:"关键字"`
+	ClassifyIds   string `description:"所选品种id列表"`
+	ListAll       bool   `form:"ListAll" json:"ListAll" description:"列表全选"`
+	TradeCodeList string `form:"TradeCodeList" json:"TradeCodeList" description:"全选为false时, 该数组为选中; 全选为true时, 该数组为不选的指标"`
+}
+
+func GetCCFFrequencyByClassifyId(classifyId int) (items []*GlFrequency, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT frequency FROM base_from_ccf_index WHERE classify_id = ? `
+	sql += ` GROUP BY frequency ORDER BY frequency ASC `
+	_, err = o.Raw(sql, classifyId).QueryRows(&items)
+	return
+}
+
+func GetCCFIndexDataByDataTime(indexCodes []string, startDate, endDate string) (items []*BaseFromCCFData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_ccf_data WHERE  index_code in (` + utils.GetOrmInReplace(len(indexCodes)) + `) and data_time >=? and data_time <? ORDER BY data_time DESC `
+	_, err = o.Raw(sql, indexCodes, startDate, endDate).QueryRows(&items)
+	return
+}
+
+func GetCCFIndexDataTimePageByCodes(indexCodes []string, startSize, pageSize int) (dataTimes []string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT data_time FROM base_from_ccf_data WHERE index_code in (` + utils.GetOrmInReplace(len(indexCodes)) + `) GROUP BY data_time ORDER BY data_time DESC LIMIT ?,? `
+	_, err = o.Raw(sql, indexCodes, startSize, pageSize).QueryRows(&dataTimes)
+	return
+}
+
+func GetCCFIndexDataTimePageCount(indexCodes []string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT COUNT(DISTINCT data_time) AS count  FROM base_from_ccf_data WHERE index_code in (` + utils.GetOrmInReplace(len(indexCodes)) + `)`
+	err = o.Raw(sql, indexCodes).QueryRow(&count)
+	return
+}
+
+// GetCCFDataDataTimeByIndexId 根据指标id获取指标数据的日期列表
+func GetCCFDataDataTimeByIndexId(indexIdList []int) (items []string, err error) {
+	if len(indexIdList) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT DISTINCT data_time FROM base_from_ccf_data WHERE base_from_ccf_index_id IN (` + utils.GetOrmInReplace(len(indexIdList)) + `) ORDER BY data_time DESC`
+	_, err = o.Raw(sql, indexIdList).QueryRows(&items)
+	return
+}
+
+func GetCCFIndexDataByIndexIdAndDataTime(indexId []int, dataTimeList []string) (items []*BaseFromCCFData, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *  FROM base_from_ccf_data WHERE  base_from_ccf_index_id in (` + utils.GetOrmInReplace(len(indexId)) + `) and data_time in (` + utils.GetOrmInReplace(len(dataTimeList)) + `)  `
+	_, err = o.Raw(sql, indexId, dataTimeList).QueryRows(&items)
+	return
+}

+ 2 - 0
models/data_manage/base_from_sci.go

@@ -65,6 +65,8 @@ type BaseFromSciIndex struct {
 	Sort               int
 	CreateTime         time.Time
 	ModifyTime         time.Time
+	FilePath           string
+	TerminalCode       string `description:"终端编码"`
 }
 
 func AddBaseFromSciIndex(item *BaseFromSciIndex) (lastId int64, err error) {

+ 8 - 6
models/data_manage/base_from_smm.go

@@ -77,6 +77,8 @@ type BaseFromSmmIndex struct {
 	ReleaseTime        string
 	StartDate          string
 	EndDate            string
+	RenameFileName     string
+	TerminalCode       string `description:"终端编码"`
 }
 
 func AddBaseFromSmmIndex(item *BaseFromSmmIndex) (lastId int64, err error) {
@@ -440,10 +442,10 @@ type SmmIndexListReq struct {
 
 // SmmIndexExistCheckReq
 type SmmIndexExistCheckReq struct {
-	Types      []string `description:"分类"`
-	Frequency  string   `description:"频度"`
-	DataState  string   `description:"数据状态"`
-	EdbCode    string   `description:"指标代码"`
-	SelectAll  bool     `description:"是否全选"`
-	Keyword    string   `description:"关键字"`
+	Types     []string `description:"分类"`
+	Frequency string   `description:"频度"`
+	DataState string   `description:"数据状态"`
+	EdbCode   string   `description:"指标代码"`
+	SelectAll bool     `description:"是否全选"`
+	Keyword   string   `description:"关键字"`
 }

+ 42 - 6
models/data_manage/chart_classify.go

@@ -3,8 +3,9 @@ package data_manage
 import (
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 type ChartClassify struct {
@@ -466,6 +467,25 @@ func GetChartClassifyAllBySource(source int) (items []*ChartClassifyItems, err e
 	return
 }
 
+// GetChartClassifyIdListByAdminId
+// @Description: 根据用户id和指标类型获取其关联的所有指标分类id列表
+// @author: Roc
+// @datetime 2024-09-11 15:52:48
+// @param adminId int
+// @param source int
+// @return chartClassifyIdList []int
+// @return err error
+func GetChartClassifyIdListByAdminId(adminId, source int) (chartClassifyIdList []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT chart_classify_id FROM chart_info WHERE sys_user_id = ? AND source = ?`
+
+	pars := []interface{}{adminId, source}
+	sql += ` group by chart_classify_id `
+	_, err = o.Raw(sql, pars).QueryRows(&chartClassifyIdList)
+
+	return
+}
+
 // GetChartClassifyAndInfoByParentId
 func GetChartClassifyAndInfoByParentId(parentId int) (items []*ChartClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -481,7 +501,15 @@ func GetChartClassifyAndInfoByParentId(parentId int) (items []*ChartClassifyItem
 	sys_user_real_name,
 	sort,
 	level,
-	unique_code
+	unique_code,
+	source,
+	0 as date_type,
+	'' as start_date,
+	'' as end_date,
+	0 as chart_type,
+	'' as calendar,
+	'' as season_start_date,
+	'' as season_end_date
 FROM
 	chart_classify 
 WHERE
@@ -498,7 +526,15 @@ SELECT
 	sys_user_real_name,
 	sort,
 	0 AS level,
-	unique_code
+	unique_code,
+	source,
+	date_type,
+	start_date,
+	end_date,
+	chart_type,
+	calendar,
+	season_start_date,
+	season_end_date
 FROM
 	chart_info 
 WHERE
@@ -546,7 +582,7 @@ SELECT
 FROM
 	chart_info 
 WHERE
-	chart_classify_id = ? AND chart_type = 1 AND sys_user_id = ?
+	chart_classify_id = ? AND sys_user_id = ?
 ORDER BY
 	sort ASC,
 	chart_classify_id ASC`
@@ -566,6 +602,6 @@ func GetChartClassifiesById(chartClassifyId int) (items []*ChartClassifyItems, e
         FROM chart_classify
         WHERE parent_id = ?
     );`
-	_,err = o.Raw(sql, chartClassifyId, chartClassifyId, chartClassifyId).QueryRows(&items)
+	_, err = o.Raw(sql, chartClassifyId, chartClassifyId, chartClassifyId).QueryRows(&items)
 	return
-}
+}

+ 19 - 7
models/data_manage/chart_info.go

@@ -5,12 +5,13 @@ import (
 	"eta/eta_api/models/mgo"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"go.mongodb.org/mongo-driver/bson"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"go.mongodb.org/mongo-driver/bson"
 )
 
 type ChartInfo struct {
@@ -2172,10 +2173,12 @@ type BarChartInfoReq struct {
 }
 
 type FutureGoodBarChartInfoReq struct {
-	EdbInfoIdList []BarChartInfoEdbItemReq `description:"指标信息"`
-	DateList      []BarChartInfoDateReq    `description:"日期配置"`
-	XDataList     []XData                  `description:"横轴配置"`
-	BaseEdbInfoId int                      `description:"日期基准指标id"`
+	EdbInfoIdList       []BarChartInfoEdbItemReq `description:"指标信息"`
+	DateList            []BarChartInfoDateReq    `description:"日期配置"`
+	XDataList           []XData                  `description:"横轴配置"`
+	BaseEdbInfoId       int                      `description:"日期基准指标id"`
+	FutureGoodEdbName   string                   `description:"期货名称"`
+	FutureGoodEdbNameEn string                   `description:"期货英文名称"`
 }
 
 // BarChartInfoEdbItemReq 柱方图预览请求数据(指标相关)
@@ -2788,6 +2791,15 @@ func GetChartInfoBySourceAndParentId(source, parentId, adminId int) (items []*Ch
 	return
 }
 
+func GetChartInfoBySourceAndAdminId(source, adminId int) (items []*ChartClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT chart_info_id,chart_classify_id,chart_name AS chart_classify_name,chart_name_en AS chart_classify_name_en,
+             unique_code,sys_user_id,sys_user_real_name,date_type,start_date,end_date,chart_type,calendar,season_start_date,season_end_date,source
+            FROM chart_info WHERE source = ? AND sys_user_id = ? ORDER BY sort asc,chart_info_id ASC `
+	_, err = o.Raw(sql, source, adminId).QueryRows(&items)
+	return
+}
+
 // PreviewSeasonChartReq 预览季节性图的请求入参
 type PreviewSeasonChartReq struct {
 	ChartEdbInfoList  []*ChartSaveItem `description:"指标及配置信息"`

+ 9 - 0
models/data_manage/edb_info.go

@@ -513,6 +513,9 @@ func GetEdbDataCountByCondition(condition string, pars []interface{}, source, su
 func GetEdbDataListByCondition(condition string, pars []interface{}, source, subSource, pageSize, startSize int) (item []*EdbData, err error) {
 	o := orm.NewOrmUsingDB("data")
 	tableName := GetEdbDataTableName(source, subSource)
+	if source == utils.DATA_SOURCE_PREDICT {
+		tableName = "edb_data_predict_base"
+	}
 	sql := ` SELECT * FROM %s WHERE 1=1 `
 	sql = fmt.Sprintf(sql, tableName)
 
@@ -2114,3 +2117,9 @@ func getThsHfAllDataByMongo(edbInfoId, source, subSource int, startDataTime stri
 
 	return
 }
+
+type EdbNameCheckResult struct {
+	EdbCode string
+	EdbName string
+	Exist   bool
+}

+ 8 - 0
models/data_manage/edb_terminal.go

@@ -148,3 +148,11 @@ func GetEdbCountGroupByTerminal(source int) (list []TerminalCodeCountGroup, err
 	_, err = o.Raw(sql, source).QueryRows(&list)
 	return
 }
+
+// EdbTerminalDirInfo 指标终端文件夹信息
+type EdbTerminalDirInfo struct {
+	Name         string `description:"终端名称"`
+	TerminalCode string `description:"终端编码,用于配置在机器上"`
+	DirPath      string `description:"终端存放的文件夹路径"`
+	FilePath     string `description:"文件夹路径"`
+}

+ 4 - 2
models/data_manage/excel/request/mixed_table.go

@@ -136,10 +136,12 @@ type MixCellShowStyle struct {
 	Pn              int         `description:"小数点位数增加或减少,正数表述增加,负数表示减少" json:"pn"`
 	Nt              string      `description:"变换类型:number 小数点位数改变,percent百分比," json:"nt"`
 	GlObj           interface{} `description:"公式对象:1:数值,2:百分比,3:文本" json:"glObj"`
-	Decimal         *int        `description:"小数点位数"`
-	Last            string      `description:"起始操作:nt|decimal"`
+	Width           float64     `description:"单元格宽度" json:"width"`
+	Decimal         *int        `description:"小数点位数" json:"decimal"`
+	Last            string      `description:"起始操作:nt|decimal" json:"last"`
 	Color           string      `description:"颜色值,#RRG" json:"color"`
 	BackgroundColor string      `description:"背景颜色值,#RRG" json:"background-color"`
+	Align           string      `description:"对齐方式:left|center|right" json:"align"`
 }
 
 type DateDataBeforeAfterReq struct {

+ 2 - 0
models/data_manage/excel/response/excel_info.go

@@ -31,6 +31,8 @@ type ExcelTableDetailResp struct {
 	SourcesFrom   string `description:"图表来源"`
 	ExcelSource   string `description:"表格来源str"`
 	ExcelSourceEn string `description:"表格来源(英文)"`
+	ExcelInfoId   int    `description:"表id"`
+	Source        int    `description:"表格来源"`
 }
 
 // ExcelTableDetailConfigResp

+ 12 - 0
models/data_manage/mysteel_chemical_index.go

@@ -30,6 +30,7 @@ type BaseFromMysteelChemicalIndex struct {
 	ModifyTime                        time.Time `description:"修改时间"`
 	CreateTime                        time.Time `description:"创建时间"`
 	Sort                              int       `description:"排序字段"`
+	FilePath                          string    `description:"文件"`
 	MergeFilePath                     string    `description:"合并文件"`
 	TerminalCode                      string    `description:"终端编码"`
 	IsStop                            int       `description:"是否停更:1:停更,0:未停更"`
@@ -316,6 +317,17 @@ func GetBaseFromMysteelChemicalDataMaxCount(classifyId int) (count int, err erro
 	return
 }
 
+// GetBaseFromMysteelChemicalDataTimeByIndexId 根据指标id获取指标数据的日期列表
+func GetBaseFromMysteelChemicalDataTimeByIndexId(indexIdList []int) (items []string, err error) {
+	if len(indexIdList) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT DISTINCT data_time FROM base_from_mysteel_chemical_data WHERE base_from_mysteel_chemical_index_id IN (` + utils.GetOrmInReplace(len(indexIdList)) + `) ORDER BY data_time DESC`
+	_, err = o.Raw(sql, indexIdList).QueryRows(&items)
+	return
+}
+
 // GetMysteelChemicalIndexDataByCode 通过钢联化工指标code获取所有数据列表
 func GetMysteelChemicalIndexDataByCode(indexCode string) (items []*MysteelChemicalData, err error) {
 	sql := ` SELECT * FROM (

+ 90 - 12
models/data_manage/trade_analysis/trade_analysis.go

@@ -182,6 +182,45 @@ func GetTradeDataByClassifyAndCompany(exchange, classifyName string, contracts,
 	if len(contracts) == 0 || len(companies) == 0 {
 		return
 	}
+	condBuy := fmt.Sprintf(`classify_name = ? AND classify_type IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+	parsBuy := make([]interface{}, 0)
+	parsBuy = append(parsBuy, classifyName, contracts)
+
+	condSold := fmt.Sprintf(`classify_name = ? AND classify_type IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+	parsSold := make([]interface{}, 0)
+	parsSold = append(parsSold, classifyName, contracts)
+
+	// 是否含有TOP20
+	var hasTop bool
+	var condCompanies []string
+	for _, v := range companies {
+		if v == TradeFuturesCompanyTop20 {
+			hasTop = true
+			continue
+		}
+		condCompanies = append(condCompanies, v)
+	}
+	if !hasTop {
+		if len(condCompanies) == 0 {
+			err = fmt.Errorf("查询条件-期货公司异常")
+			return
+		}
+		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+		parsBuy = append(parsBuy, condCompanies)
+		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+		parsSold = append(parsSold, condCompanies)
+	} else {
+		if len(condCompanies) > 0 {
+			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+			parsBuy = append(parsBuy, condCompanies)
+			parsSold = append(parsSold, condCompanies)
+		} else {
+			condBuy += ` AND rank = 999`
+			condSold += ` AND rank = 999`
+		}
+	}
+
 	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
 	sql := `SELECT
 			rank,
@@ -195,7 +234,7 @@ func GetTradeDataByClassifyAndCompany(exchange, classifyName string, contracts,
 		FROM
 			%s 
 		WHERE
-			classify_name = ? AND classify_type IN (%s) AND buy_short_name IN (%s)
+			%s
 		UNION ALL
 		(
 		SELECT
@@ -210,11 +249,11 @@ func GetTradeDataByClassifyAndCompany(exchange, classifyName string, contracts,
 		FROM
 			%s 
 		WHERE
-			classify_name = ? AND classify_type IN (%s) AND sold_short_name IN (%s)
+			%s
 		)`
-	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(contracts)), utils.GetOrmInReplace(len(companies)), tableName, utils.GetOrmInReplace(len(contracts)), utils.GetOrmInReplace(len(companies)))
+	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
 	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, classifyName, contracts, companies, classifyName, contracts, companies).QueryRows(&items)
+	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
 	return
 }
 
@@ -227,6 +266,45 @@ func GetTradeZhengzhouDataByClassifyAndCompany(exchange string, contracts, compa
 	if len(contracts) == 0 || len(companies) == 0 {
 		return
 	}
+	condBuy := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+	parsBuy := make([]interface{}, 0)
+	parsBuy = append(parsBuy, contracts)
+
+	condSold := fmt.Sprintf(`classify_name IN (%s)`, utils.GetOrmInReplace(len(contracts)))
+	parsSold := make([]interface{}, 0)
+	parsSold = append(parsSold, contracts)
+
+	// 是否含有TOP20
+	var hasTop bool
+	var condCompanies []string
+	for _, v := range companies {
+		if v == TradeFuturesCompanyTop20 {
+			hasTop = true
+			continue
+		}
+		condCompanies = append(condCompanies, v)
+	}
+	if !hasTop {
+		if len(condCompanies) == 0 {
+			err = fmt.Errorf("查询条件-期货公司异常")
+			return
+		}
+		condBuy += fmt.Sprintf(` AND buy_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+		parsBuy = append(parsBuy, condCompanies)
+		condSold += fmt.Sprintf(` AND sold_short_name IN (%s)`, utils.GetOrmInReplace(len(condCompanies)))
+		parsSold = append(parsSold, condCompanies)
+	} else {
+		if len(condCompanies) > 0 {
+			condBuy += fmt.Sprintf(` AND (rank = 999 OR buy_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+			condSold += fmt.Sprintf(` AND (rank = 999 OR sold_short_name IN (%s))`, utils.GetOrmInReplace(len(condCompanies)))
+			parsBuy = append(parsBuy, condCompanies)
+			parsSold = append(parsSold, condCompanies)
+		} else {
+			condBuy += ` AND rank = 999`
+			condSold += ` AND rank = 999`
+		}
+	}
+
 	tableName := fmt.Sprintf("base_from_trade_%s_index", exchange)
 	sql := `SELECT
 			rank,
@@ -239,7 +317,7 @@ func GetTradeZhengzhouDataByClassifyAndCompany(exchange string, contracts, compa
 		FROM
 			%s 
 		WHERE
-			classify_name IN (%s) AND buy_short_name IN (%s)
+			%s
 		UNION ALL
 		(
 		SELECT
@@ -253,11 +331,11 @@ func GetTradeZhengzhouDataByClassifyAndCompany(exchange string, contracts, compa
 		FROM
 			%s 
 		WHERE
-			classify_name IN (%s) AND sold_short_name IN (%s)
+			%s
 		)`
-	sql = fmt.Sprintf(sql, tableName, utils.GetOrmInReplace(len(contracts)), utils.GetOrmInReplace(len(companies)), tableName, utils.GetOrmInReplace(len(contracts)), utils.GetOrmInReplace(len(companies)))
+	sql = fmt.Sprintf(sql, tableName, condBuy, tableName, condSold)
 	o := orm.NewOrmUsingDB("data")
-	_, err = o.Raw(sql, contracts, companies, contracts, companies).QueryRows(&items)
+	_, err = o.Raw(sql, parsBuy, parsSold).QueryRows(&items)
 	return
 }
 
@@ -283,10 +361,10 @@ const (
 	WarehouseDefaultFrequency = "日度"
 
 	GuangZhouTopCompanyAliasName = "日成交持仓排名" // 广期所TOP20对应的公司名称
-	GuangZhouSeatNameBuy         = "持买单量"    // 广期所指标名称中的多单名称
-	GuangZhouSeatNameSold        = "持卖单量"    // 广期所指标名称中的空单名称
-	GuangZhouTopSeatNameBuy      = "持买单量总计"  // 广期所指标名称中的TOP20多单名称
-	GuangZhouTopSeatNameSold     = "持卖单量总计"  // 广期所指标名称中的TOP20空单名称
+	GuangZhouSeatNameBuy         = "持买单量"       // 广期所指标名称中的多单名称
+	GuangZhouSeatNameSold        = "持卖单量"       // 广期所指标名称中的空单名称
+	GuangZhouTopSeatNameBuy      = "持买单量总计"   // 广期所指标名称中的TOP20多单名称
+	GuangZhouTopSeatNameSold     = "持卖单量总计"   // 广期所指标名称中的TOP20空单名称
 )
 
 const (

+ 46 - 0
models/db.go

@@ -3,6 +3,8 @@ package models
 import (
 	"eta/eta_api/models/ai_summary"
 	"eta/eta_api/models/aimod"
+	"eta/eta_api/models/bi_dashboard"
+	binlogDao "eta/eta_api/models/binlog"
 	"eta/eta_api/models/company"
 	"eta/eta_api/models/data_manage"
 	"eta/eta_api/models/data_manage/chart_theme"
@@ -14,6 +16,7 @@ import (
 	"eta/eta_api/models/data_manage/stl"
 	"eta/eta_api/models/data_manage/supply_analysis"
 	"eta/eta_api/models/data_stat"
+	edbmonitor "eta/eta_api/models/edb_monitor"
 	"eta/eta_api/models/eta_trial"
 	"eta/eta_api/models/fe_calendar"
 	"eta/eta_api/models/ppt_english"
@@ -25,6 +28,7 @@ import (
 	"eta/eta_api/models/speech_recognition"
 	"eta/eta_api/models/system"
 	"eta/eta_api/models/yb"
+	binlogSvr "eta/eta_api/services/binlog"
 	"eta/eta_api/utils"
 	"time"
 
@@ -208,8 +212,22 @@ func init() {
 	// 初始化STL指标系列
 	initStlEdbInfo()
 
+	// 初始化STL指标系列
+	initStlEdbInfo()
+
+	// 初始化指标监控
+	initEdbMonitor()
+	
+	// 开启mysql binlog监听
+	if utils.MYSQL_DATA_BINLOG_URL != "" {
+		initBinlog()
+		go binlogSvr.ListenMysql()
+	}
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	afterInitTable()
+
+	// 智能看板
+	initBiDashBoard()
 }
 
 // initSystem 系统表 数据表
@@ -648,6 +666,31 @@ func initStlEdbInfo() {
 	)
 }
 
+// 预警管理
+func initEdbMonitor() {
+	orm.RegisterModel(
+		new(edbmonitor.EdbMonitorInfo),     // 预警管理表
+		new(edbmonitor.EdbMonitorClassify), // 预警管理分类表
+		new(edbmonitor.EdbMonitorMessage),  // 预警管理消息表
+	)
+}
+
+func initBinlog() {
+	orm.RegisterModel(
+		new(binlogDao.BusinessSysInteractionLog), // binlog表
+	)
+}
+
+// initBiDashBoard 智能看板
+func initBiDashBoard() {
+	orm.RegisterModel(
+		new(bi_dashboard.BiDashboard),
+		new(bi_dashboard.BiDashboardDetail),
+		new(bi_dashboard.BiDashboardGrant),
+		new(bi_dashboard.BiDashboardHomePage),
+	)
+}
+
 // afterInitTable
 // @Description: 初始化表结构的的后置操作
 // @author: Roc
@@ -658,4 +701,7 @@ func afterInitTable() {
 
 	// 初始化是否启用mongo配置
 	InitUseMongoConf()
+
+	// 初始化商家基本配置
+	InitBusinessConf()
 }

+ 5 - 2
models/document_manage_model/outside_report.go

@@ -52,7 +52,7 @@ func init() {
 // GetOutsideReportListByConditionCount 根据条件查询列表条数
 func GetOutsideReportListByConditionCount(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `select count(distinct t1.outside_report_id) from outside_report t1 left join chart_permission_search_key_word_mapping t2 on t1.classify_id = t2.classify_id  where 1 = 1 `
+	sql := `select count(DISTINCT t1.outside_report_id) from outside_report t1 left join chart_permission_search_key_word_mapping t2 on t1.classify_id = t2.classify_id  where 1 = 1 `
 	sql += condition
 	err = o.Raw(sql, pars).QueryRow(&count)
 	if err != nil {
@@ -65,7 +65,10 @@ func GetOutsideReportListByConditionCount(condition string, pars []interface{})
 // GetOutsideReportListByCondition 根据条件查询列表
 func GetOutsideReportListByCondition(condition string, pars []interface{}, currentIndex int, pageSize int) (list []OutsideReport, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `select distinct t1.* from outside_report t1 left join chart_permission_search_key_word_mapping t2 on t1.classify_id = t2.classify_id  where 1 = 1 `
+	sql := `select DISTINCT t1.outside_report_id, t1.source, t1.title, t1.abstract, t1.classify_id, 
+t1.classify_name, t1.sys_user_id, t1.sys_user_name, t1.email_message_uid, t1.report_update_time, 
+t1.modify_time, t1.create_time, t1.report_code from outside_report t1 
+left join chart_permission_search_key_word_mapping t2 on t1.classify_id = t2.classify_id  where 1 = 1 `
 	sql += condition
 	sql += ` limit ?, ?`
 	_, err = o.Raw(sql, pars, (currentIndex-1)*pageSize, pageSize).QueryRows(&list)

+ 129 - 0
models/edb_monitor/edb_monitor.go

@@ -0,0 +1,129 @@
+package edbmonitor
+
+import (
+	"eta/eta_api/utils"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type EdbMonitorInfo struct {
+	EdbMonitorId         int       `orm:"column(edb_monitor_id);pk"`
+	EdbMonitorClassifyId int       `description:"预警分类id"`
+	EdbMonitorName       string    `description:"预警名称"`
+	EdbInfoId            int       `description:"指标id"`
+	EdbInfoType          int       `description:"指标类型"`
+	EdbUniqueCode        string    `description:"指标唯一标识"`
+	EdbClassifyId        int       `description:"指标id"`
+	EdbCode              string    `description:"指标编码"`
+	Source               int       `description:"指标来源"`
+	SubSource            int       `description:"指标子来源: 0-经济数据库;1-日期序列;2-高频数据"`
+	EdbLatestDate        string    `description:"最新日期"`
+	EdbLatestValue       float64   `description:"指标最新值"`
+	MonitorType          int       `description:"突破方式: 0-向上突破;1-向下突破"`
+	MonitorData          float64   `description:"预警值"`
+	MonitorLevel         string    `description:"预警等级"`
+	State                int       `description:"预警状态: 0-已关闭;1-未触发;2-已触发"`
+	EdbTriggerDate       time.Time `description:"触发日期"`
+	MonitorTriggerTime   time.Time `description:"预警触发时间"`
+	CreateUserId         int       `description:"创建人id"`
+	CreateTime           time.Time `description:"创建时间"`
+	ModifyTime           time.Time `description:"修改时间"`
+}
+
+func (m *EdbMonitorInfo) Insert() (int64, error) {
+	o := orm.NewOrmUsingDB("data")
+	return o.Insert(m)
+}
+
+func (m *EdbMonitorInfo) Update(cols []string) (err error) {
+	if len(cols) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func GetEdbMonitorLevelList() (list []string, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT DISTINCT monitor_level FROM edb_monitor_info`
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
+func GetEdbMonitorEdbInfoList() (items []*EdbMonitorInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_monitor_info WHERE state <> 0`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+func DeleteEdbMonitorInfoById(id int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `DELETE FROM edb_monitor_info WHERE edb_monitor_id =?`
+	_, err = o.Raw(sql, id).Exec()
+	return
+}
+
+func DeleteEdbMonitorInfoByIdList(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `DELETE FROM edb_monitor_info WHERE edb_monitor_id IN(` + utils.GetOrmInReplace(len(ids)) + `)`
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func GetEdbMonitorInfoById(id int) (item *EdbMonitorInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_monitor_info WHERE edb_monitor_id =?`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetEdbMonitorInfoByEdbInfoId(edbInfoId int) (items []*EdbMonitorInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_monitor_info WHERE edb_info_id =?`
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
+	return
+}
+
+func GetEdbMonitorInfoCountByClassifyId(classifyId []int) (count int, err error) {
+	if len(classifyId) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(*) AS count FROM edb_monitor_info WHERE edb_monitor_classify_id IN(` + utils.GetOrmInReplace(len(classifyId)) + `)`
+	err = o.Raw(sql, classifyId).QueryRow(&count)
+	return
+}
+
+func GetEdbMonitorInfoCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(*) AS count FROM edb_monitor_info WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func GetEdbMonitorInfoPageByCondition(condition string, pars []interface{}, startSize int, pageSize int) (items []*EdbMonitorInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_monitor_info WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	sql += ` ORDER BY create_time DESC LIMIT?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+func GetEdbMonitorCreateUserId() (userIds []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT DISTINCT create_user_id FROM edb_monitor_info`
+	_, err = o.Raw(sql).QueryRows(&userIds)
+	return
+}

+ 191 - 0
models/edb_monitor/edb_monitor_classify.go

@@ -0,0 +1,191 @@
+package edbmonitor
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type EdbMonitorClassify struct {
+	ClassifyId   int       `orm:"column(classify_id);pk"`
+	ClassifyName string    `description:"分类名称"`
+	Level        int       `description:"分类层级"`
+	ParentId     int       `description:"父分类ID"`
+	RootId       int       `description:"根分类ID"`
+	Sort         int       `description:"排序"`
+	CreateTime   time.Time `description:"创建时间"`
+}
+
+func (e *EdbMonitorClassify) Insert() (id int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+
+	var edbMonitorIds []int
+	if e.ParentId != 0 {
+		sql := `SELECT edb_monitor_id FROM edb_monitor_info WHERE edb_monitor_classify_id = ?`
+		_, err = o.Raw(sql, e.ParentId).QueryRows(&edbMonitorIds)
+		if err != nil {
+			return
+		}
+	}
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+
+	id, err = tx.Insert(e)
+	if len(edbMonitorIds) > 0 {
+		sql := `UPDATE edb_monitor_info SET edb_monitor_classify_id = ? WHERE edb_monitor_id IN (` + utils.GetOrmInReplace(len(edbMonitorIds)) + `)`
+		_, err = tx.Raw(sql, id, edbMonitorIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func (e *EdbMonitorClassify) Update(cols []string, classifyId []int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	var edbMonitorIds []int
+	if e.ParentId != 0 {
+		sql := `SELECT edb_monitor_id FROM edb_monitor_info WHERE edb_monitor_classify_id = ?`
+		_, err = o.Raw(sql, e.ParentId).QueryRows(&edbMonitorIds)
+		if err != nil {
+			return
+		}
+	}
+
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	_, err = tx.Update(e, cols...)
+	if err != nil {
+		return
+	}
+	if len(classifyId) > 0 {
+		sql := `UPDATE edb_monitor_classify SET root_id = ? WHERE classify_id IN (` + utils.GetOrmInReplace(len(classifyId)) + `)`
+		_, err = tx.Raw(sql, e.RootId, classifyId).Exec()
+		if err != nil {
+			return
+		}
+	}
+	if len(edbMonitorIds) > 0 {
+		sql := `UPDATE edb_monitor_info SET edb_monitor_classify_id = ? WHERE edb_monitor_id IN (` + utils.GetOrmInReplace(len(edbMonitorIds)) + `)`
+		_, err = tx.Raw(sql, e.ClassifyId, edbMonitorIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func DeleteEdbMonitorClassifyById(id int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Raw("DELETE FROM edb_monitor_classify WHERE classify_id =?", id).Exec()
+	return
+}
+
+func DeleteEdbMonitorClassifyByIdList(ids []int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := "DELETE FROM edb_monitor_classify WHERE classify_id IN (" + utils.GetOrmInReplace(len(ids)) + ")"
+	_, err = o.Raw(sql, ids).Exec()
+	return
+}
+
+func GetEdbMonitorClassifyList() (items []*EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_classify ORDER BY sort ASC"
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
+func GetEdbMonitorClassifyById(id int) (item *EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_classify WHERE classify_id =?"
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetEdbMonitorClassifyMaxSortByParentId(parentId int) (sort int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT MAX(sort) FROM edb_monitor_classify WHERE parent_id =?"
+	err = o.Raw(sql, parentId).QueryRow(&sort)
+	return
+}
+
+func GetChildEdbMonitorClassifyIdById(id int) (classifyId []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT classify_id FROM edb_monitor_classify WHERE parent_id =?"
+	_, err = o.Raw(sql, id).QueryRows(&classifyId)
+	return
+}
+
+func GetChildEdbMonitorClassifyById(id int) (items []*EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_classify WHERE parent_id =?"
+	_, err = o.Raw(sql, id).QueryRows(&items)
+	return
+}
+
+func GetChildEdbMonitorClassifyByRootId(rootId int) (items []*EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_classify WHERE root_id =?"
+	_, err = o.Raw(sql, rootId).QueryRows(&items)
+	return
+}
+
+func GetEdbMonitorClassifyCountByIdList(ids []int) (count int, err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT COUNT(*) FROM edb_monitor_classify WHERE classify_id IN (` + utils.GetOrmInReplace(len(ids)) + `)`
+	err = o.Raw(sql, ids).QueryRow(&count)
+	return
+}
+
+// GetEdbMonitorClassifyByParentIdAndName 根据父级ID和名称获取分类
+func GetEdbMonitorClassifyByParentIdAndName(parentId int, classifyName string, classifyId int) (item *EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM edb_monitor_classify WHERE parent_id = ? AND classify_name = ? AND classify_id <> ? LIMIT 1`
+	err = o.Raw(sql, parentId, classifyName, classifyId).QueryRow(&item)
+	return
+}
+
+// UpdateEdbMonitorClassifySortByParentId 根据分类父类id更新排序
+func UpdateEdbMonitorClassifySortByParentId(parentId, classifyId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` update edb_monitor_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
+}
+
+// GetFirstEdbMonitorClassifyByParentId 获取当前父级图表分类下的排序第一条的数据
+func GetFirstEdbMonitorClassifyByParentId(parentId int) (item *EdbMonitorClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM edb_monitor_classify WHERE parent_id=? order by sort asc,classify_id asc limit 1`
+	err = o.Raw(sql, parentId).QueryRow(&item)
+	return
+}

+ 79 - 0
models/edb_monitor/edb_monitor_message.go

@@ -0,0 +1,79 @@
+package edbmonitor
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type EdbMonitorMessage struct {
+	EdbMonitorMessageId int       `orm:"column(edb_monitor_message_id);pk"`
+	EdbInfoId           int       `description:"指标id"`
+	EdbInfoType         int       `description:"指标类型: 0-普通指标;1-预测指标"`
+	EdbUniqueCode       string    `description:"指标唯一标识"`
+	EdbClassifyId       int       `description:"指标id"`
+	AdminId             int       `description:"用户id"`
+	IsRead              int       `description:"是否已读: 0-未读;1-已读"`
+	Message             string    `description:"消息内容"`
+	MonitorTriggerTime  time.Time `description:"预警触发时间"`
+	CreateTime          time.Time `description:"创建时间"`
+}
+
+func (m *EdbMonitorMessage) Insert() (insertId int64, err error) {
+	o := orm.NewOrmUsingDB("data")
+	insertId, err = o.Insert(m)
+	return
+}
+
+func (m *EdbMonitorMessage) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func BatchModifyEdbMonitorMessageIsRead(ids []int, adminId int) (err error) {
+	if len(ids) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := `UPDATE edb_monitor_message SET is_read =1 WHERE admin_id =? AND is_read = 0 AND edb_monitor_message_id IN (` + utils.GetOrmInReplace(len(ids)) + `)`
+	_, err = o.Raw(sql, adminId, ids).Exec()
+	return
+}
+
+func (m *EdbMonitorMessage) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM edb_monitor_message WHERE 1=1 %s`, condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func GetEdbMonitorMessageById(id int) (item *EdbMonitorMessage, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_message WHERE edb_monitor_message_id =?"
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetEdbMonitorMessageByAdminId(adminId int) (items []*EdbMonitorMessage, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_message WHERE admin_id =? AND is_read = 0 ORDER BY create_time DESC"
+	_, err = o.Raw(sql, adminId).QueryRows(&items)
+	return
+}
+
+func GetEdbMonitorMessageCountByAdminId(adminId int) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT COUNT(*) FROM edb_monitor_message WHERE admin_id =? ORDER BY is_read ASC, create_time DESC"
+	err = o.Raw(sql, adminId).QueryRow(&count)
+	return
+}
+
+func GetEdbMonitorMessagePageByAdminId(adminId, startSize, pageSize int) (items []*EdbMonitorMessage, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := "SELECT * FROM edb_monitor_message WHERE admin_id =? ORDER BY is_read ASC, create_time DESC LIMIT?,?"
+	_, err = o.Raw(sql, adminId, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 25 - 0
models/edb_monitor/request/edb_monitor.go

@@ -0,0 +1,25 @@
+package request
+
+type EdbMonitorInfoSaveReq struct {
+	EdbMonitorId   int    `description:"预警ID"`
+	EdbInfoId      int    `description:"指标ID"`
+	EdbUniqueCode  string `description:"指标唯一标识"`
+	EdbClassifyId  int    `description:"指标id"`
+	MonitorType    int    `description:"突破方式:0-向上突破;1-向下突破"`
+	MonitorData    string `description:"预警值"`
+	EdbMonitorName string `description:"预警名称"`
+	MonitorLevel   string `description:"预警级别"`
+	ClassifyId     int    `description:"预警分类"`
+}
+
+type EdbMonitorInfoDeleteReq struct {
+	EdbMonitorId int `description:"预警ID"`
+}
+
+type EdbMonitorInfoCloseReq struct {
+	EdbMonitorId int `description:"预警ID"`
+}
+
+type EdbMonitorInfoRestartReq struct {
+	EdbMonitorId int `description:"预警ID"`
+}

+ 19 - 0
models/edb_monitor/request/edb_monitor_classify.go

@@ -0,0 +1,19 @@
+package request
+
+type EdbMonitorClassifySaveReq struct {
+	ClassifyId   int
+	ClassifyName string
+	Level        int
+	ParentId     int
+}
+
+type EdbMonitorClassifyDeleteReq struct {
+	ClassifyId int
+}
+
+type MoveEdbMonitorClassifyReq struct {
+	ClassifyId       int `description:"分类id"`
+	ParentClassifyId int `description:"父级分类id"`
+	PrevClassifyId   int `description:"上一个兄弟节点分类id"`
+	NextClassifyId   int `description:"下一个兄弟节点分类id"`
+}

+ 5 - 0
models/edb_monitor/request/edb_monitor_message.go

@@ -0,0 +1,5 @@
+package request
+
+type EdbMonitorMessageReadReq struct {
+	EdbMonitorMessageId int `description:"预警消息id"`
+}

+ 46 - 0
models/edb_monitor/response/edb_monitor.go

@@ -0,0 +1,46 @@
+package response
+
+import (
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type EdbMonitorInfoItem struct {
+	EdbMonitorId           int     `orm:"column(edb_monitor_id);pk"`
+	EdbMonitorClassifyId   int     `description:"预警分类id"`
+	EdbMonitorClassifyName string  `description:"预警分类名称"`
+	EdbMonitorName         string  `description:"预警名称"`
+	EdbInfoId              int     `description:"指标id"`
+	EdbInfoName            string  `description:"指标名称"`
+	EdbInfoType            int     `description:"指标类型"`
+	EdbUniqueCode          string  `description:"指标唯一标识"`
+	EdbClassifyId          int     `description:"指标id"`
+	EdbCode                string  `description:"指标编码"`
+	Source                 int     `description:"指标来源" json:"-"`
+	SubSource              int     `description:"指标子来源: 0-经济数据库;1-日期序列;2-高频数据" json:"-"`
+	EdbLatestDate          string  `description:"最新日期"`
+	EdbLatestValue         float64 `description:"最新值"`
+	MonitorType            int     `description:"突破方式: 0-向上突破;1-向下突破"`
+	MonitorData            float64 `description:"预警值"`
+	MonitorLevel           string  `description:"预警等级"`
+	State                  int     `description:"预警状态: 0-已关闭;1-未触发;2-已触发"`
+	EdbTriggerDate         string  `description:"触发日期"`
+	MonitorTriggerTime     string  `description:"预警触发时间"`
+	CreateUserId           int     `description:"创建人id"`
+	CreateUserName         string  `description:"创建人姓名"`
+	CreateTime             string  `description:"创建时间" json:"-"`
+	ModifyTime             string  `description:"修改时间" json:"-"`
+}
+
+type EdbMonitorCreateUserItem struct {
+	AdminId  int    `description:"管理员id"`
+	RealName string `description:"管理员姓名"`
+}
+
+type EdbMonitorInfoCreateUserResp struct {
+	List []*EdbMonitorCreateUserItem `description:"创建人信息"`
+}
+
+type EdbMonitorInfoListResp struct {
+	List   []*EdbMonitorInfoItem `description:"预警列表"`
+	Paging *paging.PagingItem    `description:"分页信息"`
+}

+ 8 - 0
models/edb_monitor/response/edb_monitor_classify.go

@@ -0,0 +1,8 @@
+package response
+
+type EdbMonitorClassifyTree struct {
+	ClassifyId   int                       `description:"分类id"`
+	ClassifyName string                    `description:"分类名称"`
+	Level        int                       `description:"分类层级"`
+	Children     []*EdbMonitorClassifyTree `description:"子分类"`
+}

+ 19 - 0
models/edb_monitor/response/edb_monitor_message.go

@@ -0,0 +1,19 @@
+package response
+
+import "github.com/rdlucklib/rdluck_tools/paging"
+
+type EdbMonitorMessageResp struct {
+	EdbMonitorMessageId int    `description:"消息id"`
+	EdbInfoId           int    `description:"指标id"`
+	EdbInfoType         int    `description:"指标类型:0-普通指标;1-预测指标"`
+	EdbUniqueCode       string `description:"指标唯一标识"`
+	EdbClassifyId       int    `description:"指标id"`
+	IsRead              int    `description:"是否已读:0-未读;1-已读"`
+	Message             string `description:"消息内容"`
+	TriggerTime         string `description:"触发时间"`
+}
+
+type EdbMonitorMessageListResp struct {
+	List   []*EdbMonitorMessageResp
+	Paging *paging.PagingItem
+}

+ 51 - 5
models/english_report.go

@@ -96,8 +96,6 @@ type AddEnglishReportReq struct {
 	ClassifyNameFirst  string `description:"一级分类名称"`
 	ClassifyIdSecond   int    `description:"二级分类id"`
 	ClassifyNameSecond string `description:"二级分类名称"`
-	ClassifyIdThird    int    `description:"三级分类id"`
-	ClassifyNameThird  string `description:"三级分类名称"`
 	Title              string `description:"标题"`
 	Abstract           string `description:"摘要"`
 	Author             string `description:"作者"`
@@ -431,9 +429,10 @@ type EnglishClassifyList struct {
 	ShowType      int       `description:"展示类型:1-列表 2-专栏"`
 	IsShow        int       `description:"是否在小程序显示:1-显示 0-隐藏"`
 	//ClassifyType  int       `description:"分类类型:0英文报告,1英文线上路演"`
-	EnPermissions []int `description:"英文权限IDs"`
-	Enabled       int   `description:"是否可用,1可用,0禁用"`
-	Child         []*EnglishClassifyList
+	EnPermissions  []int `description:"英文权限IDs"`
+	Enabled        int   `description:"是否可用,1可用,0禁用"`
+	IsEnableDelete int   `description:"是否允许删除: 1-允许 0-不允许"`
+	Child          []*EnglishClassifyList
 }
 
 type EnglishClassifyListResp struct {
@@ -547,6 +546,41 @@ type EnglishClassify struct {
 	Enabled int `description:"是否可用,1可用,0禁用"`
 }
 
+func (e *EnglishClassify) Delete() (err error) {
+	tx, err := orm.NewOrmUsingDB("rddp").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tx.Rollback()
+		} else {
+			tx.Commit()
+		}
+	}()
+	_, err = tx.Delete(e)
+	if err != nil {
+		return
+	}
+	if e.Id == e.RootId {
+		// 删除一级分类时,删除其下所有子分类
+		sql := `DELETE FROM english_classify WHERE root_id = ?`
+		_, err = tx.Raw(sql, e.Id).Exec()
+		if err != nil {
+			return
+		}
+	}
+	if e.ParentId == e.RootId {
+		// 删除二级分类时,更新其父级分类的子分类数量
+		sql := `DELETE FROM english_classify WHERE id = ? OR parent_id = ?`
+		_, err = tx.Raw(sql, e.Id, e.ParentId).Exec()
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
 func AddEnglishClassify(item *EnglishClassify) (lastId int64, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	lastId, err = o.Insert(item)
@@ -1014,3 +1048,15 @@ func GetEnglishReportFieldsByIds(ids []int, fields []string) (items []*EnglishRe
 	_, err = o.Raw(sql, ids).QueryRows(&items)
 	return
 }
+
+func GetExistEnglishReportClassifyIdByClassifyIds(classifyIds []int) (existClassifyIds []*EnglishReport, err error) {
+	if len(classifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT classify_id_first, classify_id_second FROM english_report WHERE 1=1 `
+	sql += fmt.Sprintf(` AND (classify_id_first IN (%s) OR classify_id_second IN (%s))`, utils.GetOrmInReplace(len(classifyIds)), utils.GetOrmInReplace(len(classifyIds)))
+
+	_, err = o.Raw(sql, classifyIds, classifyIds).QueryRows(&existClassifyIds)
+	return
+}

+ 8 - 0
models/english_video.go

@@ -330,3 +330,11 @@ func GetEnglishVideoByIds(Ids []int, fieldArr []string) (list []*EnglishVideo, e
 	_, err = o.Raw(sql, Ids).QueryRows(&list)
 	return
 }
+
+// GetAllEnglishVideoClassify 获取路演视频分类列表
+func GetAllEnglishVideoClassify() (list []*EnglishVideo, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT classify_id_first, classify_id_second FROM english_video `
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}

+ 11 - 1
models/permission.go

@@ -1,6 +1,9 @@
 package models
 
-import "github.com/beego/beego/v2/client/orm"
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+)
 
 // ChartPermissionSearchKeyWordMapping 权限相关
 type ChartPermissionSearchKeyWordMapping struct {
@@ -124,3 +127,10 @@ func GetPermissionByClassifyId(classifyId int) (items []*ChartPermissionSearchKe
 	_, err = o.Raw(sql, classifyId).QueryRows(&items)
 	return
 }
+
+func GetClassifyIdsByPermissionId(chartPermissionIdList []string) (classifyIds []string, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := "SELECT classify_id FROM chart_permission_search_key_word_mapping WHERE `from` =  'rddp' and chart_permission_id IN (" + utils.GetOrmInReplace(len(chartPermissionIdList)) + ") and classify_id <> 0; "
+	_, err = o.Raw(sql, chartPermissionIdList).QueryRows(&classifyIds)
+	return
+}

+ 32 - 4
models/report.go

@@ -4,10 +4,11 @@ import (
 	"errors"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // 报告状态
@@ -166,7 +167,7 @@ type ReportListResp struct {
 // @return err error
 func GetReportListCountV1(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT COUNT(1) AS count  FROM report as a WHERE 1=1 `
+	sql := `SELECT COUNT(DISTINCT a.id) AS count  FROM report as a WHERE 1=1 `
 	if condition != "" {
 		sql += condition
 	}
@@ -201,7 +202,9 @@ func GetReportListV1(condition string, pars []interface{}, startSize, pageSize i
 func GetReportListByCondition(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 
-	sql := `SELECT * FROM report as a WHERE 1=1  `
+	sql := `SELECT DISTINCT a.id, a.title, a.author, a.modify_time, a.publish_time,a.classify_id_first,
+a.classify_name_first,a.classify_id_second,a.classify_name_second,a.classify_id_third,
+a.classify_name_third,a.abstract,a.admin_id,a.admin_real_name,a.last_modify_admin_id,a.last_modify_admin_name FROM report as a WHERE 1=1  `
 	if condition != "" {
 		sql += condition
 	}
@@ -1527,6 +1530,18 @@ func GetReportListByClassifyId(classifyId int) (items []*Report, err error) {
 	return items, err
 }
 
+func GetExistReportClassifyIdByClassifyIds(classifyIds []int) (existClassifyIds []*Report, err error) {
+	if len(classifyIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT classify_id_first, classify_id_second, classify_id_third FROM report WHERE 1=1 `
+	sql += fmt.Sprintf(` AND (classify_id_first IN (%s) OR classify_id_second IN (%s) OR classify_id_third IN (%s))`, utils.GetOrmInReplace(len(classifyIds)), utils.GetOrmInReplace(len(classifyIds)), utils.GetOrmInReplace(len(classifyIds)))
+
+	_, err = o.Raw(sql, classifyIds, classifyIds, classifyIds).QueryRows(&existClassifyIds)
+	return
+}
+
 // UpdateReportInfo 修改报告
 func UpdateReportInfo(reports *Report) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -1537,3 +1552,16 @@ func UpdateReportInfo(reports *Report) (err error) {
 
 	return
 }
+
+func FindReportListByCondition(condition string, pars []interface{}) (items []*Report, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report WHERE 1=1 `
+	if condition != "" {
+		sql += condition
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	if err != nil {
+		return nil, err
+	}
+	return
+}

+ 7 - 3
models/report_approve/report_approve.go

@@ -3,10 +3,11 @@ package report_approve
 import (
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // ReportApprove 报告审批表
@@ -186,6 +187,7 @@ type ReportApproveItem struct {
 	ReportClassify        string `description:"报告分类"`
 	ClassifyFirstId       int    `description:"一级分类ID"`
 	ClassifySecondId      int    `description:"二级分类ID"`
+	ClassifyThirdId       int    `description:"三级分类ID"`
 	State                 int    `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
 	RecordState           int    `description:"审批记录状态:1-待审批;2-已通过;3-已驳回"`
 	FlowId                int    `description:"审批流ID"`
@@ -216,6 +218,7 @@ func FormatReportApproveOrm2Item(origin *ReportApproveItemOrm) (item *ReportAppr
 	item.ReportTitle = origin.ReportTitle
 	item.ClassifyFirstId = origin.ClassifyFirstId
 	item.ClassifySecondId = origin.ClassifySecondId
+	item.ClassifyThirdId = origin.ClassifyThirdId
 	item.State = origin.State
 	item.RecordState = origin.RecordState
 	item.FlowId = origin.FlowId
@@ -240,6 +243,7 @@ type ReportApproveListReq struct {
 	ReportType       int    `form:"ReportType" description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
 	ClassifyFirstId  int    `form:"ClassifyFirstId" description:"一级分类ID"`
 	ClassifySecondId int    `form:"ClassifySecondId" description:"二级分类ID"`
+	ClassifyThirdId  int    `form:"ClassifyThirdId" description:"三级级分类ID"`
 	Keyword          string `form:"Keyword" description:"关键词:报告标题"`
 	ApproveState     int    `form:"ApproveState" description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
 	TimeType         int    `form:"TimeType" description:"时间类型:1-提交时间;2-处理时间;3-审批时间"`
@@ -263,7 +267,7 @@ type ReportApproveItemOrm struct {
 	ReportTitle           string    `description:"报告标题"`
 	ClassifyFirstId       int       `description:"一级分类ID"`
 	ClassifySecondId      int       `description:"二级分类ID"`
-	ClassifyThirdId       int       `description:"级分类ID"`
+	ClassifyThirdId       int       `description:"级分类ID"`
 	State                 int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
 	RecordState           int       `description:"审批记录状态:1-待审批;2-已通过;3-已驳回"`
 	FlowId                int       `description:"审批流ID"`

+ 9 - 1
models/sandbox/sandbox_classify.go

@@ -2,8 +2,9 @@ package sandbox
 
 import (
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 type SandboxClassify struct {
@@ -43,6 +44,13 @@ func GetSandboxClassifyAll() (items []*SandboxClassifyItems, err error) {
 	return
 }
 
+func GetSandboxClassifyAllIncludeParent() (items []*SandboxClassifyItems, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM sandbox_classify order by sort asc,sandbox_classify_id asc`
+	_, err = o.Raw(sql).QueryRows(&items)
+	return
+}
+
 type SandboxClassifyItems struct {
 	SandboxClassifyId   int       `orm:"column(sandbox_classify_id);pk"`
 	SandboxClassifyName string    `description:"分类名称"`

+ 13 - 2
models/system/sys_admin.go

@@ -3,10 +3,11 @@ package system
 import (
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 type AdminItem struct {
@@ -45,6 +46,16 @@ type AdminItem struct {
 	IsLdap                  int    `description:"是否为域用户:0-系统账户;1-域用户"`
 }
 
+func GetAdminItemByIdList(adminId []int) (items []*AdminItem, err error) {
+	if len(adminId) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := `SELECT * FROM admin WHERE admin_id IN (` + utils.GetOrmInReplace(len(adminId)) + `) ORDER BY created_time DESC`
+	_, err = o.Raw(sql, adminId).QueryRows(&items)
+	return
+}
+
 func GetSysuserList(condition string, pars []interface{}, startSize, pageSize int) (items []*AdminItem, err error) {
 	o := orm.NewOrm()
 	sql := `SELECT * FROM admin WHERE 1=1 `

+ 22 - 0
models/system/sys_menu.go

@@ -191,3 +191,25 @@ func GetMenuButtonApisByRoleId(roleId int) (items []*SysMenu, err error) {
 	_, err = orm.NewOrm().Raw(sql, roleId).QueryRows(&items)
 	return
 }
+
+// SysMenuSimple ETA商家菜单
+type SysMenuSimple struct {
+	MenuId     int       `orm:"column(menu_id);pk"`
+	ParentId   int       `description:"父级菜单ID"`
+	Name       string    `description:"菜单名称或者按钮名称"`
+	Sort       string    `description:"排序"`
+	Path       string    `description:"路由地址"`
+	NameEn     string    `description:"菜单名称或者按钮名称(英文)"`
+}
+
+
+// GetMenuByRoleIds 根据管理员多个角色查询菜单ID
+func GetMenuByRoleIds(roleIds string) (items []*SysMenu, err error) {
+	sql := ` SELECT DISTINCT a.* FROM sys_menu AS a
+			INNER JOIN sys_role_menu AS b ON a.menu_id=b.menu_id AND b.type = 0
+			INNER JOIN sys_role AS c ON b.role_id=c.role_id
+			WHERE c.role_id in (` + roleIds + `)
+            ORDER BY a.sort ASC, create_time DESC, menu_id DESC`
+	_, err = orm.NewOrm().Raw(sql).QueryRows(&items)
+	return
+}

+ 12 - 1
models/system/sys_role.go

@@ -2,9 +2,10 @@ package system
 
 import (
 	"eta/eta_api/utils"
+	"time"
+
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
-	"time"
 )
 
 type SysRoleAddReq struct {
@@ -257,3 +258,13 @@ func GetEnglishAuthRoleItems(roleCodes []string) (items []*SysRole, err error) {
 	_, err = o.Raw(sql, roleCodes).QueryRows(&items)
 	return
 }
+
+func GetSysRoleByIdList(id []int) (items []*SysRole, err error) {
+	if len(id) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := `SELECT * FROM sys_role WHERE role_id IN (` + utils.GetOrmInReplace(len(id)) + `)`
+	_, err = o.Raw(sql, id).QueryRows(&items)
+	return
+}

+ 31 - 21
models/target.go

@@ -427,28 +427,34 @@ func GetEdbdataClassify(userId int64) (items []*EdbdataClassifyList, err error)
 	}
 	classifyLen := len(newItems)
 
+	// 获取子集分类
+	var allChildItems []*EdbdataClassify
+	if userId > 0 {
+		userClassifyList, _ := GetManualUserClassify(int(userId))
+		var userIdArr []int
+		for _, v := range userClassifyList {
+			userIdArr = append(userIdArr, v.ClassifyId)
+		}
+		num := len(userClassifyList)
+		if num > 0 {
+			childSql := "SELECT a.classify_id,a.classify_name,a.parent_id FROM edbdata_classify AS a WHERE a.is_show=1 and a.classify_id IN(" + utils.GetOrmInReplace(num) + ") ORDER BY a.create_time ASC "
+			_, err = o.Raw(childSql, userIdArr).QueryRows(&allChildItems)
+		}
+	} else {
+		childSql := "SELECT classify_id,classify_name,parent_id FROM edbdata_classify WHERE is_show=1 ORDER BY create_time ASC "
+		_, err = o.Raw(childSql).QueryRows(&allChildItems)
+	}
+	if err != nil {
+		return
+	}
+
 	for i := 0; i < classifyLen; i++ {
 		var childItems []*EdbdataClassify
 		parentId := newItems[i].ClassifyId
-		childSql := ``
-		if userId > 0 {
-			userClassifyList, _ := GetManualUserClassify(int(userId))
-			var userIdArr []string
-			for _, v := range userClassifyList {
-				userIdArr = append(userIdArr, strconv.Itoa(v.ClassifyId))
-			}
-
-			userIdStr := strings.Join(userIdArr, ",")
-			if userIdStr != "" {
-				childSql = "SELECT a.classify_id,a.classify_name,a.parent_id FROM edbdata_classify AS a WHERE a.is_show=1 and a.classify_id IN(" + userIdStr + ") AND parent_id=? ORDER BY a.create_time ASC "
-				_, err = o.Raw(childSql, parentId).QueryRows(&childItems)
+		for _, v := range allChildItems {
+			if v.ParentId == parentId {
+				childItems = append(childItems, v)
 			}
-		} else {
-			childSql = "SELECT classify_id,classify_name,parent_id FROM edbdata_classify WHERE is_show=1 and parent_id=? ORDER BY create_time ASC "
-			_, err = o.Raw(childSql, parentId).QueryRows(&childItems)
-		}
-		if err != nil {
-			return
 		}
 		newItems[i].Child = childItems
 	}
@@ -1473,13 +1479,17 @@ type EdbInfoGroupCount struct {
 }
 
 // GetEdbInfoGroupCountByClassifyIds 根据指标分类id获取当前分类下的指标数量
-func GetEdbInfoGroupCountByClassifyIds(classifyIds string) (list []*EdbInfoGroupCount, err error) {
+func GetEdbInfoGroupCountByClassifyIds(classifyIdList []int) (list []*EdbInfoGroupCount, err error) {
+	num := len(classifyIdList)
+	if num <= 0 {
+		return
+	}
 	o := orm.NewOrmUsingDB("edb")
 	sql := `SELECT COUNT(1) AS count,classify_id FROM ( SELECT a.*,b.CLOSE FROM edbinfo AS a 
              INNER JOIN edbdata AS b ON a.TRADE_CODE=b.TRADE_CODE
-             WHERE a.classify_id in (` + classifyIds + `) group by a.TRADE_CODE) d 
+             WHERE a.classify_id in (` + utils.GetOrmInReplace(num) + `) group by a.TRADE_CODE) d 
 						 GROUP BY classify_id `
-	_, err = o.Raw(sql).QueryRows(&list)
+	_, err = o.Raw(sql, classifyIdList).QueryRows(&list)
 	return
 }
 

+ 68 - 0
models/user_collect_classify.go

@@ -0,0 +1,68 @@
+// @Author gmy 2024/9/21 14:47:00
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+/**
+CREATE TABLE `user_collect_classify` (
+  `user_collect_classify_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `classify_id` int(9) unsigned NOT NULL DEFAULT '0' COMMENT '分类id',
+  `sys_user_id` int(9) unsigned DEFAULT '0' COMMENT '收藏人用户id',
+  `create_time` datetime DEFAULT NULL COMMENT '收藏时间',
+  PRIMARY KEY (`user_collect_classify_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户收藏的分类id';
+*/
+
+type UserCollectClassify struct {
+	UserCollectClassifyId int    `orm:"column(user_collect_classify_id);pk" description:"用户收藏的分类id"`
+	ClassifyId            int    `orm:"column(classify_id)" description:"分类id"`
+	SysUserId             int    `orm:"column(sys_user_id)" description:"收藏人用户id"`
+	CreateTime            string `orm:"column(create_time)" description:"收藏时间"`
+}
+
+// GetUserCollectClassifyList 查询用户收藏的分类列表
+func GetUserCollectClassifyList(sysUserId, classifyId int) (list []*UserCollectClassify, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM user_collect_classify WHERE 1=1`
+	var params []interface{}
+
+	// 处理 sysUserId 参数
+	if sysUserId > 0 {
+		sql += ` AND sys_user_id=?`
+		params = append(params, sysUserId)
+	}
+
+	// 处理 classifyId 参数
+	if classifyId > 0 {
+		sql += ` AND classify_id=?`
+		params = append(params, classifyId)
+	}
+
+	_, err = o.Raw(sql, params...).QueryRows(&list)
+
+	return
+}
+
+// InsertUserCollectClassify 新增用户收藏的分类
+func InsertUserCollectClassify(item UserCollectClassify) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `INSERT INTO user_collect_classify(classify_id, sys_user_id, create_time) VALUES(?, ?, ?)`
+	_, err = o.Raw(sql, item.ClassifyId, item.SysUserId, item.CreateTime).Exec()
+	return
+}
+
+// DeleteUserCollectClassify 删除分类
+func DeleteUserCollectClassify(sysUserId, classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `DELETE FROM user_collect_classify WHERE sys_user_id=? AND classify_id=?`
+	_, err = o.Raw(sql, sysUserId, classifyId).Exec()
+	return
+}
+
+// DeleteUserCollectClassify 删除分类
+func DeleteCollectByClassifyId(classifyId int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `DELETE FROM user_collect_classify WHERE classify_id=?`
+	_, err = o.Raw(sql, classifyId).Exec()
+	return
+}

+ 423 - 0
routers/commentsRouter.go

@@ -4021,6 +4021,33 @@ 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: "BatchAddEdbCheck",
+            Router: `/ccf/batch/add/check`,
+            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: "CCFIndexBatchAdd",
+            Router: `/ccf/batch_add`,
+            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: "CCFIndexBatchSearch",
+            Router: `/ccf/batch_search`,
+            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: "CCFClassify",
@@ -4030,6 +4057,33 @@ 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: "CCFEdbInfoAdd",
+            Router: `/ccf/edb_info/add`,
+            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: "CCFAddCheck",
+            Router: `/ccf/edb_info/add_check`,
+            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: "CCFIndexNameCheck",
+            Router: `/ccf/edb_info/name_check`,
+            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: "ExportCCFList",
@@ -4039,6 +4093,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: "GetCCFFrequency",
+            Router: `/ccf/frequency`,
+            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: "CCFIndexData",
@@ -6523,6 +6586,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbTerminalController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbTerminalController"],
+        beego.ControllerComments{
+            Method: "TerminalIndexDirInfo",
+            Router: `/terminal/index_dir`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbTerminalController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_stat:EdbTerminalController"],
         beego.ControllerComments{
             Method: "List",
@@ -6631,6 +6703,159 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"],
+        beego.ControllerComments{
+            Method: "Delete",
+            Router: `/classify/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorClassifyController"],
+        beego.ControllerComments{
+            Method: "Move",
+            Router: `/classify/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "Add",
+            Router: `/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "Close",
+            Router: `/close`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "Delete",
+            Router: `/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "Edit",
+            Router: `/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "GetMonitorLevel",
+            Router: `/monitor_level/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "GetMonitorUser",
+            Router: `/monitor_user/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorController"],
+        beego.ControllerComments{
+            Method: "Restart",
+            Router: `/restart`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"],
+        beego.ControllerComments{
+            Method: "Close",
+            Router: `/message/close`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"],
+        beego.ControllerComments{
+            Method: "Connect",
+            Router: `/message/connect`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/message/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/edb_monitor:EdbMonitorMessageController"],
+        beego.ControllerComments{
+            Method: "Read",
+            Router: `/message/read`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/english_report:EnPermissionController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/english_report:EnPermissionController"],
         beego.ControllerComments{
             Method: "Add",
@@ -8647,6 +8872,195 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "AddDashboard",
+            Router: `/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "ChartExcelPermission",
+            Router: `/chart_excel_permission`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "AddDashboardClassify",
+            Router: `/classify/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "EditDashboardClassify",
+            Router: `/classify/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "ClassifyList",
+            Router: `/classify/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "DeleteDashboard",
+            Router: `/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "DetailDashboard",
+            Router: `/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "DeleteDashboardDetail",
+            Router: `/detail/delete`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "MoveDashboard",
+            Router: `/detail/move`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "EditDashboard",
+            Router: `/edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "Editing",
+            Router: `/editing`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "Grant",
+            Router: `/grant`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "CancelGrant",
+            Router: `/grant/cancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "GrantInfo",
+            Router: `/grant/info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "HomePage",
+            Router: `/home_page`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "HomePageSave",
+            Router: `/home_page/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "MyList",
+            Router: `/my_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "Public",
+            Router: `/public`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "PublicCancel",
+            Router: `/public/cancel`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "PublicList",
+            Router: `/public_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BIDaShboardController"],
+        beego.ControllerComments{
+            Method: "ShareList",
+            Router: `/share_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:BannerController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:BannerController"],
         beego.ControllerComments{
             Method: "Upload",
@@ -9853,6 +10267,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: "CancelPublishReportChapter",
+            Router: `/chapter/publish/cancel`,
+            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: "EditChapterTitle",

+ 13 - 0
routers/router.go

@@ -24,6 +24,7 @@ import (
 	"eta/eta_api/controllers/data_source"
 	"eta/eta_api/controllers/data_stat"
 	"eta/eta_api/controllers/document_manage"
+	"eta/eta_api/controllers/edb_monitor"
 	"eta/eta_api/controllers/english_report"
 	"eta/eta_api/controllers/eta_trial"
 	"eta/eta_api/controllers/fe_calendar"
@@ -403,6 +404,18 @@ func init() {
 				&stl.STLController{},
 			),
 		),
+		web.NSNamespace("/edb_monitor",
+			web.NSInclude(
+				&edb_monitor.EdbMonitorController{},
+				&edb_monitor.EdbMonitorClassifyController{},
+				&edb_monitor.EdbMonitorMessageController{},
+			),
+		),
+		web.NSNamespace("/bi_dashborad",
+			web.NSInclude(
+				&controllers.BIDaShboardController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 53 - 0
services/ai_summary/ai_summary.go

@@ -182,3 +182,56 @@ func SharePrompt(promptId int, adminId int) (err error) {
 	}
 	return
 }
+func GetAiSummaryClassifyByIsShowMe(classifyList []*ai_summary.AiSummaryClassifyItems, classifyId, adminId int) (list []*ai_summary.AiSummaryClassifyItems, err error) {
+	aiSummaryList, err := ai_summary.GetAiSummaryInfoByAdminId(adminId)
+	if err != nil {
+		return
+	}
+	existClassify := make(map[int]struct{})
+	for _, v := range aiSummaryList {
+		existClassify[v.AiSummaryClassifyId] = struct{}{}
+	}
+	for _, v := range classifyList {
+		if v.AiSummaryId > 0 {
+			v.ClassifyName = v.Title
+			list = append(list, v)
+		}
+	}
+
+	classifyAll, err := ai_summary.GetAiSummaryClassifyAllIncludeParent()
+	if err != nil {
+		return
+	}
+	classifyTree := aiSummaryClassifyTree(classifyAll, classifyId)
+	list = append(list, GetClassifyListRemoveNoAiSummary(classifyTree, existClassify)...)
+	return
+
+}
+
+func aiSummaryClassifyTree(classifyList []*ai_summary.AiSummaryClassifyItems, classifyId int) (list []*ai_summary.AiSummaryClassifyItems) {
+	for _, v := range classifyList {
+		if v.ParentId == classifyId {
+			list = append(list, v)
+			v.Children = aiSummaryClassifyTree(classifyList, v.AiSummaryClassifyId)
+		}
+	}
+	return
+}
+
+// GetClassifyListRemoveNoAiSummary 去除没有表格的分类
+func GetClassifyListRemoveNoAiSummary(classifyList []*ai_summary.AiSummaryClassifyItems, aiSummaryExistClassifyId map[int]struct{}) []*ai_summary.AiSummaryClassifyItems {
+	res := make([]*ai_summary.AiSummaryClassifyItems, 0)
+	for _, classify := range classifyList {
+		if _, ok := aiSummaryExistClassifyId[classify.AiSummaryClassifyId]; ok {
+			classify.Children = []*ai_summary.AiSummaryClassifyItems{}
+			res = append(res, classify)
+			continue
+		}
+		classify.Children = append([]*ai_summary.AiSummaryClassifyItems{}, GetClassifyListRemoveNoAiSummary(classify.Children, aiSummaryExistClassifyId)...)
+		if len(classify.Children) > 0 {
+			classify.Children = []*ai_summary.AiSummaryClassifyItems{}
+			res = append(res, classify)
+		}
+	}
+	return res
+}

+ 68 - 0
services/bi_dashboard.go

@@ -0,0 +1,68 @@
+package services
+
+import (
+	"encoding/json"
+	"eta/eta_api/models/bi_dashboard"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+
+
+
+// UpdateBiDashboardEditing 更新看板编辑状态
+func UpdateBiDashboardEditing(boardId, status, userId int, userName string) (ret bi_dashboard.BiDashboardEditingCache, err error) {
+	if boardId <= 0 {
+		return
+	}
+	cacheKey := ""
+	cacheKey = fmt.Sprint(utils.CACHE_BI_DASHBOARD_EDITING, boardId)
+
+	// 完成编辑
+	if status == 2 {
+		_ = utils.Rc.Delete(cacheKey)
+		return
+	}
+
+	// 读取缓存中的结果
+	var editor bi_dashboard.BiDashboardEditingCache
+	strCache, _ := utils.Rc.RedisString(cacheKey)
+	fmt.Println(strCache)
+	if strCache != "" {
+		e := json.Unmarshal([]byte(strCache), &editor)
+		if e != nil {
+			err = fmt.Errorf("解析缓存内容失败: %s", e.Error())
+			return
+		}
+	}
+
+	// 标记编辑中
+	if status == 1 {
+		// 无人编辑, 写入缓存
+		if !editor.IsEditing {
+			ret.IsEditing = true
+			ret.AdminId = userId
+			ret.Editor = userName
+			ret.Tips = fmt.Sprintf("当前%s正在编辑看板", userName)
+			b, _ := json.Marshal(ret)
+			utils.Rc.SetNX(cacheKey, string(b), 3*time.Minute)
+			return
+		}
+
+		// 有人编辑
+		if editor.IsEditing {
+			// 编辑用户与当前用户不一致, 返回编辑用户, 一致则更新缓存
+			if userId == editor.AdminId {
+				b, _ := json.Marshal(editor)
+				utils.Rc.Do("SETEX", cacheKey, int64(180), string(b))
+			}
+			ret = editor
+			return
+		}
+	} else {
+		// 默认查询
+		ret = editor
+	}
+	return
+}

+ 271 - 0
services/binlog/binlog.go

@@ -0,0 +1,271 @@
+package binlog
+
+import (
+	"eta/eta_api/models/binlog"
+	"eta/eta_api/utils"
+	"fmt"
+	"math/rand"
+	"strconv"
+	"time"
+
+	"github.com/go-mysql-org/go-mysql/canal"
+	"github.com/go-mysql-org/go-mysql/mysql"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+func ListenMysql() {
+	var err error
+	defer func() {
+		if err != nil {
+			fmt.Println("数据库监听服务异常,err:", err)
+		}
+	}()
+	if utils.MYSQL_DATA_BINLOG_URL == "" {
+		panic("mysql url is empty")
+	}
+
+	if utils.MYSQL_DATA_BINLOG_USER == "" {
+		panic("mysql user is empty")
+	}
+	if utils.MYSQL_DATA_BINLOG_PWD == "" {
+		panic("mysql password is empty")
+	}
+	if utils.MYSQL_DATA_BINLOG_DB == "" {
+		panic("mysql db is empty")
+	}
+
+	includeTableRegex := []string{
+		utils.MYSQL_DATA_BINLOG_DB + ".edb_info$",
+		// utils.MYSQL_DATA_BINLOG_DB + ".edb_classify$",
+		// utils.MYSQL_DATA_BINLOG_DB + ".base_from_mysteel_chemical_index$",
+		// utils.MYSQL_DATA_BINLOG_DB + ".base_from_smm_index$",
+		// utils.MYSQL_DATA_BINLOG_DB + ".edb_data*",
+	}
+
+	// 主从复制的身份id配置,必须全局唯一,如果没有配置的话,那么会随机生成一个
+	var serverId uint32
+	if utils.MYSQL_DATA_BINLOG_SERVER_ID != "" {
+		id, _ := strconv.ParseUint(utils.MYSQL_DATA_BINLOG_SERVER_ID, 10, 32)
+		serverId = uint32(id)
+	}
+	if serverId == 0 {
+		serverId = uint32(rand.New(rand.NewSource(time.Now().Unix())).Intn(1000)) + 1001
+	}
+	cfg := &canal.Config{
+		// 一个32位无符号整数,用于标识当前 Canal 实例在 MySQL 主从复制体系中的身份。这里使用了一个随机数生成器确保每次启动时分配的 ServerID 是唯一的(在1001到1099之间)。在实际生产环境中,你需要手动指定一个全局唯一的 ServerID。
+		ServerID: serverId,
+		// 指定 Canal 要连接的数据库类型,默认为 "mysql",表明这是一个 MySQL 数据库。
+		Flavor: "mysql",
+		// 设置 MySQL 服务器地址(主机名或 IP 地址)和端口,例如 "127.0.0.1:3306"。
+		Addr:     utils.MYSQL_DATA_BINLOG_URL,
+		User:     utils.MYSQL_DATA_BINLOG_USER,
+		Password: utils.MYSQL_DATA_BINLOG_PWD,
+		// 如果设置为 true,Canal 将以原始二进制格式获取 binlog,否则将以解析后的 SQL 语句形式提供。
+		//RawModeEnabled:  false,
+		// 是否启用半同步复制。当设置为 true 时,MySQL 主库在事务提交后会等待至少一个从库确认已接收并写入 binlog 才返回成功,提高了数据一致性。
+		SemiSyncEnabled: false,
+		//  是否将 MySQL 中的 decimal 类型字段解析为 Go 的 Decimal 类型,而不是 float 或者 string。如果业务中有精确小数计算的需求,应开启此选项以避免精度丢失问题。
+		UseDecimal: true,
+		// 用于控制初始数据导出的相关配置,在 Canal 启动时是否需要全量同步表数据。
+		//Dump:              dumpConf,
+		// 正则表达式字符串,用于定义 Canal 应该监听哪些表的 binlog 事件。只有名称匹配该正则表达式的表才会被 Canal 同步处理。
+		IncludeTableRegex: includeTableRegex,
+	}
+
+	// 校验mysql binlog format,目前仅支持row格式
+	{
+		binlogFormat, tmpErr := binlog.GetBinlogFormat()
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		if binlogFormat.Value != "ROW" {
+			panic("mysql binlog format is not ROW")
+		}
+	}
+
+	//  获取上一次启动时的binlog文件名称和位置
+	fileName, position, err := getBinlogNamePosition()
+	if err != nil {
+		return
+	}
+	// 修改记录本次启动时的binlog文件名称和位置
+	modifyBinlogNamePosition(fileName, position)
+	// 定时修改binlog文件名称和位置
+	go timingModifyBinlogNamePosition()
+
+	c, err := canal.NewCanal(cfg)
+	if err != nil {
+		fmt.Println("err:", err)
+		return
+	}
+	utils.FileLog.Debug("记录上一次启动时的fileName:", fileName, ";position:", position)
+
+	binlogHandler := &EdbEventHandler{}
+	binlogHandler.SetBinlogFileName(fileName, position)
+	c.SetEventHandler(binlogHandler)
+	//c.Run()
+	// 同步到redis
+	go binlogHandler.SyncToRedis()
+
+	pos := mysql.Position{
+		Name: fileName,
+		Pos:  position,
+	}
+	err = c.RunFrom(pos)
+}
+
+// getBinlogNamePosition
+// @Description: 获取当前binlog文件名称和位置
+// @author: Roc
+// @datetime 2024-05-17 13:18:19
+// @return fileName string
+// @return position uint32
+// @return err error
+func getBinlogNamePosition() (fileName string, position uint32, err error) {
+	// 优先从redis获取
+	fileName = utils.Rc.GetStr(utils.CACHE_MYSQL_DATA_FILENAME)
+	position64, err := utils.Rc.GetUInt64(utils.CACHE_MYSQL_DATA_POSITION)
+	if err != nil {
+		if err.Error() != utils.RedisNoKeyErr {
+			panic("mysql binlog position is not found,err:" + err.Error())
+			return
+		}
+		err = nil
+	}
+
+	position = uint32(position64)
+
+	// 如果没有从redis中获取到上次监听到的binlog的文件名称,或者位置为0,则从mysql中获取,则从 MySQL 中获取最新的文件名和位置。
+	if fileName == `` || position == 0 {
+
+		// binlog文件名
+		fileNameKey := binlog.BinlogFileNameKey
+		fileNameLog, tmpErr := binlog.GetBusinessSysInteractionLogByKey(fileNameKey)
+		if tmpErr == nil {
+			fileName = fileNameLog.InteractionKey
+		}
+
+		// binlog位置
+		positionKey := binlog.BinlogPositionKey
+		positionLog, tmpErr := binlog.GetBusinessSysInteractionLogByKey(positionKey)
+		if tmpErr == nil {
+			positionStr := positionLog.InteractionKey
+			positionInt, tmpErr := strconv.Atoi(positionStr)
+			if tmpErr == nil {
+				position = uint32(positionInt)
+			}
+		}
+	}
+
+	// 从mysql中获取最新的binlog文件名称和位置,名称不一致则以mysql中为准
+	if fileName == `` || position == 0 {
+		item, tmpErr := binlog.GetShowMaster()
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		fileName = item.File
+		position = item.Position
+	}
+	return
+}
+
+// modifyBinlogNamePosition
+// @Description: 修改记录本次启动时的binlog文件名称和位置
+// @author: Roc
+// @datetime 2024-05-17 11:32:32
+// @param fileName string
+// @param position uint32
+// @return err error
+func modifyBinlogNamePosition(fileName string, position uint32) {
+	var err error
+	defer func() {
+		if err != nil {
+			utils.FileLog.Error("修改binlog文件名称和位置异常,fileName", fileName, ",position:", position, ",err:", err)
+		}
+	}()
+
+	// fileName 变更
+	fileNameKey := binlog.BinlogFileNameKey
+	fileNameLog, err := binlog.GetBusinessSysInteractionLogByKey(fileNameKey)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			return
+		}
+		err = nil
+		fileNameLog = &binlog.BusinessSysInteractionLog{
+			//ID:             0,
+			InteractionKey: fileNameKey,
+			InteractionVal: fileName,
+			Remark:         "mysql中binlog的filename名称",
+			ModifyTime:     time.Now(),
+			CreateTime:     time.Now(),
+		}
+		err = fileNameLog.Create()
+		if err != nil {
+			return
+		}
+	} else {
+		fileNameLog.InteractionVal = fileName
+		fileNameLog.ModifyTime = time.Now()
+		err = fileNameLog.Update([]string{"InteractionVal", "ModifyTime"})
+		if err != nil {
+			return
+		}
+	}
+
+	// position 变更
+	positionKey := binlog.BinlogPositionKey
+	positionLog, err := binlog.GetBusinessSysInteractionLogByKey(positionKey)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			return
+		}
+		err = nil
+		positionLog = &binlog.BusinessSysInteractionLog{
+			//ID:             0,
+			InteractionKey: positionKey,
+			InteractionVal: fmt.Sprint(position),
+			Remark:         "mysql中binlog的position位置",
+			ModifyTime:     time.Now(),
+			CreateTime:     time.Now(),
+		}
+		err = positionLog.Create()
+		if err != nil {
+			return
+		}
+	} else {
+		positionLog.InteractionVal = fmt.Sprint(position)
+		positionLog.ModifyTime = time.Now()
+		err = positionLog.Update([]string{"InteractionVal", "ModifyTime"})
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// timingModifyBinlogNamePosition
+// @Description: 定时修改binlog文件名称和位置
+// @author: Roc
+// @datetime 2024-05-17 13:08:13
+func timingModifyBinlogNamePosition() {
+	for {
+		// 延时30s执行
+		time.Sleep(30 * time.Second)
+
+		// 获取最新的binlog文件名称和位置
+		fileName, position, err := getBinlogNamePosition()
+		if err != nil {
+			return
+		}
+
+		if fileName != `` && position != 0 {
+			// 修改记录本次启动时的binlog文件名称和位置
+			modifyBinlogNamePosition(fileName, position)
+		}
+	}
+}

+ 203 - 0
services/binlog/handler.go

@@ -0,0 +1,203 @@
+package binlog
+
+import (
+	edbmonitorSvr "eta/eta_api/services/edb_monitor"
+	"eta/eta_api/utils"
+	"fmt"
+	"reflect"
+	"time"
+
+	"github.com/go-mysql-org/go-mysql/canal"
+	"github.com/go-mysql-org/go-mysql/mysql"
+	"github.com/go-mysql-org/go-mysql/replication"
+	"github.com/go-mysql-org/go-mysql/schema"
+)
+
+type EdbEventHandler struct {
+	canal.DummyEventHandler
+	fileName string
+	position uint32
+}
+
+func (h *EdbEventHandler) OnRow(e *canal.RowsEvent) (err error) {
+
+	// 监听逻辑
+	switch e.Action {
+	case canal.InsertAction:
+		err = h.Insert(e)
+		if err != nil {
+			utils.FileLog.Info("binlog insert error:", err)
+		}
+	case canal.UpdateAction:
+		err = h.Update(e)
+		if err != nil {
+			utils.FileLog.Info("binlog update error:", err)
+		}
+	default:
+		return nil
+	}
+
+	fmt.Println("fileName:", h.fileName, ";position:", h.position)
+
+	// 每次操作完成后都将当前位置记录到缓存
+	utils.Rc.Put(utils.CACHE_MYSQL_DATA_FILENAME, h.fileName, 31*24*time.Hour)
+	utils.Rc.Put(utils.CACHE_MYSQL_DATA_POSITION, h.position, 31*24*time.Hour)
+
+	return nil
+}
+
+func (h *EdbEventHandler) OnPosSynced(header *replication.EventHeader, p mysql.Position, set mysql.GTIDSet, f bool) error {
+	h.fileName = p.Name
+	h.position = p.Pos
+
+	return nil
+}
+
+func (h *EdbEventHandler) SyncToRedis() {
+	for {
+		// 旋转binlog日志的时候,需要将当前位置记录到缓存
+		utils.Rc.Put(utils.CACHE_MYSQL_DATA_FILENAME, h.fileName, 31*24*time.Hour)
+		utils.Rc.Put(utils.CACHE_MYSQL_DATA_POSITION, h.position, 31*24*time.Hour)
+		time.Sleep(3 * time.Second)
+	}
+}
+
+func (h *EdbEventHandler) String() string {
+	return "EdbEventHandler"
+}
+
+func (h *EdbEventHandler) Insert(e *canal.RowsEvent) error {
+	// 批量插入的时候,e.Rows的长度会大于0
+	fmt.Println(e.Header.ServerID, ";", e.Table.Schema, ".", e.Table.Name)
+	for _, row := range e.Rows { // 遍历当前插入的数据列表(存在批量插入的情况,所以是list)
+		newEdbInfo := h.MapRowToStruct(e.Table.Columns, row)
+		if ok := edbmonitorSvr.EdbLocalSet.IsExist(newEdbInfo.EdbInfoId); ok {
+			err := utils.Rc.LPush(edbmonitorSvr.EDB_MONITOR_HANDLE_LIST_CACHE, newEdbInfo)
+			if err != nil {
+				return err
+			}
+		} else {
+			ok, err := utils.Rc.SIsMember(edbmonitorSvr.EDB_MONITOR_ID_SET_CACHE, newEdbInfo)
+			if err != nil {
+				return err
+			}
+			if ok {
+				err := utils.Rc.LPush(edbmonitorSvr.EDB_MONITOR_HANDLE_LIST_CACHE, newEdbInfo)
+				if err != nil {
+					return err
+				}
+			}
+		}
+		// if monitors, ok := edbMonitorMap[newEdbInfo.EdbInfoId]; ok {
+		// 	for _, monitor := range monitors {
+		// 		err = edbmonitorSvr.ModifyEdbMonitorState(monitor, newEdbInfo.EdbCode, newEdbInfo.Source, newEdbInfo.SubSource)
+		// 		if err != nil {
+		// 			continue
+		// 		}
+		// 	}
+		// }
+	}
+	return nil
+}
+
+func (h *EdbEventHandler) Update(e *canal.RowsEvent) error {
+	if len(e.Rows) != 2 {
+		fmt.Println("更新数据异常,没有原始数据和新数据:", e.Rows)
+		return nil
+	}
+	oldEdbInfo := h.MapRowToStruct(e.Table.Columns, e.Rows[0])
+	newEdbInfo := h.MapRowToStruct(e.Table.Columns, e.Rows[1])
+	if oldEdbInfo.EndValue != newEdbInfo.EndValue {
+		if ok := edbmonitorSvr.EdbLocalSet.IsExist(newEdbInfo.EdbInfoId); ok {
+			err := utils.Rc.LPush(edbmonitorSvr.EDB_MONITOR_HANDLE_LIST_CACHE, newEdbInfo)
+			if err != nil {
+				return err
+			}
+		} else {
+			ok, err := utils.Rc.SIsMember(edbmonitorSvr.EDB_MONITOR_ID_SET_CACHE, newEdbInfo)
+			if err != nil {
+				return err
+			}
+			if ok {
+				err := utils.Rc.LPush(edbmonitorSvr.EDB_MONITOR_HANDLE_LIST_CACHE, newEdbInfo)
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+
+	// if monitors, ok := edbMonitorMap[newEdbInfo.EdbInfoId]; ok {
+	// 	for _, monitor := range monitors {
+	// 		err = edbmonitorSvr.ModifyEdbMonitorState(monitor, newEdbInfo.EdbCode, newEdbInfo.Source, newEdbInfo.SubSource)
+	// 		if err != nil {
+	// 			continue
+	// 		}
+	// 	}
+	// }
+	return nil
+}
+
+func (h *EdbEventHandler) MapRowToStruct(columns []schema.TableColumn, row []interface{}) edbmonitorSvr.EdbInfoBingLog {
+	newEdbInfo := edbmonitorSvr.EdbInfoBingLog{}
+	for i, column := range columns {
+		value := reflect.ValueOf(row[i])
+		switch column.Name {
+		case "edb_info_id":
+			newEdbInfo.EdbInfoId = int(value.Int())
+		case "edb_info_type":
+			newEdbInfo.EdbInfoType = int(value.Uint())
+		case "source":
+			newEdbInfo.Source = int(value.Int())
+		case "edb_code":
+			newEdbInfo.EdbCode = value.String()
+		case "start_date":
+			newEdbInfo.StartDate = value.String()
+		case "end_date":
+			newEdbInfo.EndDate = value.String()
+		case "unique_code":
+			newEdbInfo.UniqueCode = value.String()
+		case "create_time":
+			newEdbInfo.CreateTime = value.String()
+		case "modify_time":
+			newEdbInfo.ModifyTime = value.String()
+		case "base_modify_time":
+			if value.IsValid() {
+				newEdbInfo.BaseModifyTime = value.String()
+			}
+		case "min_value":
+			newEdbInfo.MinValue = value.Float()
+		case "max_value":
+			newEdbInfo.MaxValue = value.Float()
+		case "latest_date":
+			newEdbInfo.LatestDate = value.String()
+		case "latest_value":
+			newEdbInfo.LatestValue = value.Float()
+		case "end_value":
+			newEdbInfo.EndValue = value.Float()
+		case "data_update_time":
+			newEdbInfo.DataUpdateTime = value.String()
+		case "er_data_update_date":
+			newEdbInfo.ErDataUpdateDate = value.String()
+		case "sub_source":
+			newEdbInfo.SubSource = int(value.Int())
+		default:
+			continue
+		}
+	}
+	return newEdbInfo
+}
+
+// SetBinlogFileName
+// @Description: 设置当前的binlog文件名和位置
+// @author: Roc
+// @receiver h
+// @datetime 2024-02-29 18:09:36
+// @param fileName string
+// @param position uint32
+func (h *EdbEventHandler) SetBinlogFileName(fileName string, position uint32) {
+	h.fileName = fileName
+	h.position = position
+
+	fmt.Println("init fileName:", h.fileName, ";position:", h.position)
+}

+ 149 - 35
services/classify.go

@@ -9,6 +9,8 @@ import (
 	"fmt"
 	"sort"
 	"time"
+
+	"github.com/beego/beego/v2/core/logs"
 )
 
 // MoveReportClassify 移动分类
@@ -249,6 +251,13 @@ func AddReportClassify(classifyName string, parentId int, chartPermissionIdList
 			return
 		}
 
+		// 清除父级分类的收藏 战研2.1
+		err = models.DeleteCollectByClassifyId(parentId)
+		if err != nil {
+			errMsg = "清除父级分类的收藏失败"
+			return
+		}
+
 	}
 
 	nowTime := time.Now().Local()
@@ -276,47 +285,54 @@ func AddReportClassify(classifyName string, parentId int, chartPermissionIdList
 		return
 	}
 
-	// 如果父级分类下有报告,修改报告到子级分类下
-	reports, err := models.GetReportListByClassifyId(parentId)
+	// 如果当前分类下,没有其他分类,则将当前分类下的所有报告放入新分类下
+	count, err := models.GetClassifySubCountByParentId(parentId)
 	if err != nil {
-		return err, "查询报告列表失败", false
-	}
-	if len(reports) > 0 {
-		for _, report := range reports {
-			if report.ClassifyIdFirst == 0 {
-				report.ClassifyIdFirst = classify.Id
-				report.ClassifyNameFirst = classifyName
-			} else if report.ClassifyIdSecond == 0 {
-				report.ClassifyIdSecond = classify.Id
-				report.ClassifyNameSecond = classifyName
-			} else {
-				report.ClassifyIdThird = classify.Id
-				report.ClassifyNameThird = classifyName
-			}
+		return err, "查询分类下所有的分类记录数失败", false
+	}
+
+	if count == 1 {
+		// 如果父级分类下 无其他子分类 并且有报告,修改报告到子级分类下
+		reports, err := models.GetReportListByClassifyId(parentId)
+		if err != nil {
+			return err, "查询报告列表失败", false
+		}
+		if len(reports) > 0 {
+			for _, report := range reports {
+				// 一级分类不用判断,有报告一定有分类,二级分类如果等于0,就不用判断三级了
+				if report.ClassifyIdSecond == 0 {
+					report.ClassifyIdSecond = classify.Id
+					report.ClassifyNameSecond = classifyName
+				} else if report.ClassifyIdThird == 0 {
+					report.ClassifyIdThird = classify.Id
+					report.ClassifyNameThird = classifyName
+				}
 
-			// beego orm 不支持批量修改,所以只能一个一个修改
-			err := models.UpdateReportInfo(report)
-			if err != nil {
-				return err, "修改报告分类失败", false
+				// beego orm 不支持批量修改,所以只能一个一个修改
+				err := models.UpdateReportInfo(report)
+				if err != nil {
+					return err, "修改报告分类失败", false
+				}
 			}
 		}
-	}
-	outsideReports, err := document_manage_model.GetOutsideReportListByClassifyId(parentId)
-	if err != nil {
-		return err, "查询外部报告列表失败", false
-	}
-	if len(outsideReports) > 0 {
-		for _, report := range outsideReports {
-			tempReport := report
-
-			tempReport.ClassifyId = classify.Id
-			tempReport.ClassifyName = classifyName
-			// 修改报告
-			err := document_manage_model.UpdateOutsideReport(&tempReport)
-			if err != nil {
-				return err, "修改外部报告分类失败", false
+		outsideReports, err := document_manage_model.GetOutsideReportListByClassifyId(parentId)
+		if err != nil {
+			return err, "查询外部报告列表失败", false
+		}
+		if len(outsideReports) > 0 {
+			for _, report := range outsideReports {
+				tempReport := report
+
+				tempReport.ClassifyId = classify.Id
+				tempReport.ClassifyName = classifyName
+				// 修改报告
+				err := document_manage_model.UpdateOutsideReport(&tempReport)
+				if err != nil {
+					return err, "修改外部报告分类失败", false
+				}
 			}
 		}
+
 	}
 
 	//获取报告分类权限列表
@@ -819,3 +835,101 @@ func (a BySortAndCreateTime) Less(i, j int) bool {
 func SortClassifyListBySortAndCreateTime(classifyList []*models.ClassifyList) {
 	sort.Sort(BySortAndCreateTime(classifyList))
 }
+
+// MarkEnableDeleteClassify 标记是否可以删除分类
+func MarkEnableDeleteClassify(classifyList []*models.ClassifyList) (err error) {
+	if len(classifyList) == 0 {
+		return
+	}
+	classifyIds := make([]int, 0)
+	for _, v := range classifyList {
+		classifyIds = append(classifyIds, v.Id)
+	}
+	// 检查是否有报告
+	reportList, err := models.GetExistReportClassifyIdByClassifyIds(classifyIds)
+	if err != nil {
+		return
+	}
+
+	// 查询该分类是否关联了审批流
+	flowOb := new(report_approve.ReportApproveFlow)
+	flowCond := fmt.Sprintf(` AND %s = ? AND ( %s IN (`+utils.GetOrmInReplace(len(classifyIds))+`) OR %s IN (`+utils.GetOrmInReplace(len(classifyIds))+`) OR %s IN (`+utils.GetOrmInReplace(len(classifyIds))+`))`,
+		report_approve.ReportApproveFlowCols.ReportType,
+		report_approve.ReportApproveFlowCols.ClassifyFirstId,
+		report_approve.ReportApproveFlowCols.ClassifySecondId,
+		report_approve.ReportApproveFlowCols.ClassifyThirdId,
+	)
+	flowPars := make([]interface{}, 0)
+	flowPars = append(flowPars, report_approve.FlowReportTypeChinese, classifyIds, classifyIds, classifyIds)
+	flowList, err := flowOb.GetItemsByCondition(flowCond, flowPars, []string{"classify_first_id", "classify_second_id", "classify_third_id"}, "")
+	if err != nil {
+		return
+	}
+
+	disableDeleteClassifyMap := make(map[int]struct{})
+	// 记录关联报告的分类
+	for _, v := range reportList {
+		if v.ClassifyIdFirst > 0 {
+			disableDeleteClassifyMap[v.ClassifyIdFirst] = struct{}{}
+		}
+		if v.ClassifyIdSecond > 0 {
+			disableDeleteClassifyMap[v.ClassifyIdSecond] = struct{}{}
+		}
+		if v.ClassifyIdThird > 0 {
+			disableDeleteClassifyMap[v.ClassifyIdThird] = struct{}{}
+		}
+	}
+	// 记录关联审批流的分类
+	for _, v := range flowList {
+		if v.ClassifyFirstId > 0 {
+			disableDeleteClassifyMap[v.ClassifyFirstId] = struct{}{}
+		}
+		if v.ClassifySecondId > 0 {
+			disableDeleteClassifyMap[v.ClassifySecondId] = struct{}{}
+		}
+		if v.ClassifyThirdId > 0 {
+			disableDeleteClassifyMap[v.ClassifyThirdId] = struct{}{}
+		}
+	}
+	for _, v := range classifyList {
+		if _, ok := disableDeleteClassifyMap[v.Id]; !ok {
+			v.IsEnableDelete = 1
+		}
+	}
+
+	return
+}
+
+// DealBug6445 处理禅道bug6445,对数据进行补偿刷新
+func DealBug6445() error {
+	var condition string
+	var pars []interface{}
+	reportList, err := models.FindReportListByCondition(condition, pars)
+	if err != nil {
+		return err
+	}
+
+	for _, report := range reportList {
+		oldClassifyIdThird := report.ClassifyIdThird
+		oldClassifyNameThird := report.ClassifyNameThird
+		classifyIdList := []int{report.ClassifyIdSecond, report.ClassifyIdThird}
+
+		// 判断当前分类id的父id是否一样,如果系统则将3级分类置为0
+		classifies, err := models.GetClassifyListByIdList(classifyIdList)
+		if err != nil {
+			return err
+		}
+		if len(classifies) >= 2 {
+			if classifies[0].ParentId == classifies[1].ParentId && classifies[0].ParentId != 0 {
+				report.ClassifyIdThird = 0
+				report.ClassifyNameThird = ""
+				err := report.UpdateReport([]string{"classify_id_third", "classify_name_third"})
+				if err != nil {
+					return err
+				}
+				logs.Info("update report id: %d, classify_id_third: %d, classify_name_third: %s", report.Id, oldClassifyIdThird, oldClassifyNameThird)
+			}
+		}
+	}
+	return nil
+}

+ 49 - 0
services/data/base_from_ccf.go

@@ -0,0 +1,49 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+)
+
+// CCFIndexSource2Edb 新增CCF数据源到指标库
+func CCFIndexSource2Edb(req data_manage.CCFIndexSource2EdbReq, lang string) (edb *data_manage.EdbInfo, err error, errMsg string, skip bool) {
+	if req.EdbCode == "" {
+		err = fmt.Errorf("指标ID为空")
+		return
+	}
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("CCFIndexSource2Edb新增失败, Err: %s", err.Error())
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+		}
+	}()
+	source := utils.DATA_SOURCE_CCF
+
+	// 是否新增过指标
+	exist, e := data_manage.GetEdbInfoByEdbCode(source, req.EdbCode)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("获取指标是否存在失败, err: %s", e.Error())
+		return
+	}
+	if exist != nil {
+		skip = true
+		return
+	}
+
+	// 开始结束时间
+	var startDate, endDate string
+
+	// 新增指标库
+	edbInfo, e, msg, _ := EdbInfoAdd(source, utils.DATA_SUB_SOURCE_EDB, req.ClassifyId, req.EdbCode, req.EdbName, req.Frequency, req.Unit, startDate, endDate, req.AdminId, req.AdminRealName, lang)
+	if e != nil {
+		errMsg = msg
+		err = fmt.Errorf("EdbInfo: 新增指标失败, err: %s", e.Error())
+		return
+	}
+
+	edb = edbInfo
+
+	return
+}

+ 56 - 3
services/data/chart_classify.go

@@ -995,7 +995,7 @@ func EditChartClassifyV2(chartClassifyId, praentId, source int, chartClassifyNam
 			err = e
 			return
 		}
-		if classifyInfo.Level != parentClassifyInfo.Level - 1 {
+		if classifyInfo.Level != parentClassifyInfo.Level-1 {
 			err = errors.New("父级分类层级异常")
 		}
 	}
@@ -1008,7 +1008,6 @@ func EditChartClassifyV2(chartClassifyId, praentId, source int, chartClassifyNam
 		return
 	}
 
-
 	// 需要变更的字段
 	updateCols := make([]string, 0)
 
@@ -1127,4 +1126,58 @@ func GetChartClassifyChildrenRecursiveByParentIds(list []*data_manage.ChartClass
 		}
 	}
 	return res
-}
+}
+
+func GetChartClassifyByIsMe(adminId, parentId, source int, classifyList []*data_manage.ChartClassifyItems) (list []*data_manage.ChartClassifyItems, err error) {
+	chartInfoList, err := data_manage.GetChartInfoByAdminId([]int{source}, adminId)
+	if err != nil {
+		return
+	}
+	classifyIdList := make([]int, 0)
+	for _, chartInfo := range chartInfoList {
+		if chartInfo.ChartClassifyId > 0 {
+			classifyIdList = append(classifyIdList, chartInfo.ChartClassifyId)
+		}
+	}
+	if parentId > 0 {
+		for _, v := range classifyList {
+			if v.ChartClassifyId > 0 && v.ChartInfoId == 0 {
+				classifyItems, er, _ := GetChildChartClassifyByClassifyId(v.ChartClassifyId)
+				if er != nil {
+					err = er
+					return
+				}
+				existClassifyMap := make(map[int]struct{})
+				for _, classify := range classifyItems {
+					existClassifyMap[classify.ChartClassifyId] = struct{}{}
+				}
+				for _, chart := range chartInfoList {
+					if _, ok := existClassifyMap[chart.ChartClassifyId]; ok {
+						list = append(list, v)
+						break
+					}
+				}
+			} else {
+				list = append(list, v)
+			}
+		}
+	} else {
+		chartClassifyList, er := data_manage.GetChartClassifyByIdList(classifyIdList)
+		if er != nil {
+			err = er
+			return
+		}
+
+		existClassifyIdMap := make(map[int]struct{})
+		for _, classify := range chartClassifyList {
+			existClassifyIdMap[classify.RootId] = struct{}{}
+		}
+
+		for _, classify := range classifyList {
+			if _, ok := existClassifyIdMap[classify.ChartClassifyId]; ok {
+				list = append(list, classify)
+			}
+		}
+	}
+	return
+}

+ 4 - 0
services/data/chart_info.go

@@ -1637,6 +1637,8 @@ func BatchChartInfoRefreshV2(chartInfoList []*data_manage.ChartInfo, redisKey st
 		for _, v := range chartInfoList {
 			key := utils.HZ_CHART_LIB_DETAIL + v.UniqueCode
 			refreshItem.ItemRefreshKeys = append(refreshItem.ItemRefreshKeys, key)
+			// eta平台的缓存,用于Ppt等地方的展示
+			refreshItem.ItemRefreshKeys = append(refreshItem.ItemRefreshKeys, GetChartInfoDataKey(v.ChartInfoId))
 		}
 		refreshItem.BaseEdbInfoArr = newBaseEdbInfoArr
 		refreshItem.BasePredictEdbInfoArr = newBasePredictEdbInfoArr
@@ -1652,6 +1654,8 @@ func BatchChartInfoRefreshV2(chartInfoList []*data_manage.ChartInfo, redisKey st
 		for _, v := range chartInfoList {
 			key := utils.HZ_CHART_LIB_DETAIL + v.UniqueCode
 			_ = utils.Rc.Delete(key)
+			// eta平台的缓存,用于Ppt等地方的展示
+			_ = utils.Rc.Delete(GetChartInfoDataKey(v.ChartInfoId))
 		}
 	}
 

+ 5 - 5
services/data/chart_info_excel_balance.go

@@ -634,7 +634,7 @@ func GetBalanceExcelChartDetail(chartInfo *data_manage.ChartInfoView, mappingLis
 			dateType = 3
 		}
 	}
-	yearMax := 0
+	var dateMax time.Time
 	if dateType == utils.DateTypeNYears {
 		for _, v := range mappingList {
 			if v.LatestDate != "" {
@@ -644,13 +644,13 @@ func GetBalanceExcelChartDetail(chartInfo *data_manage.ChartInfoView, mappingLis
 					err = fmt.Errorf("获取图表日期信息失败,Err:" + tErr.Error())
 					return
 				}
-				if lastDateT.Year() > yearMax {
-					yearMax = lastDateT.Year()
+				if lastDateT.After(dateMax) {
+					dateMax = lastDateT
 				}
 			}
 		}
 	}
-	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, dateMax)
 
 	if chartInfo.ChartType == 2 {
 		chartInfo.StartDate = startDate
@@ -1011,7 +1011,7 @@ func GetBalanceExcelEdbDataMapList(chartInfoId, chartType int, calendar, startDa
 			var rightAxisDate time.Time
 			if jumpYear == 1 {
 				latestDate = latestDate.AddDate(-1, 0, 0)
-				latestDateStr := fmt.Sprintf("%d-%s", latestDate.Year(),xStartDate)
+				latestDateStr := fmt.Sprintf("%d-%s", latestDate.Year(), xStartDate)
 				rightAxisDate, err = time.Parse(utils.FormatDate, latestDateStr)
 				if err != nil {
 					return

+ 110 - 0
services/data/correlation/correlation_chart_classify.go

@@ -0,0 +1,110 @@
+package correlation
+
+import (
+	"errors"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+)
+
+func GetCorrelationClassifyByIsMe(adminId, parentId, source int, classifyList []*data_manage.ChartClassifyItems) (list []*data_manage.ChartClassifyItems, err error) {
+	chartInfoList, err := data_manage.GetChartInfoByAdminId([]int{source}, adminId)
+	if err != nil {
+		return
+	}
+	classifyIdList := make([]int, 0)
+	for _, chartInfo := range chartInfoList {
+		if chartInfo.ChartClassifyId > 0 {
+			classifyIdList = append(classifyIdList, chartInfo.ChartClassifyId)
+		}
+	}
+	if parentId > 0 {
+		for _, v := range classifyList {
+			if v.ChartClassifyId > 0 && v.ChartInfoId == 0 {
+				classifyItems, _, er := GetChildClassifyByClassifyId(v.ChartClassifyId)
+				if er != nil {
+					err = er
+					return
+				}
+				existClassifyMap := make(map[int]struct{})
+				for _, classify := range classifyItems {
+					existClassifyMap[classify.ChartClassifyId] = struct{}{}
+				}
+				for _, chart := range chartInfoList {
+					if _, ok := existClassifyMap[chart.ChartClassifyId]; ok {
+						list = append(list, v)
+						break
+					}
+				}
+			} else {
+				list = append(list, v)
+			}
+		}
+	} else {
+		chartClassifyList, er := data_manage.GetChartClassifyByIdList(classifyIdList)
+		if er != nil {
+			err = er
+			return
+		}
+
+		existClassifyIdMap := make(map[int]struct{})
+		for _, classify := range chartClassifyList {
+			existClassifyIdMap[classify.RootId] = struct{}{}
+		}
+
+		for _, classify := range classifyList {
+			if _, ok := existClassifyIdMap[classify.ChartClassifyId]; ok {
+				list = append(list, classify)
+			}
+		}
+	}
+	return
+}
+
+func GetChildClassifyByClassifyId(targetClassifyId int) (targetList []*data_manage.ChartClassifyItems, errMsg string, err error) {
+	//判断是否是挂在顶级目录下
+	targetClassify, err := data_manage.GetChartClassifyById(targetClassifyId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前分类不存在"
+			err = errors.New(errMsg)
+			return
+		}
+		errMsg = "获取失败"
+		err = errors.New("获取分类信息失败,Err:" + err.Error())
+		return
+	}
+	orderStr := ` order by level asc, sort asc, classify_id asc`
+	tmpList, err := data_manage.GetChartClassifyByRootIdLevel(targetClassify.RootId, targetClassify.Source, orderStr)
+	if err != nil {
+		errMsg = "获取失败"
+		err = errors.New("获取数据失败,Err:" + err.Error())
+		return
+	}
+	idMap := make(map[int]struct{})
+	if len(tmpList) > 0 {
+		for _, v := range tmpList {
+			if v.ChartClassifyId == targetClassify.ChartClassifyId {
+				idMap[v.ChartClassifyId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ParentId]; ok {
+				idMap[v.ChartClassifyId] = struct{}{}
+			}
+		}
+		for _, v := range tmpList {
+			if _, ok := idMap[v.ChartClassifyId]; ok {
+				targetItem := new(data_manage.ChartClassifyItems)
+				targetItem.ChartClassifyId = v.ChartClassifyId
+				targetItem.ParentId = v.ParentId
+				targetItem.UniqueCode = v.UniqueCode
+				targetItem.Level = v.Level
+				targetItem.ChartClassifyName = v.ChartClassifyName
+				targetItem.IsJoinPermission = v.IsJoinPermission
+				targetList = append(targetList, targetItem)
+			}
+		}
+	}
+
+	return
+}

+ 54 - 0
services/data/edb_classify.go

@@ -1570,3 +1570,57 @@ func GetEdbClassifyMaxSort(parentId int, classifyType uint8) (maxSort int, err e
 	}
 	return
 }
+
+func GetEdbClassifyByIsMe(adminId, parentId, edbInfoType int, classifyList []*data_manage.EdbClassifyItems) (list []*data_manage.EdbClassifyItems, err error) {
+	edbInfoList, err := data_manage.GetEdbInfoListByUserId([]int{adminId}, edbInfoType)
+	if err != nil {
+		return
+	}
+	classifyIdList := make([]int, 0)
+	for _, edbInfo := range edbInfoList {
+		if edbInfo.ClassifyId > 0 {
+			classifyIdList = append(classifyIdList, edbInfo.ClassifyId)
+		}
+	}
+	if parentId > 0 {
+		for _, v := range classifyList {
+			if v.ClassifyId > 0 && v.EdbInfoId == 0 {
+				classifyItems, er, _ := GetChildClassifyByClassifyId(v.ClassifyId)
+				if er != nil {
+					err = er
+					return
+				}
+				existClassifyMap := make(map[int]struct{})
+				for _, classify := range classifyItems {
+					existClassifyMap[classify.ClassifyId] = struct{}{}
+				}
+				for _, edb := range edbInfoList {
+					if _, ok := existClassifyMap[edb.ClassifyId]; ok {
+						list = append(list, v)
+						break
+					}
+				}
+			} else {
+				list = append(list, v)
+			}
+		}
+	} else {
+		edbInfoClassifyList, er := data_manage.GetEdbClassifyByIdList(classifyIdList)
+		if er != nil {
+			err = er
+			return
+		}
+
+		existClassifyIdMap := make(map[int]struct{})
+		for _, classify := range edbInfoClassifyList {
+			existClassifyIdMap[classify.RootId] = struct{}{}
+		}
+
+		for _, classify := range classifyList {
+			if _, ok := existClassifyIdMap[classify.ClassifyId]; ok {
+				list = append(list, classify)
+			}
+		}
+	}
+	return
+}

+ 136 - 4
services/data/edb_info.go

@@ -46,7 +46,6 @@ func EdbInfoRefreshAllFromBaseV3Bak(edbInfoIdList []int, refreshAll, isSync bool
 		if err != nil {
 			fmt.Println("EdbInfoRefreshAllFromBaseV2 Err:" + err.Error() + ";errmsg:" + errmsg)
 			go alarm_msg.SendAlarmMsg("EdbInfoRefreshFromBaseV2,Err"+err.Error()+";errMsg:"+errmsg, 3)
-			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "EdbInfoRefreshFromBase:"+errmsg, utils.EmailSendToUsers)
 		}
 	}()
 
@@ -237,7 +236,7 @@ func getRefreshEdbInfoListByTraceEdbInfo(traceEdbInfo data_manage.TraceEdbInfoRe
 		}
 	}
 
-	if traceEdbInfo.Child != nil && len(traceEdbInfo.Child) > 0 {
+	if len(traceEdbInfo.Child) > 0 {
 		for _, v := range traceEdbInfo.Child {
 			tmpBaseEdbInfoArr, tmpPredictEdbInfoArr, tmpCalculateMap, tmpPredictCalculateMap, tmpCalculateArr, tmpPredictCalculateArr := getRefreshEdbInfoListByTraceEdbInfo(v, existEdbInfoIdMap)
 
@@ -2226,7 +2225,7 @@ func getEdbRuleTitle(edbInfo, parentEdbInfo *data_manage.EdbInfo, childList []da
 	// 规则
 	switch edbInfo.Source {
 	case utils.DATA_SOURCE_CALCULATE, utils.DATA_SOURCE_PREDICT_CALCULATE:
-		ruleTitle = "=" + edbInfo.CalculateFormula
+		ruleTitle = formatCalculateFormula(edbInfo.CalculateFormula)
 	case utils.DATA_SOURCE_CALCULATE_LJZZY, utils.DATA_SOURCE_PREDICT_CALCULATE_LJZZY:
 		ruleTitle = `累计转月值计算`
 		ruleTitleEn = `Cumulative to Monthly Calculation`
@@ -2260,7 +2259,6 @@ func getEdbRuleTitle(edbInfo, parentEdbInfo *data_manage.EdbInfo, childList []da
 			if childEdbInfo, ok := edbInfoMap[childList[0].EdbInfoId]; ok {
 				childFrequency = childEdbInfo.Frequency
 			}
-
 		}
 		ruleTitle = fmt.Sprintf("升频计算(%s转%s)", childFrequency, edbInfo.Frequency)
 		ruleTitleEn = fmt.Sprintf("Upsampling Calculation(%s转%s)", childFrequency, edbInfo.Frequency)
@@ -2398,6 +2396,73 @@ func getEdbRuleTitle(edbInfo, parentEdbInfo *data_manage.EdbInfo, childList []da
 	return
 }
 
+func formatCalculateFormula(calculateFormula string) (ruleTitle string) {
+	var tmpCalculateFormula []map[string]string
+	if e := json.Unmarshal([]byte(calculateFormula), &tmpCalculateFormula); e != nil {
+		ruleTitle = "=" + calculateFormula
+		return
+	}
+	newCalculateFormula := make([]map[string]string, 0)
+	sort.Slice(tmpCalculateFormula, func(i, j int) bool {
+		return compareDates(tmpCalculateFormula[i]["d"], tmpCalculateFormula[j]["d"])
+	})
+
+	for i, entry := range tmpCalculateFormula {
+		if formula, ok := entry["f"]; ok {
+			singleFormula := make(map[string]string)
+			singleFormula["公式"] = formula
+			singleFormula["日期"] = determineDateRange(i, len(tmpCalculateFormula), tmpCalculateFormula)
+			newCalculateFormula = append(newCalculateFormula, singleFormula)
+		}
+
+	}
+	if b, e := json.Marshal(newCalculateFormula); e != nil {
+		ruleTitle = "=" + calculateFormula
+	} else {
+		ruleTitle = "=" + string(b)
+	}
+	return
+}
+
+// compareDates 日期比较 date1 < date2 --> true
+func compareDates(date1, date2 string) bool {
+	if date1 == "" {
+		return true
+	}
+	if date2 == "" {
+		return false
+	}
+
+	date1Parsed, err := time.Parse(utils.FormatDate, date1)
+	if err != nil {
+		return false
+	}
+	date2Parsed, err := time.Parse(utils.FormatDate, date2)
+	if err != nil {
+		return false
+	}
+
+	return date1Parsed.Before(date2Parsed)
+}
+
+func determineDateRange(index, totalLength int, formulas []map[string]string) string {
+	if totalLength == 1 {
+		return "全部"
+	}
+
+	currentDate := formulas[index]["d"]
+	if index == 0 {
+		return formulas[totalLength-1]["d"] + "(含)之后"
+	}
+	if index == totalLength-1 {
+		return formulas[1]["d"] + "之前"
+	}
+	if index >= 1 && index < totalLength-1 {
+		return fmt.Sprintf("%s(含)——%s", currentDate, formulas[index+1]["d"])
+	}
+	return ""
+}
+
 // GetEdbChartAdminList
 // @param source 来源 :1:手工数据指标 2:钢联化工数据库 3:ETA指标库 4:ETA预测指标 5:图库 6:ETA表格
 func GetEdbChartAdminList(source int) (list []int, err error) {
@@ -3123,3 +3188,70 @@ func GetIsSupplierStop(source int, edbCode string) (isSupplierStop int) {
 
 	return
 }
+
+// GetMySteelSourceByEdbCode
+// @Description: 根据钢联的指标编码,获取该数据应该从哪个数据源查询
+// @author: Roc
+// @datetime 2024-09-10 13:25:07
+// @param edbCode string
+// @return source int
+// @return item *data_manage.EdbInfo
+// @return err error
+func GetMySteelSourceByEdbCode(edbCode string) (source int, item *data_manage.EdbInfo, err error) {
+	// 先判断在指标库的“上海钢联”中是否存在,存在就直接返回
+	source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
+	item, err = data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_MYSTEEL_CHEMICAL, edbCode)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			return
+		}
+		err = nil
+	}
+	if item != nil {
+		source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
+		return
+	}
+
+	// 再判断在指标库的“钢联原始”中是否存在,存在就直接返回
+	item, err = data_manage.GetEdbInfoByEdbCode(utils.DATA_SOURCE_GL, edbCode)
+	if err != nil {
+		if err.Error() != utils.ErrNoRow() {
+			return
+		}
+		err = nil
+	}
+	if item != nil {
+		source = utils.DATA_SOURCE_GL
+		return
+	}
+
+	// 再没有就判断下是否处于 《上海钢联》 数据源里面
+	{
+		tmpInfo, tmpErr := data_manage.GetBaseFromMysteelChemicalIndexByCode(edbCode)
+		if tmpErr != nil {
+			if tmpErr.Error() != utils.ErrNoRow() {
+				err = tmpErr
+				return
+			}
+		}
+		if tmpInfo != nil {
+			source = utils.DATA_SOURCE_MYSTEEL_CHEMICAL
+		}
+	}
+
+	// 再没有就判断下是否处于 《钢联原始》 数据源里面
+	{
+		tmpInfo, tmpErr := data_manage.GetGlIndexByCode(edbCode)
+		if tmpErr != nil {
+			if tmpErr.Error() != utils.ErrNoRow() {
+				err = tmpErr
+				return
+			}
+		}
+		if tmpInfo != nil {
+			source = utils.DATA_SOURCE_GL
+		}
+	}
+
+	return
+}

+ 46 - 0
services/data/edb_info_relation.go

@@ -707,3 +707,49 @@ func GetCalculateEdbByFromEdbInfo(edbInfoIds []int, calculateEdbIds []int, hasFi
 
 	return
 }
+
+// 查询两个指标是否存在循环引用关系
+func CheckTwoEdbInfoRelation(edbInfoA, edbInfoB *data_manage.EdbInfo) (hasRelation bool, err error) {
+	//查询指标信息
+	allEdbMappingMap := make(map[int][]*data_manage.EdbInfoCalculateMappingInfo, 0)
+	allMappingList, e := data_manage.GetEdbInfoCalculateMappingListByEdbInfoId(edbInfoA.EdbInfoId)
+	if e != nil {
+		err = fmt.Errorf("GetEdbInfoCalculateMappingListByEdbInfoIds err: %s", e.Error())
+		return
+	}
+	for _, v := range allMappingList {
+		if v.EdbInfoId == edbInfoB.EdbInfoId {
+			hasRelation = true
+			return
+		}
+		if _, ok := allEdbMappingMap[v.EdbInfoId]; !ok {
+			allEdbMappingMap[v.EdbInfoId] = make([]*data_manage.EdbInfoCalculateMappingInfo, 0)
+		}
+		allEdbMappingMap[v.EdbInfoId] = append(allEdbMappingMap[v.EdbInfoId], v)
+	}
+	//查询指标映射
+	//查询所有指标数据
+	//查询这个指标相关的mapping信息放到数组里,
+	//将得到的指标ID信息放到数组里
+	hasFindMap := make(map[int]struct{})
+	edbInfoIdMap := make(map[int]struct{})
+	edbMappingList := make([]*data_manage.EdbInfoCalculateMapping, 0)
+	edbInfoMappingRootIdsMap := make(map[int][]int, 0)
+	edbMappingMap := make(map[int]struct{})
+
+	if edbInfoA.EdbType == 2 {
+		edbInfoId := edbInfoA.EdbInfoId
+		edbMappingList, err = getCalculateEdbInfoByEdbInfoId(allEdbMappingMap, edbInfoId, hasFindMap, edbInfoIdMap, edbMappingList, edbMappingMap, edbInfoMappingRootIdsMap, edbInfoId)
+		if err != nil {
+			err = fmt.Errorf(" GetCalculateEdbInfoByEdbInfoId err: %s", err.Error())
+			return
+		}
+		// 判断其中是否包含指标B
+		if _, ok := edbInfoIdMap[edbInfoB.EdbInfoId]; ok { // 如果包含,则说明存在循环引用关系
+			hasRelation = true
+			return
+		}
+	}
+
+	return
+}

Some files were not shown because too many files changed in this diff