Jelajahi Sumber

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

zqbao 10 bulan lalu
induk
melakukan
5ba3a144f4
100 mengubah file dengan 7670 tambahan dan 1838 penghapusan
  1. 1 2
      .gitignore
  2. 22 0
      cache/replace_edb_info.go
  3. 10 1
      controllers/ai/ai_file.go
  4. 18 2
      controllers/data_manage/chart_info.go
  5. 4 0
      controllers/data_manage/chart_theme.go
  6. 9 2
      controllers/data_manage/edb_classify.go
  7. 90 40
      controllers/data_manage/edb_info.go
  8. 8 2
      controllers/data_manage/edb_info_calculate.go
  9. 85 1
      controllers/data_manage/edb_info_refresh.go
  10. 18 2
      controllers/data_manage/excel/excel_info.go
  11. 6 0
      controllers/data_manage/future_good/future_good_chart_info.go
  12. 3 2
      controllers/data_manage/predict_edb_classify.go
  13. 13 2
      controllers/data_manage/predict_edb_info.go
  14. 6 2
      controllers/data_source/icpi.go
  15. 6 7
      controllers/english_report/report.go
  16. 2 0
      controllers/fe_calendar/fe_calendar_matter.go
  17. 1 1
      controllers/ppt_v2.go
  18. 268 723
      controllers/report.go
  19. 47 2
      controllers/report_approve/report_approve.go
  20. 1 1
      controllers/report_author.go
  21. 1019 0
      controllers/report_chapter.go
  22. 43 61
      controllers/report_chapter_type.go
  23. 1262 0
      controllers/report_v2.go
  24. 35 6
      controllers/sandbox/sandbox.go
  25. 7 8
      controllers/smart_report/smart_report.go
  26. 3 3
      controllers/sys_team.go
  27. 41 6
      controllers/target.go
  28. 1 1
      go.mod
  29. 2 3
      go.sum
  30. 1 2
      models/business_conf.go
  31. 29 0
      models/chart_permission.go
  32. 3 2
      models/data_manage/base_from_trade_index.go
  33. 9 0
      models/data_manage/chart_edb_mapping.go
  34. 105 75
      models/data_manage/chart_info.go
  35. 16 0
      models/data_manage/cross_variety/chart_info_cross_variety.go
  36. 11 0
      models/data_manage/cross_variety/chart_tag_variety.go
  37. 13 3
      models/data_manage/edb_classify.go
  38. 15 5
      models/data_manage/edb_data_base.go
  39. 32 0
      models/data_manage/edb_data_wind.go
  40. 161 4
      models/data_manage/edb_info.go
  41. 2 0
      models/data_manage/edb_info_calculate.go
  42. 28 0
      models/data_manage/edb_info_record.go
  43. 107 0
      models/data_manage/edb_info_relation.go
  44. 7 0
      models/data_manage/edb_refresh/request/edb_info_refresh.go
  45. 23 2
      models/data_manage/excel/excel_edb_mapping.go
  46. 74 5
      models/data_manage/excel/excel_info.go
  47. 10 0
      models/data_manage/excel/request/excel_info.go
  48. 40 0
      models/data_manage/excel/request/time_table.go
  49. 126 0
      models/data_manage/multiple_graph_config.go
  50. 136 0
      models/data_manage/multiple_graph_config_chart_mapping.go
  51. 10 10
      models/data_manage/my_chart.go
  52. 46 0
      models/data_manage/mysteel_chemical_index.go
  53. 19 11
      models/db.go
  54. 2 0
      models/english_report.go
  55. 3 3
      models/ppt_v2.go
  56. 306 76
      models/report.go
  57. 110 0
      models/report/report_chapter_grant.go
  58. 93 0
      models/report/report_chapter_permission_mapping.go
  59. 126 0
      models/report/report_grant.go
  60. 6 1
      models/report_approve/report_approve.go
  61. 3 0
      models/report_approve/report_approve_flow.go
  62. 39 0
      models/report_approve/report_approve_record.go
  63. 231 29
      models/report_chapter.go
  64. 17 2
      models/report_chapter_type.go
  65. 47 22
      models/report_chapter_type_permission.go
  66. 66 0
      models/report_grant.go
  67. 359 0
      models/report_v2.go
  68. 54 0
      models/sandbox/sandbox.go
  69. 12 5
      models/sandbox/sandbox_classify.go
  70. 19 0
      models/system/sys_admin.go
  71. 69 15
      routers/commentsRouter.go
  72. 20 12
      routers/router.go
  73. 34 12
      services/data/chart_info.go
  74. 4 0
      services/data/correlation/chart_info.go
  75. 9 3
      services/data/cross_variety/chart.go
  76. 88 16
      services/data/edb_classify.go
  77. 30 18
      services/data/edb_info.go
  78. 0 287
      services/data/edb_info_calculate.go
  79. 30 0
      services/data/edb_info_record.go
  80. 242 0
      services/data/edb_info_relation.go
  81. 105 0
      services/data/edb_refresh.go
  82. 4 4
      services/data/excel/balance_table.go
  83. 2 2
      services/data/excel/excel_info.go
  84. 5 0
      services/data/line_equation/chart_info.go
  85. 5 1
      services/data/line_feature/chart_info.go
  86. 254 0
      services/edb_info_replace.go
  87. 1 0
      services/elastic.go
  88. 31 35
      services/excel/lucky_sheet.go
  89. 52 10
      services/ppt.go
  90. 47 196
      services/report.go
  91. 37 9
      services/report_approve.go
  92. 169 0
      services/report_chapter.go
  93. 0 59
      services/report_push.go
  94. 742 0
      services/report_v2.go
  95. 106 0
      services/sandbox/sandbox.go
  96. 2 0
      services/smart_report.go
  97. 5 2
      services/task.go
  98. 19 18
      services/user_login.go
  99. 3 1
      services/video.go
  100. 8 1
      static/ErrMsgConfig.json

+ 1 - 2
.gitignore

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

+ 22 - 0
cache/replace_edb_info.go

@@ -0,0 +1,22 @@
+package cache
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+)
+
+// 将替换指标操作加入到队列中
+func AddReplaceEdbInfo(oldEdbInfo, newEdbInfo *data_manage.EdbInfo) bool {
+	record := new(data_manage.ReplaceEdbInfoItem)
+	record.OldEdbInfo = oldEdbInfo
+	record.NewEdbInfo = newEdbInfo
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_KEY_REPLACE_EDB, record)
+		if err != nil {
+			fmt.Println("AddReplaceEdbInfo LPush Err:" + err.Error())
+		}
+		return true
+	}
+	return false
+}

+ 10 - 1
controllers/ai/ai_file.go

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

+ 18 - 2
controllers/data_manage/chart_info.go

@@ -2940,6 +2940,14 @@ func (this *EdbInfoController) BatchChartInfoRefresh() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+	if req.Source == "" {
+		br.Msg = "刷新来源有误"
+		return
+	}
+	if req.PrimaryId <= 0 {
+		br.Msg = "刷新对象有误"
+		return
+	}
 
 	//获取所有的图表列表
 	_, chartInfoList, err := data_manage.GetChartInfoListByUniqueCodeSlice(req.ChartInfoCode)
@@ -2950,7 +2958,7 @@ func (this *EdbInfoController) BatchChartInfoRefresh() {
 		return
 	}
 
-	redisKey := data.GetBatchChartRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+	redisKey := data.GetBatchChartRefreshKey(req.Source, req.PrimaryId, req.SubId)
 
 	// 图表中的指标刷新
 	err, isAsync := data.BatchChartInfoRefreshV2(chartInfoList, redisKey)
@@ -3462,9 +3470,17 @@ func (this *EdbInfoController) GetBatchChartRefreshResult() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+	if req.Source == "" {
+		br.Msg = "刷新来源有误"
+		return
+	}
+	if req.PrimaryId <= 0 {
+		br.Msg = "刷新对象有误"
+		return
+	}
 
 	// 刷新结果,默认是刷新完成了
-	refreshResult := data.CheckBatchChartRefreshResult(req.Source, req.ReportId, req.ReportChapterId)
+	refreshResult := data.CheckBatchChartRefreshResult(req.Source, req.PrimaryId, req.SubId)
 
 	resp := response.ChartRefreshResp{
 		RefreshResult: refreshResult,

+ 4 - 0
controllers/data_manage/chart_theme.go

@@ -133,6 +133,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 	chartInfo := new(data_manage.ChartInfoView)
 	// 图表额外数据参数
 	extraConfigStr := ``
+	var barConfig data_manage.BarChartInfoReq
 
 	// 开始时间,结束时间
 	var tmpStartDate, tmpEndDate string
@@ -161,6 +162,8 @@ func (c *ChartThemeController) GetThemePreviewData() {
 		chartInfo.ChartName = "散点图"
 	case 7: // 柱形图
 		edbInfoIdList = []int{1, 2, 3, 4, 5}
+		chartInfo.LeftMin = "260"
+		chartInfo.LeftMax = "430"
 		extraConfigStr = `{"EdbInfoIdList":[{"EdbInfoId":1,"Name":"指标1","NameEn":"","Source":0},{"EdbInfoId":2,"Name":"指标2","NameEn":"","Source":0},{"EdbInfoId":3,"Name":"指标3","NameEn":"","Source":0},{"EdbInfoId":4,"Name":"指标4","NameEn":"","Source":0},{"EdbInfoId":5,"Name":"指标5","NameEn":"","Source":0}],"DateList":[{"Type":2,"Date":"","Value":100,"Color":"","Name":""},{"Type":1,"Date":"","Value":0,"Color":"","Name":""}],"Sort":{"Sort":0,"DateIndex":0},"XEdbList":null,"YEdbList":null,"Unit":"千桶","UnitEn":""}`
 		chartInfo.ChartName = "柱形图"
 	case 10: // 截面散点图
@@ -246,6 +249,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 	resp.XEdbIdValue = xEdbIdValue
 	resp.YDataList = yDataList
 	resp.DataResp = dataResp
+	resp.BarChartInfo = barConfig
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 9 - 2
controllers/data_manage/edb_classify.go

@@ -356,7 +356,7 @@ func (this *EdbClassifyController) DeleteEdbClassifyCheck() {
 		br.IsSendEmail = false
 		return
 	}
-	deleteStatus, tipsMsg, err, errMsg := data.DeleteCheck(req.ClassifyId, req.EdbInfoId, this.SysUser)
+	deleteStatus, tipsMsg, tableList, err, errMsg := data.DeleteCheck(req.ClassifyId, req.EdbInfoId, this.SysUser)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -367,6 +367,12 @@ func (this *EdbClassifyController) DeleteEdbClassifyCheck() {
 		}
 		return
 	}
+	if this.Lang == "en" {
+		if utils.ViperConfig.InConfig(tipsMsg) {
+			tipsMsg = utils.ViperConfig.GetString(tipsMsg)
+		}
+	}
+
 	//var deleteStatus int
 	//var tipsMsg string
 	////删除分类
@@ -429,6 +435,7 @@ func (this *EdbClassifyController) DeleteEdbClassifyCheck() {
 	resp := new(data_manage.ClassifyDeleteCheckResp)
 	resp.DeleteStatus = deleteStatus
 	resp.TipsMsg = tipsMsg
+	resp.TableList = tableList
 	br.Ret = 200
 	br.Msg = "检测成功"
 	br.Success = true
@@ -467,7 +474,7 @@ func (this *EdbClassifyController) DeleteEdbClassify() {
 		return
 	}
 
-	nextItem, err, errMsg := data.Delete(req.ClassifyId, req.EdbInfoId, sysUser, string(this.Ctx.Input.RequestBody), this.Ctx.Input.URI())
+	nextItem, _, err, errMsg := data.Delete(req.ClassifyId, req.EdbInfoId, sysUser, string(this.Ctx.Input.RequestBody), this.Ctx.Input.URI())
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg

+ 90 - 40
controllers/data_manage/edb_info.go

@@ -2,10 +2,12 @@ package data_manage
 
 import (
 	"encoding/json"
+	"eta/eta_api/cache"
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/company"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/cross_variety"
 	request2 "eta/eta_api/models/data_manage/excel/request"
 	"eta/eta_api/models/data_manage/request"
 	"eta/eta_api/models/data_manage/response"
@@ -2431,6 +2433,11 @@ func (this *EdbInfoController) EdbInfoEdit() {
 		return
 	}
 
+	// 记录旧的指标基本信息
+	oldEdbName := edbInfo.EdbName
+	oldFrequency := edbInfo.Frequency
+	oldUnit := edbInfo.Unit
+
 	var haveOperaAuth bool
 	// 权限校验
 	{
@@ -2524,6 +2531,20 @@ func (this *EdbInfoController) EdbInfoEdit() {
 	//	}
 	//}
 
+	// 新增保存记录日志
+	oldEdbInfo := new(data_manage.EdbInfo)
+	oldEdbInfo.EdbInfoId = edbInfo.EdbInfoId
+	oldEdbInfo.EdbName = oldEdbName
+	oldEdbInfo.Frequency = oldFrequency
+	oldEdbInfo.Unit = oldUnit
+	newEdbInfoRecord := new(data_manage.EdbInfoEditRecord)
+	newEdbInfoRecord.EdbName = req.EdbName
+	newEdbInfoRecord.Frequency = req.Frequency
+	newEdbInfoRecord.Unit = req.Unit
+	newEdbInfoRecord.OperateUserId = sysUser.AdminId
+	newEdbInfoRecord.OperateUserRealName = sysUser.RealName
+	go data.AddEditEdbInfoRcord(oldEdbInfo, newEdbInfoRecord)
+
 	//新增操作日志
 	{
 		edbLog := new(data_manage.EdbInfoLog)
@@ -3881,41 +3902,17 @@ func (this *ChartInfoController) EdbInfoReplace() {
 	//replaceChartTotal, replaceCalculateTotal, err := data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
 	_, _, err = data.EdbInfoReplace(oldEdbInfo, newEdbInfo, sysAdminId, sysUser.RealName)
 	//msgContent := ``
-	isFail := false
-	var errmsg string
 	if err != nil {
-		//msgContent = oldEdbInfo.EdbName + "指标替换" + newEdbInfo.EdbName + "指标,全部替换失败,涉及" + strconv.Itoa(replaceChartTotal) + "张图表,\n\n " + strconv.Itoa(replaceCalculateTotal) + "个计算指标"
-		isFail = true
-		errmsg = "replace err:" + err.Error()
-	} else {
-		//msgContent = oldEdbInfo.EdbName + "指标替换" + newEdbInfo.EdbName + "指标,全部替换成功,涉及" + strconv.Itoa(replaceChartTotal) + "张图表,\n\n" + strconv.Itoa(replaceCalculateTotal) + "个计算指标"
-		isFail = false
-	}
-
-	// 添加站内信息
-	//{
-	//	msgItem := new(company.CompanyApprovalMessage)
-	//	msgItem.CreateUserId = sysAdminId
-	//	msgItem.ReceiveUserId = sysAdminId
-	//	msgItem.MessageStatus = 0
-	//	msgItem.Remark = "指标替换"
-	//	msgItem.OperationStatus = 1
-	//	msgItem.Content = msgContent
-	//	msgItem.CreateTime = time.Now()
-	//	msgItem.ModifyTime = time.Now()
-	//	msgItem.MessageType = 3 //1:申请消息,2:审批结果,3:文字消息
-	//	msgItem.SourceType = 4  //消息来源
-	//	err = company.AddCompanyApprovalMessage(msgItem)
-	//}
-
-	if isFail {
 		br.Msg = "替换失败"
-		br.ErrMsg = "替换失败 err:" + errmsg
-	} else {
-		br.Msg = "替换成功"
-		br.ErrMsg = "替换成功"
-		br.Ret = 200
+		br.ErrMsg = "替换失败 replace err:" + err.Error()
+		return
 	}
+
+	//加入到缓存队列中处理
+	go cache.AddReplaceEdbInfo(oldEdbInfo, newEdbInfo)
+	br.Msg = "替换成功"
+	br.ErrMsg = "替换成功"
+	br.Ret = 200
 	br.IsAddLog = true
 	return
 }
@@ -3970,9 +3967,9 @@ func (this *EdbInfoController) RelationChartList() {
 		return
 	}
 
-	// 关联指标
+	/*// 关联指标
 	condition += ` AND b.edb_info_id = ? `
-	pars = append(pars, edbInfoId)
+	pars = append(pars, edbInfoId)*/
 
 	//只看我的
 	isShowMe, _ := this.GetBool("IsShowMe")
@@ -3981,8 +3978,47 @@ func (this *EdbInfoController) RelationChartList() {
 		pars = append(pars, sysUser.AdminId)
 	}
 
+	chartIds := make([]int, 0)
+	chartIdMap := make(map[int]bool)
+	// 查询指标绑定的图表
+	edbListTemp, err := data_manage.GetEdbMappingListByEdbInfoId(edbInfoId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+	for _, v := range edbListTemp {
+		if _, ok := chartIdMap[v.ChartInfoId]; !ok {
+			chartIdMap[v.ChartInfoId] = true
+		}
+	}
+	// 查询跨品种的图表
+	tagXList, err := cross_variety.GetChartInfoCrossVarietyByXEdbInfoId(edbInfoId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+
+	for _, v := range tagXList {
+		if _, ok := chartIdMap[v.ChartInfoId]; !ok {
+			chartIdMap[v.ChartInfoId] = true
+		}
+	}
+
+	tagYList, err := cross_variety.GetChartInfoCrossVarietyByYEdbInfoId(edbInfoId)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取图表信息失败"
+		br.ErrMsg = "获取图表信息失败,Err:" + err.Error()
+		return
+	}
+	for _, v := range tagYList {
+		if _, ok := chartIdMap[v.ChartInfoId]; !ok {
+			chartIdMap[v.ChartInfoId] = true
+		}
+	}
+
 	// 获取当前账号的不可见图表
-	noPermissionChartIdList := make([]int, 0)
 	{
 		obj := data_manage.EdbInfoNoPermissionAdmin{}
 		confList, err := obj.GetAllChartListByAdminId(this.SysUser.AdminId)
@@ -3992,15 +4028,29 @@ func (this *EdbInfoController) RelationChartList() {
 			return
 		}
 		for _, v := range confList {
-			noPermissionChartIdList = append(noPermissionChartIdList, v.ChartInfoId)
+			if _, ok := chartIdMap[v.ChartInfoId]; ok {
+				delete(chartIdMap, v.ChartInfoId)
+			}
 		}
 	}
-	noPermissionChartIdNum := len(noPermissionChartIdList)
-	if noPermissionChartIdNum > 0 {
-		condition += ` AND a.chart_info_id not in  (` + utils.GetOrmInReplace(noPermissionChartIdNum) + `) `
-		pars = append(pars, noPermissionChartIdList)
+	for k, _ := range chartIdMap {
+		chartIds = append(chartIds, k)
 	}
 
+	// 关联指标
+	if len(chartIds) > 0 {
+		condition += `  AND a.chart_info_id in  (` + utils.GetOrmInReplace(len(chartIds)) + `)`
+		pars = append(pars, chartIds)
+	} else {
+		items := make([]*data_manage.ChartInfoView, 0)
+		resp.Paging = page
+		resp.List = items
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		return
+	}
+	// 得到图表ID
 	//获取关联图表列表
 	list, err := data_manage.GetRelationChartListByCondition(condition, pars, startSize, pageSize)
 	if err != nil && err.Error() != utils.ErrNoRow() {

+ 8 - 2
controllers/data_manage/edb_info_calculate.go

@@ -9,11 +9,12 @@ import (
 	"eta/eta_api/services/data/data_manage_permission"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"net/url"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // 计算指标
@@ -230,7 +231,6 @@ func (this *ChartInfoController) CalculateDetail() {
 		br.ErrMsg = "获取失败,Err:" + err.Error()
 		return
 	}
-
 	fullEdb := new(data_manage.EdbInfoFullClassify)
 	classifyList, err, errMsg := data.GetFullClassifyByClassifyId(edbInfo.ClassifyId)
 	if err != nil {
@@ -848,6 +848,8 @@ func (this *ChartInfoController) CalculateBatchEdit() {
 		Frequency:     req.Frequency,
 		Unit:          req.Unit,
 		ClassifyId:    req.ClassifyId,
+		AdminId:       this.SysUser.AdminId,
+		AdminName:     this.SysUser.RealName,
 		Formula:       req.Formula, //N数值移动平均计算、环比值、环差值
 		FromEdbInfoId: req.FromEdbInfoId,
 		Source:        req.Source,
@@ -1948,6 +1950,10 @@ func (this *ChartInfoController) BatchCalculateBatchEdit() {
 		}
 		return
 	}
+
+	req.AdminId = sysUser.AdminId
+	req.AdminName = sysUser.RealName
+
 	req.EdbList = reqEdbList
 	// 调用指标库去更新
 	reqJson, err := json.Marshal(req)

+ 85 - 1
controllers/data_manage/edb_info_refresh.go

@@ -474,7 +474,7 @@ func (c *EdbInfoController) SaveEdbRefreshStatus() {
 		br.IsSendEmail = false
 		return
 	}
-
+	// todo 批量设置刷新状态修改
 	edbIdList := make([]int, 0)
 	edbCodeList := make([]string, 0)
 	// 指标id列表
@@ -538,6 +538,90 @@ func (c *EdbInfoController) SaveEdbRefreshStatus() {
 	br.Msg = "保存成功"
 }
 
+// SaveEdbRefreshStatusSingle
+// @Title 设置单个指标刷新状态接口
+// @Description 设置单个指标刷新状态接口
+// @Param	request	body data_manage.SaveEdbRefreshStatusReq true "type json string"
+// @Success 200 {object} data_manage.RefreshBaseEdbInfoResp
+// @router /edb_info/single_refresh/status/save [post]
+func (c *EdbInfoController) SaveEdbRefreshStatusSingle() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	var req request.SaveEdbRefreshStatusSingleReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.EdbInfoId <= 0 {
+		br.Msg = "请选择指标"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 查询指标
+	edbInfo, err := data_manage.GetEdbInfoById(req.EdbInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "指标不存在"
+			return
+		}
+		br.Msg = "查询指标失败"
+		br.ErrMsg = "查询指标失败,Err:" + err.Error()
+		return
+	}
+
+	// 查询指标的指标代码
+	calculateEdbIdList := make([]int, 0)
+
+	isStop := 0
+	if req.ModifyStatus == `暂停` {
+		isStop = 1
+	}
+	// 查询相关的计算指标
+	calculateEdb, err := data_manage.GetAllCalculateByEdbInfoId(edbInfo.EdbInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "指标不存在"
+			return
+		}
+		br.Msg = "查询计算指标失败"
+		br.ErrMsg = "查询计算指标失败,Err:" + err.Error()
+	}
+	// 遍历指标列表,把计算指标id整理成数组
+	if len(calculateEdb) > 0 {
+		for _, calculateEdbInfo := range calculateEdb {
+			calculateEdbIdList = append(calculateEdbIdList, calculateEdbInfo.EdbInfoId)
+		}
+	}
+	// todo 查询相关的预测指标
+
+	switch edbInfo.Source {
+	case utils.DATA_SOURCE_MYSTEEL_CHEMICAL: // 钢联
+		err = data_manage.ModifyMysteelChemicalUpdateStatusByEdbInfoId(edbInfo.EdbInfoId, isStop, edbInfo.EdbCode, calculateEdbIdList)
+	case utils.DATA_SOURCE_WIND: // wind
+		err = data_manage.WindEdbInfoUpdateStatusByEdbInfoId(edbInfo.EdbInfoId, isStop, edbInfo.SubSource, calculateEdbIdList)
+	default:
+		br.Msg = "暂不支持设置其他来源的指标"
+		return
+	}
+	if err != nil {
+		br.Msg = `保存失败`
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
 // GetEdbRefreshEdbConfig
 // @Title 获取单个指标的刷新配置列表接口
 // @Description 获取单个指标的刷新配置列表接口

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

@@ -2694,6 +2694,14 @@ func (c *ExcelInfoController) BatchRefresh() {
 		br.Msg = "刷新成功"
 		return
 	}
+	if req.Source == "" {
+		br.Msg = "刷新来源有误"
+		return
+	}
+	if req.PrimaryId <= 0 {
+		br.Msg = "刷新对象有误"
+		return
+	}
 
 	// 获取表格关联的指标IDs
 	edbIds, e := excel2.GetEdbIdsFromExcelCodes(req.ExcelCodes, sysUser.AdminId, c.Lang)
@@ -2703,7 +2711,7 @@ func (c *ExcelInfoController) BatchRefresh() {
 		return
 	}
 
-	redisKey := data.GetBatchChartRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+	redisKey := data.GetBatchChartRefreshKey(req.Source, req.PrimaryId, req.SubId)
 	refreshKeys := make([]string, 0)
 	for _, v := range req.ExcelCodes {
 		refreshKeys = append(refreshKeys, fmt.Sprint(utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL, v))
@@ -2751,10 +2759,18 @@ func (c *ExcelInfoController) GetBatchChartRefreshResult() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+	if req.Source == "" {
+		br.Msg = "刷新来源有误"
+		return
+	}
+	if req.PrimaryId <= 0 {
+		br.Msg = "刷新对象有误"
+		return
+	}
 
 	// 校验缓存是否存在, 存在说明还在刷新中
 	result := true
-	redisKey := excel2.GetExcelEdbBatchRefreshKey(req.Source, req.ReportId, req.ReportChapterId)
+	redisKey := excel2.GetExcelEdbBatchRefreshKey(req.Source, req.PrimaryId, req.SubId)
 	if redisKey != `` {
 		// 如果找到了key,那么就是还在更新中
 		ok := utils.Rc.IsExist(redisKey)

+ 6 - 0
controllers/data_manage/future_good/future_good_chart_info.go

@@ -544,6 +544,9 @@ func (this *FutureGoodChartInfoController) ChartInfoAdd() {
 	resp.UniqueCode = chartInfo.UniqueCode
 	resp.ChartType = req.ChartType
 
+	chartInfo.ChartInfoId = chartInfoId
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartInfoId)
 
@@ -767,6 +770,9 @@ func (this *FutureGoodChartInfoController) ChartInfoEdit() {
 	resp.UniqueCode = chartItem.UniqueCode
 	resp.ChartType = req.ChartType
 
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartItem)
+
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据

+ 3 - 2
controllers/data_manage/predict_edb_classify.go

@@ -302,7 +302,7 @@ func (this *PredictEdbClassifyController) DeleteCheck() {
 		return
 	}
 
-	deleteStatus, tipsMsg, err, errMsg := data.DeleteCheck(req.ClassifyId, req.EdbInfoId, this.SysUser)
+	deleteStatus, tipsMsg, tableList, err, errMsg := data.DeleteCheck(req.ClassifyId, req.EdbInfoId, this.SysUser)
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg
@@ -317,6 +317,7 @@ func (this *PredictEdbClassifyController) DeleteCheck() {
 	resp := new(data_manage.ClassifyDeleteCheckResp)
 	resp.DeleteStatus = deleteStatus
 	resp.TipsMsg = tipsMsg
+	resp.TableList = tableList
 	br.Ret = 200
 	br.Msg = "检测成功"
 	br.Success = true
@@ -356,7 +357,7 @@ func (this *PredictEdbClassifyController) Delete() {
 		return
 	}
 
-	nextItem, err, errMsg := data.Delete(req.ClassifyId, req.EdbInfoId, sysUser, string(this.Ctx.Input.RequestBody), this.Ctx.Input.URI())
+	nextItem, _, err, errMsg := data.Delete(req.ClassifyId, req.EdbInfoId, sysUser, string(this.Ctx.Input.RequestBody), this.Ctx.Input.URI())
 	if errMsg != `` {
 		br.Msg = errMsg
 		br.ErrMsg = errMsg

+ 13 - 2
controllers/data_manage/predict_edb_info.go

@@ -12,12 +12,13 @@ import (
 	"eta/eta_api/services/elastic"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"github.com/shopspring/decimal"
 	"sort"
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"github.com/shopspring/decimal"
 )
 
 // PredictEdbInfoController 预测指标
@@ -770,6 +771,16 @@ func (this *PredictEdbInfoController) Edit() {
 	//修改es
 	data.AddOrEditEdbInfoToEs(resp.EdbInfoId)
 
+	// 添加操作日志
+	newEdbRecord := new(data_manage.EdbInfoEditRecord)
+	newEdbRecord.EdbName = req.EdbName
+	// 频度和单位在此接口不处理
+	newEdbRecord.Frequency = edbInfo.Frequency
+	newEdbRecord.Unit = edbInfo.Unit
+	newEdbRecord.OperateUserId = sysUser.AdminId
+	newEdbRecord.OperateUserRealName = sysUser.RealName
+	go data.AddEditEdbInfoRcord(edbInfo, newEdbRecord)
+
 	// 刷新关联指标
 	go data.EdbInfoRefreshAllFromBaseV2(resp.EdbInfoId, true, false)
 

+ 6 - 2
controllers/data_source/icpi.go

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

+ 6 - 7
controllers/english_report/report.go

@@ -92,7 +92,7 @@ func (this *EnglishReportController) Add() {
 	}
 
 	// 根据审批开关及审批流判断当前报告状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird, models.ReportOperateAdd)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -475,7 +475,6 @@ func (this *EnglishReportController) ListReport() {
 
 	var authOk bool
 	adminMap := make(map[int]string, 0) // 编辑中的研究员姓名
-
 	total, e := models.GetEnglishReportListCount(condition, pars, companyType)
 	if e != nil {
 		br.Msg = "获取失败"
@@ -676,7 +675,7 @@ func (this *EnglishReportController) PublishReport() {
 		}
 
 		// 根据审批开关及审批流判断当前报告状态
-		state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, report.ClassifyIdFirst, report.ClassifyIdSecond, models.ReportOperatePublish)
+		state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, report.ClassifyIdFirst, report.ClassifyIdSecond, 0, models.ReportOperatePublish)
 		if e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -838,7 +837,7 @@ func (this *EnglishReportController) PublishCancleReport() {
 	}
 
 	// 根据审批开关及审批流判断当前报告状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, models.ReportOperateCancelPublish)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportInfo.ClassifyIdFirst, reportInfo.ClassifyIdSecond, 0, models.ReportOperateCancelPublish)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -1301,7 +1300,7 @@ func (this *EnglishReportController) SubmitApprove() {
 	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateSubmitApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
@@ -1324,7 +1323,7 @@ func (this *EnglishReportController) SubmitApprove() {
 	}
 
 	// 提交审批
-	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeEnglish, reportItem.Id, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, sysUser.AdminId, sysUser.RealName)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "提交审批失败, Err: " + e.Error()
@@ -1392,7 +1391,7 @@ func (this *EnglishReportController) CancelApprove() {
 	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeEnglish, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateCancelApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()

+ 2 - 0
controllers/fe_calendar/fe_calendar_matter.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/controllers"
 	"eta/eta_api/models"
 	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
 	"strings"
@@ -323,6 +324,7 @@ func (this *FeCalendarMatterController) Save() {
 		return
 	}
 
+	_ = data.SaveCalendarEdbInfoRelation(req.ChartPermissionId, req.MatterDate, editMatters, removeMatters)
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"

+ 1 - 1
controllers/ppt_v2.go

@@ -856,7 +856,7 @@ func (this *PptV2Controller) ToReport() {
 		br.Msg = "参数有误"
 		return
 	}
-	reportId, reportCode, msg, e := services.SavePPTReport(req.PptId, req.ClassifyIdSecond, req.Title, sysUser)
+	reportId, reportCode, msg, e := services.SavePPTReport(req.PptId, req.ClassifyId, req.Title, sysUser)
 	if e != nil {
 		br.Msg = msg
 		br.ErrMsg = "PPT转报告失败, Err: " + e.Error()

File diff ditekan karena terlalu besar
+ 268 - 723
controllers/report.go


+ 47 - 2
controllers/report_approve/report_approve.go

@@ -174,7 +174,7 @@ func (this *ReportApproveController) List() {
 
 	// 已处理
 	if params.ListType == 2 {
-		cond := fmt.Sprintf(` AND a.%s = ? AND a.%s IN (%s)`, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.State, utils.GetOrmInReplace(2))
+		cond := fmt.Sprintf(` AND a.%s = ? AND a.%s IN (%s)`, report_approve.ReportApproveRecordCols.ApproveUserId, report_approve.ReportApproveRecordCols.NodeState, utils.GetOrmInReplace(2))
 		pars := make([]interface{}, 0)
 		pars = append(pars, sysUser.AdminId, []int{report_approve.ReportApproveStatePass, report_approve.ReportApproveStateRefuse})
 		order := ""
@@ -236,6 +236,12 @@ func (this *ReportApproveController) List() {
 			br.ErrMsg = "GetApprovedReportApprovePageList err: " + e.Error()
 			return
 		}
+
+		for _, v := range list {
+			// 这个时候的状态,用审批状态
+			v.RecordState = v.NodeState
+			v.ApproveTime = v.NodeApproveTime
+		}
 		ormList = list
 	}
 
@@ -513,7 +519,7 @@ func (this *ReportApproveController) Detail() {
 		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.ReportCode = 	utils.MD5(fmt.Sprint("smart_", approveItem.ReportId))
+		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])
 	}
 
@@ -934,3 +940,42 @@ func (this *ReportApproveController) CheckApproveOpen() {
 	br.Success = true
 	br.Msg = "操作成功"
 }
+
+func init() {
+	//fixApproveRecord()
+}
+func fixApproveRecord() {
+	recordOb := new(report_approve.ReportApproveRecord)
+
+	recordCond := fmt.Sprintf(` AND %s = ? AND %s in (?,?)`, report_approve.ReportApproveRecordCols.NodeType, report_approve.ReportApproveRecordCols.State)
+	recordPars := make([]interface{}, 0)
+	recordPars = append(recordPars, 0, report_approve.ReportApproveStatePass, report_approve.ReportApproveStateRefuse)
+	list, e := recordOb.GetItemsByCondition(recordCond, recordPars, []string{}, "")
+	if e != nil {
+		fmt.Println("查找审批记录失败,Err:", e.Error())
+		return
+	}
+	for _, recordItem := range list {
+		//fmt.Println(recordItem)
+		recordItem.NodeState = report_approve.ReportApproveStatePass
+		recordItem.NodeApproveUserId = recordItem.ApproveUserId
+		recordItem.NodeApproveUserName = recordItem.ApproveUserName
+		recordItem.NodeApproveTime = recordItem.ApproveTime
+
+		// 如果不是或签,那么只需要修复自己就好了
+		if recordItem.ApproveType != report_approve.NodeApproveTypeAny {
+			recordCols := []string{"State", "ApproveTime", "ModifyTime", "NodeState", "NodeApproveUserId", "NodeApproveUserName", "NodeApproveTime"}
+			if e = recordItem.Update(recordCols); e != nil {
+				fmt.Println("更新审批记录状态失败,Err:", e.Error())
+			}
+			continue
+		}
+		// 或签
+		// 需要将该审批的同一个节点的记录标记为已审批
+		if e := recordItem.UpdateNodeState(recordItem.ReportApproveId, recordItem.NodeId, recordItem.NodeState, recordItem.NodeApproveUserId, recordItem.NodeApproveUserName, recordItem.NodeApproveTime); e != nil {
+			fmt.Println("更新同一节点的其他审批记录状态失败,Err:", e.Error())
+		}
+	}
+
+	fmt.Println("审批数据修复完成")
+}

+ 1 - 1
controllers/report_author.go

@@ -366,7 +366,7 @@ func (this *ReportAuthorController) DeleteAuthor() {
 		condition = " AND author = ? "
 		pars = append(pars, item.ReportAuthor)
 		if item.AuthorType == 1 {
-			count, err = models.GetReportListCount(condition, pars, "")
+			count, err = models.GetReportListCount(condition, pars)
 		} else {
 			count, err = models.GetEnglishReportListCount(condition, pars, "")
 		}

+ 1019 - 0
controllers/report_chapter.go

@@ -0,0 +1,1019 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report"
+	"eta/eta_api/models/smart_report"
+	"eta/eta_api/services"
+	"eta/eta_api/utils"
+	"html"
+	"strconv"
+	"time"
+)
+
+// AddChapter
+// @Title 新增晨周报章节内容
+// @Description 新增晨周报章节内容
+// @Param	request	body models.AddReportChapterReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /chapter/add [post]
+func (this *ReportController) AddChapter() {
+	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.AddReportChapterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ReportId <= 0 {
+		br.Msg = "报告ID有误"
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(req.ReportId)
+	if err != nil {
+		br.Msg = "报告信息有误"
+		br.ErrMsg = "报告信息有误, Err: " + err.Error()
+		return
+	}
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许新增"
+		br.ErrMsg = "该报告已发布,不允许新增"
+		return
+	}
+
+	//newContent := req.Content
+	//// 更新章节及指标
+	//contentSub := ""
+	//if req.Content != "" {
+	//	e := utils.ContentXssCheck(req.Content)
+	//	if e != nil {
+	//		br.Msg = "存在非法标签"
+	//		br.ErrMsg = "存在非法标签, Err: " + e.Error()
+	//		return
+	//	}
+	//	contentClean, e := services.FilterReportContentBr(req.Content)
+	//	if e != nil {
+	//		br.Msg = "内容去除前后空格失败"
+	//		br.ErrMsg = "内容去除前后空格失败, Err: " + e.Error()
+	//		return
+	//	}
+	//	req.Content = contentClean
+	//
+	//	contentSub, err = services.GetReportContentSub(req.Content)
+	//	if err != nil {
+	//		br.Msg = "内容分段解析失败"
+	//		br.ErrMsg = "编辑报告章节-解析 ContentSub 失败, Err: " + err.Error()
+	//		return
+	//	}
+	//}
+	//if req.Content == "" {
+	//	req.Content = newContent
+	//}
+
+	reportChapterInfo := new(models.ReportChapter)
+	reportChapterInfo.ReportId = reportInfo.Id
+	reportChapterInfo.ClassifyIdFirst = reportInfo.ClassifyIdFirst
+	reportChapterInfo.ClassifyNameFirst = reportInfo.ClassifyNameFirst
+
+	reportChapterInfo.Title = req.Title
+	reportChapterInfo.AddType = 1
+	//reportChapterInfo.Author = req.Author
+	//reportChapterInfo.Content = html.EscapeString(req.Content)
+	//reportChapterInfo.ContentSub = html.EscapeString(contentSub)
+	reportChapterInfo.IsEdit = 1
+	//reportChapterInfo.CreateTime = req.CreateTime
+	reportChapterInfo.CreateTime = reportInfo.CreateTime
+	reportChapterInfo.VideoKind = 1
+
+	reportChapterInfo.ClassifyIdSecond = reportInfo.ClassifyIdSecond
+	reportChapterInfo.ClassifyNameSecond = reportInfo.ClassifyNameSecond
+	reportChapterInfo.ClassifyIdThird = reportInfo.ClassifyIdThird
+	reportChapterInfo.ClassifyNameThird = reportInfo.ClassifyNameThird
+	reportChapterInfo.LastModifyAdminId = sysUser.AdminId
+	reportChapterInfo.LastModifyAdminName = sysUser.RealName
+	reportChapterInfo.ContentModifyTime = time.Now()
+	//reportChapterInfo.ContentStruct = html.EscapeString(req.ContentStruct)
+	//reportChapterInfo.CanvasColor = req.CanvasColor
+	//reportChapterInfo.HeadResourceId = req.HeadResourceId
+	//reportChapterInfo.EndResourceId = req.EndResourceId
+
+	err, errMsg := services.AddChapterBaseInfoAndPermission(reportInfo, reportChapterInfo, req.PermissionIdList, req.AdminIdList)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// EditDayWeekChapter
+// @Title 编辑晨周报章节内容
+// @Description 编辑晨周报章节内容
+// @Param	request	body models.EditReportChapterReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /editDayWeekChapter [post]
+func (this *ReportController) EditDayWeekChapter() {
+	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.EditReportChapterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	reportChapterId := req.ReportChapterId
+	if reportChapterId <= 0 {
+		br.Msg = "报告章节ID有误"
+		return
+	}
+	if req.Content == "" {
+		br.Msg = "请输入内容"
+		return
+	}
+
+	// 获取章节详情
+	reportChapterInfo, err := models.GetReportChapterInfoById(reportChapterId)
+	if err != nil {
+		br.Msg = "报告章节信息有误"
+		br.ErrMsg = "报告章节信息有误, Err: " + err.Error()
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(reportChapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "报告信息有误"
+		br.ErrMsg = "报告信息有误, Err: " + err.Error()
+		return
+	}
+
+	// 操作权限校验
+	{
+		// 如果不是创建人,那么就要去查看是否授权
+		if reportInfo.AdminId != sysUser.AdminId {
+			// 授权用户权限校验
+			chapterGrantObj := report.ReportChapterGrant{}
+			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
+			if tmpErr != nil {
+				if tmpErr.Error() == utils.ErrNoRow() {
+					br.Msg = "没有权限"
+					br.ErrMsg = "没有权限"
+					br.IsSendEmail = false
+					return
+				}
+				br.Msg = "获取章节id授权用户失败"
+				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
+				return
+			}
+		}
+
+		// 标记更新中
+		{
+			markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
+			if err != nil {
+				br.Msg = err.Error()
+				return
+			}
+			if markStatus.Status == 1 {
+				br.Msg = markStatus.Msg
+				br.IsSendEmail = false
+				return
+			}
+		}
+	}
+
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	reqTickerList := req.TickerList
+	// 更新章节及指标
+	contentSub := ""
+	if req.Content != "" {
+		e := utils.ContentXssCheck(req.Content)
+		if e != nil {
+			br.Msg = "存在非法标签"
+			br.ErrMsg = "存在非法标签, Err: " + e.Error()
+			return
+		}
+		contentClean, e := services.FilterReportContentBr(req.Content)
+		if e != nil {
+			br.Msg = "内容去除前后空格失败"
+			br.ErrMsg = "内容去除前后空格失败, Err: " + e.Error()
+			return
+		}
+		req.Content = contentClean
+
+		contentSub, err = services.GetReportContentSub(req.Content)
+		if err != nil {
+			br.Msg = "内容分段解析失败"
+			br.ErrMsg = "编辑报告章节-解析 ContentSub 失败, Err: " + err.Error()
+			return
+		}
+	}
+
+	reportChapterInfo.Title = req.Title
+	//reportChapterInfo.AddType = req.AddType
+	reportChapterInfo.Author = req.Author
+	reportChapterInfo.Content = html.EscapeString(req.Content)
+	reportChapterInfo.ContentSub = html.EscapeString(contentSub)
+	reportChapterInfo.IsEdit = 1
+	reportChapterInfo.CreateTime = req.CreateTime
+	reportChapterInfo.VideoUrl = req.VideoUrl
+	reportChapterInfo.VideoName = req.VideoName
+	reportChapterInfo.VideoPlaySeconds = req.VideoPlaySeconds
+	reportChapterInfo.VideoSize = req.VideoSize
+	reportChapterInfo.VideoKind = 1
+
+	reportChapterInfo.LastModifyAdminId = sysUser.AdminId
+	reportChapterInfo.LastModifyAdminName = sysUser.RealName
+	reportChapterInfo.ContentModifyTime = time.Now()
+	reportChapterInfo.ContentStruct = html.EscapeString(req.ContentStruct)
+	reportChapterInfo.CanvasColor = req.CanvasColor
+	reportChapterInfo.HeadResourceId = req.HeadResourceId
+	reportChapterInfo.EndResourceId = req.EndResourceId
+
+	updateCols := make([]string, 0)
+	updateCols = append(updateCols, "Title", "AddType", "Author", "Content", "ContentSub", "IsEdit", "CreateTime")
+	if req.VideoUrl != "" {
+		updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds", "VideoKind")
+	}
+
+	updateCols = append(updateCols, "LastModifyAdminId", "LastModifyAdminName", "ContentModifyTime", "ContentStruct", "CanvasColor", "HeadResourceId", "EndResourceId")
+
+	// 章节报告更新指标
+	tickerList := make([]*models.ReportChapterTicker, 0)
+	if len(reqTickerList) > 0 {
+		nowTime := time.Now()
+		for i := 0; i < len(reqTickerList); i++ {
+			tickerList = append(tickerList, &models.ReportChapterTicker{
+				ReportChapterId: reportChapterInfo.ReportChapterId,
+				Sort:            reqTickerList[i].Sort,
+				Ticker:          reqTickerList[i].Ticker,
+				CreateTime:      nowTime,
+				UpdateTime:      nowTime,
+			})
+		}
+	}
+	err = models.UpdateChapterAndTicker(reportChapterInfo, updateCols, tickerList)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "报告章节内容保存失败, Err: " + err.Error()
+		return
+	}
+
+	// 标记更新中
+	{
+		markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
+		if err != nil {
+			br.Msg = err.Error()
+			return
+		}
+		if markStatus.Status == 1 {
+			br.Msg = markStatus.Msg
+			return
+		}
+	}
+
+	// 备份关键数据
+	chapters := make([]*models.ReportChapter, 0)
+	chapters = append(chapters, reportChapterInfo)
+	go services.SaveReportLogs(nil, chapters, sysUser.AdminId, sysUser.RealName)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// DelChapter
+// @Title 编辑晨周报章节内容
+// @Description 编辑晨周报章节内容
+// @Param	request	body models.EditReportChapterReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /chapter/del [post]
+func (this *ReportController) DelChapter() {
+	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.DelReportChapterReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	reportChapterId := req.ReportChapterId
+	if reportChapterId <= 0 {
+		br.Msg = "报告章节ID有误"
+		return
+	}
+
+	// 获取章节详情
+	reportChapterInfo, err := models.GetReportChapterInfoById(reportChapterId)
+	if err != nil {
+		br.Msg = "报告章节信息有误"
+		br.ErrMsg = "报告章节信息有误, Err: " + err.Error()
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(reportChapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "报告信息有误"
+		br.ErrMsg = "报告信息有误, Err: " + err.Error()
+		return
+	}
+
+	// 操作权限校验
+	{
+		// 如果不是创建人,那么就要去查看是否授权
+		if reportInfo.AdminId != sysUser.AdminId {
+			// 授权用户权限校验
+			chapterGrantObj := report.ReportChapterGrant{}
+			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(reportChapterInfo.ReportChapterId, sysUser.AdminId)
+			if tmpErr != nil {
+				if tmpErr.Error() == utils.ErrNoRow() {
+					br.Msg = "没有权限"
+					br.ErrMsg = "没有权限"
+					br.IsSendEmail = false
+					return
+				}
+				br.Msg = "获取章节id授权用户失败"
+				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
+				return
+			}
+		}
+
+		// 标记更新中
+		{
+			markStatus, err := services.UpdateReportEditMark(reportChapterInfo.ReportId, reportChapterInfo.ReportChapterId, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
+			if err != nil {
+				br.Msg = err.Error()
+				return
+			}
+			if markStatus.Status == 1 {
+				br.Msg = markStatus.Msg
+				br.IsSendEmail = false
+				return
+			}
+		}
+	}
+
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	// 删除章节
+	err, errMsg := services.DelChapter(reportInfo, reportChapterInfo, sysUser)
+	if err != nil {
+		br.Msg = "删除失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "删除失败,Err:" + err.Error()
+		return
+	}
+
+	// 备份关键数据
+	chapters := make([]*models.ReportChapter, 0)
+	chapters = append(chapters, reportChapterInfo)
+	go services.SaveReportLogs(nil, chapters, sysUser.AdminId, sysUser.RealName)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "删除成功"
+}
+
+// EditChapterBaseInfoAndPermission
+// @Title 修改报告章节的基础信息、授权用户权限、品种权限
+// @Description 修改报告章节的基础信息、授权用户权限、品种权限
+// @Param	request	body models.EditReportChapterReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /chapter/base_info/edit [post]
+func (this *ReportController) EditChapterBaseInfoAndPermission() {
+	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.EditReportChapterBaseInfoAndPermissionReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	reportChapterId := req.ReportChapterId
+	if reportChapterId <= 0 {
+		br.Msg = "报告章节ID有误"
+		return
+	}
+	// 获取章节详情
+	reportChapterInfo, err := models.GetReportChapterInfoById(reportChapterId)
+	if err != nil {
+		br.Msg = "报告章节信息有误"
+		br.ErrMsg = "报告章节信息有误, Err: " + err.Error()
+		return
+	}
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(reportChapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "报告信息有误"
+		br.ErrMsg = "报告信息有误, Err: " + err.Error()
+		return
+	}
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	err, errMsg := services.EditChapterBaseInfoAndPermission(reportInfo, reportChapterInfo, req.Title, req.PermissionIdList, req.AdminIdList)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// GetReportChapterList
+// @Title 获取报告章节列表
+// @Description 获取报告章节列表
+// @Param   ReportId	query	string	true	"报告ID"
+// @Success 200 {object} company.CompanyListResp
+// @router /getReportChapterList [get]
+func (this *ReportController) GetReportChapterList() {
+	// TODO 授权用户校验
+	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
+	}
+
+	reqReportId := this.GetString("ReportId")
+	reportId, _ := strconv.Atoi(reqReportId)
+	if reportId <= 0 {
+		br.Msg = "报告ID有误"
+		return
+	}
+
+	// 获取章节列表
+	chapterList, err := models.GetChapterListByReportId(reportId)
+	if err != nil {
+		br.Msg = "获取章节列表失败"
+		br.ErrMsg = "获取章节列表失败, Err: " + err.Error()
+		return
+	}
+	typeList, err := models.GetReportChapterTypeList()
+	if err != nil {
+		br.Msg = "获取章节类型列表失败"
+		br.ErrMsg = "获取章节类型列表失败, Err: " + err.Error()
+		return
+	}
+	typeIdImg := make(map[int]string)
+	for i := 0; i < len(typeList); i++ {
+		typeIdImg[typeList[i].ReportChapterTypeId] = typeList[i].EditImgUrl
+	}
+
+	resp := make([]models.ReportChapterResp, 0)
+	if len(chapterList) > 0 {
+		chapterIdList := make([]int, 0)
+		// 章节id授权用户列表map
+		chapterIdGrandListMap := make(map[int][]int)
+		// 章节id关联品种id列表map
+		chapterIdPermissionListMap := make(map[int][]int)
+
+		for _, v := range chapterList {
+			chapterIdList = append(chapterIdList, v.ReportChapterId)
+		}
+
+		// 处理章节id授权用户列表
+		{
+			chapterGrantObj := report.ReportChapterGrant{}
+			chapterGrantList, tmpErr := chapterGrantObj.GetGrantListByIdList(chapterIdList)
+			if tmpErr != nil {
+				br.Msg = "获取章节id授权用户列表失败"
+				br.ErrMsg = "获取章节id授权用户列表失败, Err: " + tmpErr.Error()
+				return
+			}
+
+			for _, v := range chapterGrantList {
+				tmpChapterIdGrandList, ok := chapterIdGrandListMap[v.ReportChapterId]
+				if !ok {
+					tmpChapterIdGrandList = make([]int, 0)
+				}
+				chapterIdGrandListMap[v.ReportChapterId] = append(tmpChapterIdGrandList, v.AdminId)
+			}
+		}
+
+		// 处理章节id关联品种id列表
+		{
+			obj := report.ReportChapterPermissionMapping{}
+			chapterPermissionList, tmpErr := obj.GetPermissionListByIdList(chapterIdList)
+			if tmpErr != nil {
+				br.Msg = "获取章节id关联品种列表失败"
+				br.ErrMsg = "获取章节id关联品种列表失败, Err: " + tmpErr.Error()
+				return
+			}
+
+			for _, v := range chapterPermissionList {
+				tmpChapterIdPermissionList, ok := chapterIdPermissionListMap[v.ReportChapterId]
+				if !ok {
+					tmpChapterIdPermissionList = make([]int, 0)
+				}
+				chapterIdPermissionListMap[v.ReportChapterId] = append(tmpChapterIdPermissionList, v.ChartPermissionId)
+			}
+		}
+
+		// TODO 获取更新规则
+		researchType := chapterList[0].ReportType
+		chapterTypeList, tmpErr := models.GetAllReportChapterTypeListByResearchType(researchType)
+		if tmpErr != nil {
+			br.Msg = "获取更新规则失败"
+			br.ErrMsg = "获取更新规则失败, Err: " + tmpErr.Error()
+			return
+		}
+		// 调整章节更新
+		nowTime := time.Now().Local()
+		for _, item := range chapterList {
+			stop := false
+			for _, rule := range chapterTypeList {
+				if rule.ReportChapterTypeId == item.TypeId {
+					//fmt.Println("rule.Enabled :", rule.Enabled, ";name=", rule.ReportChapterTypeName, "item.IsEdit:", item.IsEdit, "rule.IsSet:", rule.IsSet)
+					// 如果被永久暂停更新了
+					if rule.Enabled == 0 && item.IsEdit == 0 { //该章节已被永久禁用,同时未被操作过
+						stop = true
+					} else if rule.PauseStartTime != "" && rule.PauseEndTime != "" && rule.PauseStartTime != utils.EmptyDateStr && rule.PauseEndTime != utils.EmptyDateStr {
+						startTime, timeErr := time.ParseInLocation(utils.FormatDate, rule.PauseStartTime, time.Local)
+						if timeErr != nil {
+							br.Msg = "获取更新规则失败"
+							br.ErrMsg = "更新规则时间转换失败4001, Err: " + timeErr.Error()
+							return
+						}
+						endTime, timeErr := time.ParseInLocation(utils.FormatDate, rule.PauseEndTime, time.Local)
+						if timeErr != nil {
+							br.Msg = "获取更新规则失败"
+							br.ErrMsg = "更新规则时间转换失败4002, Err: " + timeErr.Error()
+							return
+						}
+						// 暂停更新
+						if nowTime.After(startTime) && nowTime.Before(endTime.AddDate(0, 0, 1)) {
+							stop = true
+						}
+						break
+					}
+				}
+			}
+			if !stop {
+				// 授权的用户列表
+				tmpChapterIdGrandList, ok := chapterIdGrandListMap[item.ReportChapterId]
+				if !ok {
+					tmpChapterIdGrandList = make([]int, 0)
+				}
+				// 关联的品种列表
+				tmpChapterIdPermissionList, ok := chapterIdPermissionListMap[item.ReportChapterId]
+				if !ok {
+					tmpChapterIdPermissionList = make([]int, 0)
+				}
+
+				tmpChapterItem := models.ReportChapterResp{
+					ReportChapterId:  item.ReportChapterId,
+					ReportId:         item.ReportId,
+					ReportType:       item.ReportType,
+					TypeId:           item.TypeId,
+					TypeName:         item.TypeName,
+					TypeEditImg:      typeIdImg[item.TypeId],
+					Title:            item.Title,
+					IsEdit:           item.IsEdit,
+					Trend:            item.Trend,
+					Sort:             item.Sort,
+					PublishState:     item.PublishState,
+					VideoUrl:         item.VideoUrl,
+					VideoName:        item.VideoName,
+					VideoPlaySeconds: item.VideoPlaySeconds,
+					VideoSize:        item.VideoSize,
+					VideoKind:        item.VideoKind,
+					ModifyTime:       item.ModifyTime.Format(utils.FormatDate),
+					GrandAdminIdList: tmpChapterIdGrandList,
+					PermissionIdList: tmpChapterIdPermissionList,
+				}
+				markStatus, err := services.UpdateReportEditMark(item.ReportId, item.ReportChapterId, this.SysUser.AdminId, 2, this.SysUser.RealName, this.Lang)
+				if err != nil {
+					br.Msg = "查询标记状态失败"
+					br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
+					return
+				}
+
+				if markStatus.Status == 0 {
+					tmpChapterItem.CanEdit = true
+				} else {
+					tmpChapterItem.Editor = markStatus.Editor
+				}
+
+				resp = append(resp, tmpChapterItem)
+			}
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// GetDayWeekChapter
+// @Title 获取晨周报章节信息
+// @Description 获取晨周报章节信息
+// @Param	ReportChapterId  query  int  true  "报告章节ID"
+// @Success 200 Ret=200 保存成功
+// @router /getDayWeekChapter [get]
+func (this *ReportController) GetDayWeekChapter() {
+	// TODO 授权用户校验
+	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
+	}
+
+	reportChapterId, _ := this.GetInt("ReportChapterId")
+	if reportChapterId <= 0 {
+		br.Msg = "参数有误"
+		return
+	}
+	chapterInfo, err := models.GetReportChapterInfoById(reportChapterId)
+	if err != nil {
+		br.Msg = "获取章节信息失败"
+		br.ErrMsg = "获取章节信息失败, Err: " + err.Error()
+		return
+	}
+	if chapterInfo != nil {
+		chapterInfo.Content = html.UnescapeString(chapterInfo.Content)
+		chapterInfo.ContentSub = html.UnescapeString(chapterInfo.ContentSub)
+		chapterInfo.ContentStruct = html.UnescapeString(chapterInfo.ContentStruct)
+	}
+
+	chapterInfo.Content = html.UnescapeString(chapterInfo.Content)
+	chapterInfo.ContentSub = html.UnescapeString(chapterInfo.ContentSub)
+	chapterInfo.ContentStruct = html.UnescapeString(chapterInfo.ContentStruct)
+
+	// 授权用户列表map
+	chapterGrantIdList := make([]int, 0)
+	// 关联品种id列表map
+	chapterPermissionIdList := make([]int, 0)
+	// 处理章节id授权用户列表
+	{
+		chapterGrantObj := report.ReportChapterGrant{}
+		chapterGrantList, tmpErr := chapterGrantObj.GetGrantListById(chapterInfo.ReportChapterId)
+		if tmpErr != nil {
+			br.Msg = "获取章节id授权用户列表失败"
+			br.ErrMsg = "获取章节id授权用户列表失败, Err: " + tmpErr.Error()
+			return
+		}
+
+		for _, v := range chapterGrantList {
+			chapterGrantIdList = append(chapterGrantIdList, v.AdminId)
+		}
+	}
+
+	// 处理章节id关联品种id列表
+	{
+		obj := report.ReportChapterPermissionMapping{}
+		chapterPermissionList, tmpErr := obj.GetPermissionListById(chapterInfo.ReportChapterId)
+		if tmpErr != nil {
+			br.Msg = "获取章节id关联品种列表失败"
+			br.ErrMsg = "获取章节id关联品种列表失败, Err: " + tmpErr.Error()
+			return
+		}
+
+		for _, v := range chapterPermissionList {
+			chapterPermissionIdList = append(chapterPermissionIdList, v.ChartPermissionId)
+		}
+	}
+
+	resp := models.ReportChapterItem{
+		ReportChapter:    *chapterInfo,
+		GrandAdminIdList: chapterGrantIdList,
+		PermissionIdList: chapterPermissionIdList,
+	}
+
+	if chapterInfo.HeadResourceId > 0 {
+		headResource, err := smart_report.GetResourceItemById(chapterInfo.HeadResourceId)
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取资源库版头失败, Err: " + err.Error()
+			return
+		}
+		resp.HeadImg = headResource.ImgUrl
+		resp.HeadStyle = headResource.Style
+	}
+
+	if chapterInfo.EndResourceId > 0 {
+		endResource, err := smart_report.GetResourceItemById(resp.EndResourceId)
+		if err != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "获取资源库版头失败, Err: " + err.Error()
+			return
+		}
+		resp.EndImg = endResource.ImgUrl
+		resp.EndStyle = endResource.Style
+	}
+
+	// 获取当前编辑状态
+	{
+		markStatus, err := services.UpdateReportEditMark(chapterInfo.ReportId, chapterInfo.ReportChapterId, this.SysUser.AdminId, 2, this.SysUser.RealName, this.Lang)
+		if err != nil {
+			br.Msg = "查询标记状态失败"
+			br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
+			return
+		}
+		if markStatus.Status == 0 {
+			resp.CanEdit = true
+		} else {
+			resp.Editor = markStatus.Editor
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ChapterMove
+// @Title 移动章节类型
+// @Description 移动章节类型
+// @Param	request	body models.PermissionMoveReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /chapter/move [post]
+func (this *ReportController) ChapterMove() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req models.ReportChapterMoveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+
+	if req.ReportChapterId == 0 {
+		br.Msg = "请选择要移动的章节"
+		return
+	}
+	e, msg := services.MoveReportChapter(&req)
+	if e != nil {
+		br.Msg = msg
+		br.ErrMsg = "移动品种失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// EditChapterTrendTag
+// @Title 编辑章节趋势标签
+// @Description 编辑章节趋势标签
+// @Param	request	body models.EditReportChapterReq true "type json string"
+// @Success 200 Ret=200 保存成功
+// @router /editChapterTrendTag [post]
+func (this *ReportController) EditChapterTrendTag() {
+	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.EditChapterTrendTagReq
+	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 = "章节ID有误"
+		return
+	}
+	if req.Trend == "" {
+		br.Msg = "请输入标签"
+		return
+	}
+
+	chapterInfo, err := models.GetReportChapterInfoById(req.ReportChapterId)
+	if err != nil {
+		br.Msg = "获取章节信息失败"
+		br.ErrMsg = "获取章节信息失败, Err: " + err.Error()
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, err := models.GetReportByReportId(chapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "报告信息有误"
+		br.ErrMsg = "报告信息有误, Err: " + err.Error()
+		return
+	}
+
+	// 操作权限校验
+	{
+		// 如果不是创建人,那么就要去查看是否授权
+		if reportInfo.AdminId != sysUser.AdminId {
+			// 授权用户权限校验
+			chapterGrantObj := report.ReportChapterGrant{}
+			_, tmpErr := chapterGrantObj.GetGrantByIdAndAdmin(chapterInfo.ReportChapterId, sysUser.AdminId)
+			if tmpErr != nil {
+				if tmpErr.Error() == utils.ErrNoRow() {
+					br.Msg = "没有权限"
+					br.ErrMsg = "没有权限"
+					br.IsSendEmail = false
+					return
+				}
+				br.Msg = "获取章节id授权用户失败"
+				br.ErrMsg = "获取章节id授权用户失败, Err: " + tmpErr.Error()
+				return
+			}
+		}
+	}
+
+	// 更新章节标签
+	chapterInfo.Trend = req.Trend
+	updateCols := make([]string, 0)
+	updateCols = append(updateCols, "Trend")
+	if err = chapterInfo.UpdateChapter(updateCols); err != nil {
+		br.Msg = "更新标签失败"
+		br.ErrMsg = "更新标签失败, Err: " + err.Error()
+		return
+	}
+
+	// 添加关键词
+	if err = models.AddTrendTagKeyWord(req.Trend); err != nil {
+		br.Msg = "添加标签关键词失败"
+		br.ErrMsg = "添加标签关键词失败, Err: " + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+}
+
+// GetSunCode 获取太阳码
+// @Title 公共模块
+// @Description 获取分享海报
+// @Param	request	body models.SunCodeReq true "type json string"
+// @Success 200 {object} string "获取成功"
+// @failure 400 {string} string "获取失败"
+// @router /getSunCode [post]
+func (this *ReportController) GetSunCode() {
+	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.SunCodeReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	var sunCodeUrl string
+	//先查,查不到再去生成上传
+	item, err := models.GetYbPcSunCode(req.CodeScene, req.CodePage)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "查询太阳码失败!"
+		br.ErrMsg = "查询太阳码失败,Err:" + err.Error()
+		return
+	}
+	if item != nil {
+		sunCodeUrl = item.SuncodeUrl
+	}
+
+	if sunCodeUrl == "" {
+		sunCodeUrl, err = services.PcCreateAndUploadSunCode(req.CodeScene, req.CodePage)
+		if err != nil {
+			br.Msg = "生成太阳码失败!"
+			br.ErrMsg = "生成太阳码失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	br.Data = sunCodeUrl
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}

+ 43 - 61
controllers/report_chapter_type.go

@@ -16,7 +16,7 @@ type ReportChapterTypeController struct {
 // List
 // @Title 报告章节列表
 // @Description 报告章节列表
-// @Param   ReportType  query  string  true  "报告类型: day-晨报; week-周报"
+// @Param   ClassifyId  query  int  true  "所属分类id"
 // @Success 200 {object} models.ReportChapterTypePageListResp
 // @router /chapter_type/list [get]
 func (this *ReportChapterTypeController) List() {
@@ -33,22 +33,27 @@ func (this *ReportChapterTypeController) List() {
 		br.Ret = 408
 		return
 	}
-	reportType := this.GetString("ReportType")
-	typeArr := []string{utils.REPORT_TYPE_DAY, utils.REPORT_TYPE_WEEK}
-	if !utils.InArrayByStr(typeArr, reportType) {
-		br.Msg = "请选择报告类型"
+	classifyId, _ := this.GetInt("ClassifyId", 0)
+	if classifyId <= 0 {
+		br.Msg = "请选择分类"
 		return
 	}
-	cond := ` AND research_type = ?`
+
+	cond := ` AND report_classify_id = ?`
 	pars := make([]interface{}, 0)
-	pars = append(pars, reportType)
+	pars = append(pars, classifyId)
 	list, e := models.GetReportChapterTypePageList(cond, pars)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取报告章节列表失败, Err: " + e.Error()
 		return
 	}
-	mappingList, e := models.GetChapterTypePermissionByResearchType(reportType)
+	chapterTypeIdList := make([]int, 0)
+	for _, v := range list {
+		chapterTypeIdList = append(chapterTypeIdList, v.ReportChapterTypeId)
+	}
+
+	mappingList, e := models.GetChapterTypePermissionByChapterTypeIdList(chapterTypeIdList)
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取章节类型权限列表失败, Err: " + e.Error()
@@ -116,15 +121,16 @@ func (this *ReportChapterTypeController) Add() {
 		br.Msg = "请输入章节名称"
 		return
 	}
-	typeArr := []string{utils.REPORT_TYPE_DAY, utils.REPORT_TYPE_WEEK}
-	if !utils.InArrayByStr(typeArr, req.ResearchType) {
-		br.Msg = "请选择报告类型"
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择分类"
 		return
 	}
+
 	// 重名校验
-	cond := ` AND report_chapter_type_name = ? AND research_type = ?`
+	cond := ` AND report_chapter_type_name = ? AND report_classify_id = ?`
 	pars := make([]interface{}, 0)
-	pars = append(pars, req.ReportChapterTypeName, req.ResearchType)
+	pars = append(pars, req.ReportChapterTypeName, req.ClassifyId)
 	exists, e := models.GetReportChapterTypeByCondition(cond, pars)
 	if e != nil && e.Error() != utils.ErrNoRow() {
 		br.Msg = "操作失败"
@@ -149,7 +155,8 @@ func (this *ReportChapterTypeController) Add() {
 	item.Enabled = 1
 	item.CreatedTime = nowTime
 	item.LastUpdatedTime = nowTime
-	item.ResearchType = req.ResearchType
+	//item.ResearchType = req.ResearchType
+	item.ReportClassifyId = req.ClassifyId
 	item.IsSet = 0
 	item.ReportChapterTypeKey = req.ReportChapterTypeName
 	item.TickerTitle = req.ReportChapterTypeName
@@ -174,29 +181,20 @@ func (this *ReportChapterTypeController) Add() {
 		permissionIdName[permissionList[i].ChartPermissionId] = permissionList[i].PermissionName
 	}
 
-	researchType := item.ResearchType
-	newPermissions := make([]*models.ReportChapterTypePermission, 0)       // 报告章节权限表(新)
-	newWeekPermissions := make([]*models.ChartPermissionChapterMapping, 0) // 报告章节权限表(老)
+	newPermissions := make([]*models.ReportChapterTypePermission, 0) // 报告章节权限表(新)
 	for i := range req.ChartPermissionIdList {
 		newPermissions = append(newPermissions, &models.ReportChapterTypePermission{
 			ReportChapterTypeId:   item.ReportChapterTypeId,
 			ReportChapterTypeName: item.ReportChapterTypeName,
 			ChartPermissionId:     req.ChartPermissionIdList[i],
 			PermissionName:        permissionIdName[req.ChartPermissionIdList[i]],
-			ResearchType:          researchType,
-			CreatedTime:           nowTime,
+			//ResearchType:          researchType,
+			CreatedTime: nowTime,
 		})
-		if researchType == utils.REPORT_TYPE_WEEK {
-			newWeekPermissions = append(newWeekPermissions, &models.ChartPermissionChapterMapping{
-				ChartPermissionId:   req.ChartPermissionIdList[i],
-				ReportChapterTypeId: item.ReportChapterTypeId,
-				ResearchType:        researchType,
-			})
-		}
 	}
 
 	// 设置权限
-	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, researchType, newPermissions, newWeekPermissions)
+	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, newPermissions)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "设置章节类型权限失败, Err: " + e.Error()
@@ -211,7 +209,7 @@ func (this *ReportChapterTypeController) Add() {
 	//todo 同步更新crm章节权限和章节类型
 	go func() {
 		var syncReq services.ChapterTypeSyncReq
-		syncReq.ResearchType = researchType
+		//syncReq.ResearchType = researchType
 		syncReq.ReportChapterTypeId = item.ReportChapterTypeId
 		_, _ = services.ReportChapterTypeSync(&syncReq)
 	}()
@@ -254,15 +252,16 @@ func (this *ReportChapterTypeController) Edit() {
 		br.Msg = "请输入章节名称"
 		return
 	}
-	typeArr := []string{utils.REPORT_TYPE_DAY, utils.REPORT_TYPE_WEEK}
-	if !utils.InArrayByStr(typeArr, req.ResearchType) {
-		br.Msg = "请选择报告类型"
+
+	if req.ClassifyId <= 0 {
+		br.Msg = "请选择分类"
 		return
 	}
+
 	// 重名校验
-	cond := ` AND report_chapter_type_name = ? AND research_type = ?`
+	cond := ` AND report_chapter_type_name = ? AND report_classify_id = ?`
 	pars := make([]interface{}, 0)
-	pars = append(pars, req.ReportChapterTypeName, req.ResearchType)
+	pars = append(pars, req.ReportChapterTypeName, req.ClassifyId)
 	exists, e := models.GetReportChapterTypeByCondition(cond, pars)
 	if e != nil && e.Error() != utils.ErrNoRow() {
 		br.Msg = "操作失败"
@@ -297,29 +296,20 @@ func (this *ReportChapterTypeController) Edit() {
 		permissionIdName[permissionList[i].ChartPermissionId] = permissionList[i].PermissionName
 	}
 
-	researchType := item.ResearchType
-	newPermissions := make([]*models.ReportChapterTypePermission, 0)       // 报告章节权限表(新)
-	newWeekPermissions := make([]*models.ChartPermissionChapterMapping, 0) // 报告章节权限表(老)
+	newPermissions := make([]*models.ReportChapterTypePermission, 0) // 报告章节权限表(新)
 	for i := range req.ChartPermissionIdList {
 		newPermissions = append(newPermissions, &models.ReportChapterTypePermission{
 			ReportChapterTypeId:   item.ReportChapterTypeId,
 			ReportChapterTypeName: item.ReportChapterTypeName,
 			ChartPermissionId:     req.ChartPermissionIdList[i],
 			PermissionName:        permissionIdName[req.ChartPermissionIdList[i]],
-			ResearchType:          researchType,
-			CreatedTime:           nowTime,
+			//ResearchType:          researchType,
+			CreatedTime: nowTime,
 		})
-		if researchType == utils.REPORT_TYPE_WEEK {
-			newWeekPermissions = append(newWeekPermissions, &models.ChartPermissionChapterMapping{
-				ChartPermissionId:   req.ChartPermissionIdList[i],
-				ReportChapterTypeId: item.ReportChapterTypeId,
-				ResearchType:        researchType,
-			})
-		}
 	}
 
 	// 设置权限
-	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, researchType, newPermissions, newWeekPermissions)
+	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, newPermissions)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "设置章节类型权限失败, Err: " + e.Error()
@@ -338,9 +328,10 @@ func (this *ReportChapterTypeController) Edit() {
 		_ = utils.Rc.Delete(key)
 	}
 
+	// todo 处理crm那边的报告权限逻辑
 	go func() {
 		var syncReq services.ChapterTypeSyncReq
-		syncReq.ResearchType = researchType
+		//syncReq.ResearchType = researchType
 		syncReq.ReportChapterTypeId = item.ReportChapterTypeId
 		_, _ = services.ReportChapterTypeSync(&syncReq)
 	}()
@@ -474,30 +465,21 @@ func (this *ReportChapterTypeController) AuthSetting() {
 		permissionIdName[permissionList[i].ChartPermissionId] = permissionList[i].PermissionName
 	}
 
-	researchType := item.ResearchType
 	nowTime := time.Now().Local()
-	newPermissions := make([]*models.ReportChapterTypePermission, 0)       // 报告章节权限表(新)
-	newWeekPermissions := make([]*models.ChartPermissionChapterMapping, 0) // 报告章节权限表(老)
+	newPermissions := make([]*models.ReportChapterTypePermission, 0) // 报告章节权限表(新)
 	for i := range req.ChartPermissionIdList {
 		newPermissions = append(newPermissions, &models.ReportChapterTypePermission{
 			ReportChapterTypeId:   item.ReportChapterTypeId,
 			ReportChapterTypeName: item.ReportChapterTypeName,
 			ChartPermissionId:     req.ChartPermissionIdList[i],
 			PermissionName:        permissionIdName[req.ChartPermissionIdList[i]],
-			ResearchType:          researchType,
-			CreatedTime:           nowTime,
+			//ResearchType:          researchType,
+			CreatedTime: nowTime,
 		})
-		if researchType == utils.REPORT_TYPE_WEEK {
-			newWeekPermissions = append(newWeekPermissions, &models.ChartPermissionChapterMapping{
-				ChartPermissionId:   req.ChartPermissionIdList[i],
-				ReportChapterTypeId: item.ReportChapterTypeId,
-				ResearchType:        researchType,
-			})
-		}
 	}
 
 	// 设置权限
-	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, researchType, newPermissions, newWeekPermissions)
+	e = models.SetReportChapterTypePermission(item.ReportChapterTypeId, newPermissions)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "设置章节类型权限失败, Err: " + e.Error()
@@ -546,7 +528,7 @@ func (this *ReportChapterTypeController) PermissionList() {
 		br.Msg = "章节不存在或已被删除"
 		return
 	}
-	list, e := models.GetChapterTypePermissionByTypeIdAndResearchType(typeId, item.ResearchType)
+	list, e := models.GetChapterTypePermissionByReportChapterTypeId(typeId)
 	if e != nil {
 		br.Msg = "章节不存在或已被删除"
 		br.ErrMsg = "获取章节类型权限列表失败, Err: " + e.Error()

+ 1262 - 0
controllers/report_v2.go

@@ -0,0 +1,1262 @@
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report"
+	"eta/eta_api/models/report_approve"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/services/data"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"html"
+	"strconv"
+	"time"
+)
+
+// TODO 报告的权限校验(跳过列表页,直接进入详情页,不管是普通报告还是章节报告)
+
+// ListReport
+// @Title 获取报告列表接口
+// @Description 获取报告列表
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   TimeType     query string true  "筛选的时间类别:publish_time(发布时间),modify_time(更新时间);approve_time(审批时间)"
+// @Param   StartDate   query   string  true       "开始时间"
+// @Param   EndDate   query   string  true       "结束时间"
+// @Param   Frequency   query   string  true       "频度"
+// @Param   ClassifyIdFirst   query   int  true       "一级分类id"
+// @Param   ClassifyIdSecond   query   int  true       "二级分类id"
+// @Param   ClassifyIdThird   query   int  true       "三级分类id"
+// @Param   State   query   int  true       "状态"
+// @Param   KeyWord   query   string  true       "搜索关键词"
+// @Param   PublishSort   query   string  true       "desc:降序,asc 升序(预留)"
+// @Param   FilterReportType   query   string  true       "筛选报告类型,1:公共研报,2:共享研报,3:我的研报"
+// @Success 200 {object} models.ReportListResp
+// @router /list [get]
+func (this *ReportController) ListReport() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+
+	timeType := this.GetString("TimeType")
+	startDate := this.GetString("StartDate")
+	endDate := this.GetString("EndDate")
+	frequency := this.GetString("Frequency")
+	classifyIdFirst, _ := this.GetInt("ClassifyIdFirst", 0)
+	classifyIdSecond, _ := this.GetInt("ClassifyIdSecond", 0)
+	classifyIdThird, _ := this.GetInt("ClassifyIdThird", 0)
+	state, _ := this.GetInt("State")
+	keyWord := this.GetString("KeyWord")
+	msgIsSend, _ := this.GetInt("MsgIsSend")
+	filterReportType, _ := this.GetInt("FilterReportType", 1)
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	if timeType == "" {
+		timeType = "publish_time"
+	}
+	if timeType != "publish_time" && timeType != "modify_time" && timeType != "approve_time" {
+		br.Msg = "请选择正确的时间"
+		br.ErrMsg = "请选择正确的时间"
+		return
+	}
+
+	var condition string
+	var pars []interface{}
+
+	if keyWord != "" {
+		condition += ` AND (a.title LIKE ? OR a.admin_real_name LIKE ? ) `
+		pars = utils.GetLikeKeywordPars(pars, keyWord, 2)
+	}
+	if startDate != "" {
+		condition += ` AND a.` + timeType + ` >= ? `
+		pars = append(pars, startDate)
+	}
+	if endDate != "" {
+		condition += ` AND a.` + timeType + ` <= ? `
+		pars = append(pars, endDate)
+	}
+	if frequency != "" {
+		condition += ` AND a.frequency = ? `
+		pars = append(pars, frequency)
+	}
+
+	if classifyIdFirst > 0 {
+		condition += ` AND a.classify_id_first = ? `
+		pars = append(pars, classifyIdFirst)
+	}
+	if classifyIdSecond > 0 {
+		condition += ` AND a.classify_id_second = ? `
+		pars = append(pars, classifyIdSecond)
+	}
+	if classifyIdThird > 0 {
+		condition += ` AND a.classify_id_third = ? `
+		pars = append(pars, classifyIdSecond)
+	}
+
+	if state > 0 {
+		condition += ` AND a.state = ? `
+		pars = append(pars, state)
+	}
+	// 消息是否已推送 1-未推送; 2-已推送
+	if msgIsSend == 1 {
+		condition += ` AND (a.msg_is_send = 0 OR a.ths_msg_is_send = 0) `
+	}
+	if msgIsSend == 2 {
+		condition += ` AND a.msg_is_send = 1 AND a.ths_msg_is_send = 1 `
+	}
+
+	var err error
+	var total int
+	var list []*models.ReportList
+
+	switch filterReportType {
+	// 筛选报告类型,1:公共研报,2:共享研报,3:我的研报
+	case 1:
+		condition += ` AND a.is_public_publish = ? `
+		// TODO 临时使用,提测上线前得打开注释
+		//condition += `  AND a.state in (2,6) `
+		pars = append(pars, 1)
+	case 3:
+		condition += ` AND a.admin_id = ? `
+		pars = append(pars, this.SysUser.AdminId)
+	case 2:
+		condition += ` AND (a.admin_id = ? or b.admin_id = ?) `
+		pars = append(pars, this.SysUser.AdminId, this.SysUser.AdminId)
+	}
+
+	// 共享报告需要连表查询,所以需要单独写
+	if filterReportType == 2 {
+		total, err = models.GetReportListCountByGrant(condition, pars)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+		list, err = models.GetReportListByGrant(condition, pars, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		total, err = models.GetReportListCountV1(condition, pars)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+		list, err = models.GetReportListV1(condition, pars, startSize, pageSize)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	listLen := len(list)
+	if listLen > 0 {
+		pvMap := make(map[int]int)
+		uvMap := make(map[int]int)
+		reportIdArr := make([]string, 0)
+		syncReportIdArr := make([]string, 0)      // 同步过来的报告IDs
+		oldAndNewReportIdMap := make(map[int]int) // 旧报告和新报告的id对应关系
+		for i := 0; i < listLen; i++ {
+			reportIdArr = append(reportIdArr, strconv.Itoa(list[i].Id))
+			if list[i].OldReportId > 0 {
+				syncReportIdArr = append(syncReportIdArr, strconv.Itoa(list[i].OldReportId))
+				oldAndNewReportIdMap[list[i].OldReportId] = list[i].Id
+			}
+			pvMap[list[i].Id] = list[i].Pv
+			uvMap[list[i].Id] = list[i].Uv
+		}
+
+		// 当下报告的pv,uv
+		if len(reportIdArr) > 0 {
+			pvList, e := models.GetReportPvUvByReportIdList(reportIdArr)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取同步报告对应的PV、UV失败, Err: " + e.Error()
+				return
+			}
+			for _, v := range pvList {
+				pv := pvMap[v.ReportId]
+				uv := uvMap[v.ReportId]
+				pvMap[v.ReportId] = v.PvTotal + pv
+				uvMap[v.ReportId] = v.UvTotal + uv
+			}
+		}
+
+		//reportIds := strings.Join(reportIdArr, ",")
+		//syncReportIds := strings.Join(syncReportIdArr, ",")
+
+		// 查询同步过来的报告对应的老报告PV+UV
+		if len(syncReportIdArr) > 0 {
+			puvList, e := models.GetPUVByResearchReportIds(syncReportIdArr)
+			if e != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取同步报告对应的PV、UV失败, Err: " + e.Error()
+				return
+			}
+			puvLen := len(puvList)
+			for i := 0; i < puvLen; i++ {
+				newReportId, ok := oldAndNewReportIdMap[puvList[i].ResearchReportId]
+				if ok {
+					pv := pvMap[newReportId]
+					uv := uvMap[newReportId]
+					pvMap[newReportId] = puvList[i].Pv + pv
+					uvMap[newReportId] = puvList[i].Uv + uv
+				}
+			}
+		}
+		// 晨周报音频列表
+		videoList, err := models.GetReportChapterVideoListByReportIds(reportIdArr)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取报告音频文件失败,Err:" + err.Error()
+			return
+		}
+		for i := 0; i < listLen; i++ {
+			list[i].Content = html.UnescapeString(list[i].Content)
+			list[i].ContentSub = html.UnescapeString(list[i].ContentSub)
+			// 除周报外其余报告均可推送客群
+			list[i].NeedThsMsg = 1
+			//if list[i].HasChapter == 1 && list[i].ChapterType == utils.REPORT_TYPE_WEEK {
+			//	list[i].NeedThsMsg = 0
+			//}
+			chapterList := make([]*models.ReportChapterVideoList, 0)
+			for ii := 0; ii < len(videoList); ii++ {
+				if list[i].Id == videoList[ii].ReportId {
+					chapterList = append(chapterList, videoList[ii])
+				}
+			}
+			list[i].ChapterVideoList = chapterList
+			list[i].Pv += pvMap[list[i].Id]
+			list[i].Uv += uvMap[list[i].Id]
+		}
+	}
+
+	for _, item := range list {
+		/*key := fmt.Sprint(`crm:report:edit:`, item.Id)
+		opUserId, _ := utils.Rc.RedisInt(key)
+		//如果当前没有人操作,获取当前操作人是本人,那么编辑按钮可用
+		if opUserId <= 0 || (opUserId == this.SysUser.AdminId) || item.ClassifyNameFirst == "周报" || item.ClassifyNameFirst == "晨报" {
+			item.CanEdit = true
+		} else {
+			adminInfo, errAdmin := system.GetSysUserById(opUserId)
+			if errAdmin != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取失败,Err:" + errAdmin.Error()
+				return
+			}
+			item.Editor = adminInfo.RealName
+		}*/
+		if item.HasChapter == 1 {
+			item.CanEdit = true
+			continue
+		}
+		markStatus, err := services.UpdateReportEditMark(item.Id, 0, this.SysUser.AdminId, 2, this.SysUser.RealName, this.Lang)
+		if err != nil {
+			br.Msg = "查询标记状态失败"
+			br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
+			return
+		}
+		if markStatus.Status == 0 {
+			item.CanEdit = true
+		} else {
+			item.Editor = markStatus.Editor
+		}
+	}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(models.ReportListResp)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// Add
+// @Title 新增报告接口
+// @Description 新增报告(不区分报告类型)
+// @Param	request	body models.AddReq true "type json string"
+// @Success 200 {object} models.AddResp
+// @router /add [post]
+func (this *ReportController) Add() {
+	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.AddReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.Title == `` {
+		br.Msg = "标题不能为空"
+		br.ErrMsg = "标题不能为空"
+		br.IsSendEmail = false
+		return
+	}
+	if req.ClassifyIdFirst <= 0 {
+		br.Msg = "分类必填"
+		br.ErrMsg = "分类必填"
+		br.IsSendEmail = false
+		return
+	}
+
+	var contentSub string
+	if req.Content != "" {
+		e := utils.ContentXssCheck(req.Content)
+		if e != nil {
+			br.Msg = "存在非法标签"
+			br.ErrMsg = "存在非法标签, Err: " + e.Error()
+			return
+		}
+		content, e := services.FilterReportContentBr(req.Content)
+		if e != nil {
+			br.Msg = "内容去除前后空格失败"
+			br.ErrMsg = "内容去除前后空格失败, Err: " + e.Error()
+			return
+		}
+		req.Content = content
+
+		contentSub, err = services.GetReportContentSub(req.Content)
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("ContentSub 失败,Err:"+err.Error(), 3)
+			//utils.SendEmail(utils.APPNAME+"失败提醒", "解析 ContentSub 失败,Err:"+err.Error(), utils.EmailSendToUsers)
+		}
+	}
+
+	// 报告期数
+	maxStage, err := models.GetReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird)
+	if err != nil {
+		br.Msg = "期数获取失败!"
+		br.ErrMsg = "期数获取失败,Err:" + err.Error()
+		return
+	}
+
+	// 根据审批开关及审批流判断当前报告状态
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeChinese, req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird, models.ReportOperateAdd)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
+		return
+	}
+
+	// 协作方式,1:个人,2:多人协作。默认:1
+	if req.CollaborateType == 0 {
+		req.CollaborateType = 1
+	}
+	// 报告布局,1:常规布局,2:智能布局。默认:1
+	if req.ReportLayout == 0 {
+		req.ReportLayout = 1
+	}
+	// 是否公开发布,1:是,2:否
+	if req.IsPublicPublish == 0 {
+		req.IsPublicPublish = 1
+	}
+
+	item := new(models.Report)
+	item.AddType = req.AddType
+	item.ReportVersion = 2
+	item.ClassifyIdFirst = req.ClassifyIdFirst
+	item.ClassifyNameFirst = req.ClassifyNameFirst
+	item.ClassifyIdSecond = req.ClassifyIdSecond
+	item.ClassifyNameSecond = req.ClassifyNameSecond
+	item.Title = req.Title
+	item.Abstract = req.Abstract
+	item.Author = req.Author
+	item.Frequency = req.Frequency
+	item.State = state
+	item.Content = html.EscapeString(req.Content)
+	item.Stage = maxStage + 1
+	item.ContentSub = html.EscapeString(contentSub)
+	item.CreateTime = req.CreateTime
+	item.ModifyTime = time.Now()
+	item.ReportVersion = req.ReportVersion
+	item.AdminId = sysUser.AdminId
+	item.AdminRealName = sysUser.RealName
+
+	item.ClassifyIdThird = req.ClassifyIdThird
+	item.ClassifyNameThird = req.ClassifyNameThird
+
+	// 产品要求,如果是多人协作,那么就是章节类型的报告
+	if req.CollaborateType == 2 {
+		item.HasChapter = 1
+		item.ChapterType = ""
+	}
+	item.LastModifyAdminId = sysUser.AdminId
+	item.LastModifyAdminName = sysUser.RealName
+	item.ContentModifyTime = time.Now()
+	item.NeedSplice = 0
+	item.ContentStruct = html.EscapeString(req.ContentStruct)
+	item.HeadImg = req.HeadImg
+	item.EndImg = req.EndImg
+	item.CanvasColor = req.CanvasColor
+	item.HeadResourceId = req.HeadResourceId
+	item.EndResourceId = req.EndResourceId
+	item.CollaborateType = req.CollaborateType
+	item.ReportLayout = req.ReportLayout
+	item.IsPublicPublish = req.IsPublicPublish
+	item.ReportCreateTime = time.Now()
+
+	err, errMsg := services.AddReportAndChapter(item, req.InheritReportId, req.GrantAdminIdList)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	recordItem := &models.ReportStateRecord{
+		ReportId:   item.Id,
+		ReportType: 1,
+		State:      1,
+		AdminId:    this.SysUser.AdminId,
+		AdminName:  this.SysUser.AdminName,
+		CreateTime: time.Now(),
+	}
+	go func() {
+		_, _ = models.AddReportStateRecord(recordItem)
+	}()
+
+	resp := new(models.AddResp)
+	resp.ReportId = int64(item.Id)
+	resp.ReportCode = item.ReportCode
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+}
+
+// Edit
+// @Title 编辑报告基础信息接口
+// @Description 编辑报告基础信息(不区分报告类型)
+// @Param	request	body models.EditReq true "type json string"
+// @Success 200 {object} models.EditResp
+// @router /edit [post]
+func (this *ReportController) Edit() {
+	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.EditReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	//if req.Content == "" {
+	//	br.Msg = "报告内容不能为空"
+	//	return
+	//}
+	//更新标记key
+	markStatus, err := services.UpdateReportEditMark(int(req.ReportId), 0, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
+	if err != nil {
+		br.Msg = err.Error()
+		return
+	}
+	if markStatus.Status == 1 {
+		br.Msg = markStatus.Msg
+		//br.Ret = 202 //202 服务器已接受请求,但尚未处理。
+		return
+	}
+
+	reportInfo, e := models.GetReportByReportId(int(req.ReportId))
+	if e != nil {
+		if e.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除, 请刷新页面"
+			return
+		}
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取报告失败, Err: " + e.Error()
+		return
+	}
+
+	if reportInfo.State == models.ReportStatePublished || reportInfo.State == models.ReportStatePass {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	// 编辑报告信息
+	err, errMsg := services.EditReport(reportInfo, req, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != "" {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	reportCode := utils.MD5(strconv.Itoa(int(req.ReportId)))
+	resp := new(models.EditResp)
+	resp.ReportId = req.ReportId
+	resp.ReportCode = reportCode
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+}
+
+// Detail
+// @Title 获取报告详情接口
+// @Description 获取报告详情
+// @Param	request	body models.ReportDetailReq true "type json string"
+// @Success 200 {object} models.Report
+// @router /detail [get]
+func (this *ReportController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	/*var req models.ReportDetailReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}*/
+	reportId, err := this.GetInt("ReportId")
+	if err != nil {
+		br.Msg = "获取参数失败!"
+		br.ErrMsg = "获取参数失败,Err:" + err.Error()
+		return
+	}
+	if reportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	item, err := models.GetReportById(reportId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	chapterList := make([]*models.ReportChapter, 0)
+	if item.HasChapter == 1 {
+		// 获取章节内容
+		tmpChapterList, err := models.GetPublishedChapterListByReportId(item.Id)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取晨/周报章节列表失败, Err: " + err.Error()
+			return
+		}
+
+		// TODO 更新规则
+		if len(tmpChapterList) > 0 {
+			// 获取更新规则
+			researchType := tmpChapterList[0].ReportType
+			chapterTypeList, tmpErr := models.GetAllReportChapterTypeListByResearchType(researchType)
+			if tmpErr != nil {
+				br.Msg = "获取更新规则失败"
+				br.ErrMsg = "获取更新规则失败, Err: " + tmpErr.Error()
+				return
+			}
+			// 调整章节更新
+			nowTime := time.Now().Local()
+			for _, item := range tmpChapterList {
+				stop := false
+				for _, rule := range chapterTypeList {
+					if rule.ReportChapterTypeId == item.TypeId {
+						//fmt.Println("rule.Enabled :", rule.Enabled, ";name=", rule.ReportChapterTypeName, "item.IsEdit:", item.IsEdit, "rule.IsSet:", rule.IsSet)
+						// 如果被永久暂停更新了
+						if rule.Enabled == 0 && item.IsEdit == 0 { //该章节已被永久禁用,同时未被操作过
+							stop = true
+						} else if rule.PauseStartTime != "" && rule.PauseEndTime != "" && rule.PauseStartTime != utils.EmptyDateStr && rule.PauseEndTime != utils.EmptyDateStr {
+							startTime, timeErr := time.ParseInLocation(utils.FormatDate, rule.PauseStartTime, time.Local)
+							if timeErr != nil {
+								br.Msg = "获取更新规则失败"
+								br.ErrMsg = "更新规则时间转换失败4001, Err: " + timeErr.Error()
+								return
+							}
+							endTime, timeErr := time.ParseInLocation(utils.FormatDate, rule.PauseEndTime, time.Local)
+							if timeErr != nil {
+								br.Msg = "获取更新规则失败"
+								br.ErrMsg = "更新规则时间转换失败4002, Err: " + timeErr.Error()
+								return
+							}
+							// 暂停更新
+							if nowTime.After(startTime) && nowTime.Before(endTime.AddDate(0, 0, 1)) {
+								stop = true
+							}
+							break
+						}
+					}
+				}
+				if !stop {
+					item.Content = html.UnescapeString(item.Content)
+					item.ContentSub = html.UnescapeString(item.ContentSub)
+					chapterList = append(chapterList, item)
+				}
+			}
+		}
+
+		item.Abstract = item.Title
+	}
+	item.Content = html.UnescapeString(item.Content)
+	item.ContentSub = html.UnescapeString(item.ContentSub)
+	item.ContentStruct = html.UnescapeString(item.ContentStruct)
+
+	resp := &models.ReportDetailView{
+		ReportDetail: item,
+		ChapterList:  chapterList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// SaveReportContent
+// @Title 保存草稿
+// @Description 保存草稿
+// @Param	request	body models.SaveReportContent true "type json string"
+// @Success 200 {object} models.ReportAuthorResp
+// @router /saveReportContent [post]
+func (this *ReportController) SaveReportContent() {
+	br := new(models.BaseResponse).Init()
+	br.IsSendEmail = false
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req models.SaveReportContent
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	reportId := req.ReportId
+	noChangeFlag := req.NoChange
+
+	if reportId <= 0 {
+		resp := new(models.SaveReportContentResp)
+		resp.ReportId = reportId
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "保存成功"
+		br.Data = resp
+		return
+	}
+
+	// 获取报告详情
+	reportInfo, _ := models.GetReportByReportId(int(req.ReportId))
+	if reportInfo != nil && reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	// 标记更新中
+	{
+		markStatus, err := services.UpdateReportEditMark(int(req.ReportId), 0, sysUser.AdminId, 1, sysUser.RealName, this.Lang)
+		if err != nil {
+			br.Msg = err.Error()
+			return
+		}
+		if markStatus.Status == 1 {
+			br.Msg = markStatus.Msg
+			return
+		}
+	}
+
+	// 内容有过修改的话,那么逻辑处理
+	if noChangeFlag != 1 {
+		content := req.Content
+		if content == "" {
+			content = this.GetString("Content")
+		}
+		if content != "" {
+			e := utils.ContentXssCheck(req.Content)
+			if e != nil {
+				br.Msg = "存在非法标签"
+				br.ErrMsg = "存在非法标签, Err: " + e.Error()
+				return
+			}
+			contentClean, e := services.FilterReportContentBr(req.Content)
+			if e != nil {
+				br.Msg = "内容去除前后空格失败"
+				br.ErrMsg = "内容去除前后空格失败, Err: " + e.Error()
+				return
+			}
+			content = contentClean
+
+			contentSub, err := services.GetReportContentSub(content)
+			if err != nil {
+				go alarm_msg.SendAlarmMsg("解析 ContentSub 失败,Err:"+err.Error(), 3)
+				//utils.SendEmail(utils.APPNAME+"失败提醒", "解析 ContentSub 失败,Err:"+err.Error(), utils.EmailSendToUsers)
+			}
+			reportInfo.Content = html.EscapeString(content)
+			reportInfo.ContentSub = html.EscapeString(contentSub)
+			reportInfo.ContentStruct = html.EscapeString(req.ContentStruct)
+			reportInfo.HeadImg = req.HeadImg
+			reportInfo.EndImg = req.EndImg
+			reportInfo.CanvasColor = req.CanvasColor
+			reportInfo.HeadResourceId = req.HeadResourceId
+			reportInfo.EndResourceId = req.EndResourceId
+			reportInfo.ModifyTime = time.Now()
+			reportInfo.ContentModifyTime = time.Now()
+			updateCols := []string{"Content", "ContentSub", "ContentStruct", "HeadImg", "EndImg", "CanvasColor", "HeadResourceId", "EndResourceId", "ModifyTime", "ContentModifyTime"}
+			err = reportInfo.UpdateReport(updateCols)
+			if err != nil {
+				br.Msg = "保存失败"
+				br.ErrMsg = "保存失败,Err:" + err.Error()
+				return
+			}
+			go models.AddReportSaveLog(reportId, this.SysUser.AdminId, reportInfo.Content, reportInfo.ContentSub, reportInfo.ContentStruct, reportInfo.CanvasColor, this.SysUser.AdminName, reportInfo.HeadResourceId, reportInfo.EndResourceId)
+		}
+	}
+
+	resp := new(models.SaveReportContentResp)
+	resp.ReportId = reportId
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+}
+
+// PublishDayWeekReportChapter
+// @Title 发布晨周报章节
+// @Description 发布晨周报章节
+// @Param	request	body models.PublishReportChapterReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /publishDayWeekReportChapter [post]
+func (this *ReportController) PublishDayWeekReportChapter() {
+	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
+	}
+	if req.Title == "" {
+		br.Msg = "请输入标题"
+		return
+	}
+	if req.Content == "" {
+		br.Msg = "请输入内容"
+		return
+	}
+	if req.AddType == 0 {
+		br.Msg = "请选择新增方式"
+		return
+	}
+
+	reqTickerList := req.TickerList
+
+	chapterInfo, err := models.GetReportChapterInfoById(req.ReportChapterId)
+	if err != nil {
+		br.Msg = "章节信息有误"
+		br.ErrMsg = "获取章节信息失败, Err: " + err.Error()
+		return
+	}
+
+	reportInfo, err := models.GetReportById(chapterInfo.ReportId)
+	if err != nil {
+		br.Msg = "查询报告有误"
+		br.ErrMsg = "查询报告信息失败, Err: " + err.Error()
+		return
+	}
+	if reportInfo.State == 2 {
+		br.Msg = "该报告已发布,不允许编辑"
+		br.ErrMsg = "该报告已发布,不允许编辑"
+		return
+	}
+
+	// 图表刷新状态
+	refreshResult := data.CheckBatchChartRefreshResult("report", chapterInfo.ReportId, chapterInfo.ReportChapterId)
+	if !refreshResult {
+		br.Msg = "图表刷新未完成,请稍后操作"
+		br.ErrMsg = "图表刷新未完成,请稍后操作"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取规则配置
+	reportChapterTypeRule, err := models.GetReportChapterTypeById(chapterInfo.TypeId)
+	if err != nil {
+		br.Msg = "获取配置信息异常"
+		br.ErrMsg = "获取配置信息异常, Err: " + err.Error()
+		return
+	}
+	if reportChapterTypeRule.Enabled == 0 {
+		br.Msg = "该章节已永久停更"
+		br.ErrMsg = "该章节已永久停更 "
+		br.IsSendEmail = false
+		return
+	}
+
+	updateCols := make([]string, 0)
+	updateCols = append(updateCols, "Title", "AddType", "Author", "Content", "ContentSub", "IsEdit", "CreateTime", "PublishState", "PublishTime")
+
+	var needHandleVideo bool // 是否需要处理音频文件
+	nowTime := time.Now()
+	var publishTime time.Time
+	if reportInfo.MsgIsSend == 1 && reportInfo.PublishTime != "" { //如果报告曾经发布过,并且已经发送过模版消息,则章节的发布时间为报告的发布时间
+		publishTime, _ = time.ParseInLocation(utils.FormatDateTime, reportInfo.PublishTime, time.Local)
+	} else {
+		publishTime = time.Now()
+	}
+	if req.VideoUrl != "" {
+		chapterInfo.VideoUrl = req.VideoUrl
+		chapterInfo.VideoName = req.VideoName
+		chapterInfo.VideoSize = req.VideoSize
+		chapterInfo.VideoPlaySeconds = req.VideoPlaySeconds
+		chapterInfo.VideoKind = 1
+
+		updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds", "VideoKind")
+
+		// 手动上传的音频需要处理音频文件
+		needHandleVideo = true
+	} else {
+		if chapterInfo.VideoUrl == "" {
+			// 生成video
+			videoUrl, videoName, videoSize, videoPlaySeconds, err := services.CreateReportVideo(req.Title, req.Content, publishTime.Format(utils.FormatDateTime))
+			if err != nil {
+				br.Msg = "生成video失败"
+				br.ErrMsg = "生成video失败, Err: " + err.Error()
+				return
+			}
+			chapterInfo.VideoUrl = videoUrl
+			chapterInfo.VideoName = videoName
+			chapterInfo.VideoSize = videoSize
+			chapterInfo.VideoPlaySeconds = fmt.Sprintf("%.2f", videoPlaySeconds)
+			chapterInfo.VideoKind = 2
+			updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds", "VideoKind")
+		}
+	}
+
+	// 更新章节信息
+	contentSub := ""
+	if req.Content != "" {
+		e := utils.ContentXssCheck(req.Content)
+		if e != nil {
+			br.Msg = "存在非法标签"
+			br.ErrMsg = "存在非法标签, Err: " + e.Error()
+			return
+		}
+		contentClean, e := services.FilterReportContentBr(req.Content)
+		if e != nil {
+			br.Msg = "内容去除前后空格失败"
+			br.ErrMsg = "内容去除前后空格失败, Err: " + e.Error()
+			return
+		}
+		req.Content = contentClean
+
+		contentSub, err = services.GetReportContentSub(req.Content)
+		if err != nil {
+			br.Msg = "内容分段解析失败"
+			br.ErrMsg = "编辑报告章节-解析 ContentSub 失败, Err: " + err.Error()
+			return
+		}
+	}
+	chapterInfo.Title = req.Title
+	chapterInfo.AddType = req.AddType
+	chapterInfo.Author = req.Author
+	chapterInfo.Content = html.EscapeString(req.Content)
+	chapterInfo.ContentSub = html.EscapeString(contentSub)
+	chapterInfo.IsEdit = 1
+	chapterInfo.CreateTime = req.CreateTime
+	chapterInfo.PublishState = 2
+	chapterInfo.PublishTime = publishTime
+
+	// 晨报更新指标
+	tickerList := make([]*models.ReportChapterTicker, 0)
+	if chapterInfo.ReportType == "day" && len(reqTickerList) > 0 {
+		for i := 0; i < len(reqTickerList); i++ {
+			tickerList = append(tickerList, &models.ReportChapterTicker{
+				ReportChapterId: chapterInfo.ReportChapterId,
+				Sort:            reqTickerList[i].Sort,
+				Ticker:          reqTickerList[i].Ticker,
+				CreateTime:      nowTime,
+				UpdateTime:      nowTime,
+			})
+		}
+	}
+	if err = models.UpdateChapterAndTicker(chapterInfo, updateCols, tickerList); err != nil {
+		br.Msg = "发布失败"
+		br.ErrMsg = "报告章节内容保存失败, Err: " + err.Error()
+		return
+	}
+	// 更新章节ES
+	{
+		go services.UpdateReportChapterEs(chapterInfo.ReportChapterId)
+	}
+
+	// 同时发布报告
+	if req.PublishReport == 1 {
+		if _, e := services.PublishDayWeekReport(chapterInfo.ReportId); e != nil {
+			br.Msg = "章节发布成功,报告发布失败,请手动发布报告"
+			br.ErrMsg = "发布晨/周报失败, Err: " + e.Error()
+			return
+		}
+	}
+
+	// 处理报告中的音频文件分贝
+	if needHandleVideo {
+		go services.HandleVideoDecibel(chapterInfo)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// AuthorizedListReport
+// @Title 获取有权限的报告列表接口
+// @Description 获取有权限的报告列表接口
+// @Param   PageSize   query   int  true       "每页数据条数"
+// @Param   CurrentIndex   query   int  true       "当前页页码,从1开始"
+// @Param   Keyword   query   string  true       "搜索关键词"
+// @Param   ClassifyIdFirst   query   int  true       "一级分类id"
+// @Param   ClassifyIdSecond   query   int  true       "二级分类id"
+// @Param   ClassifyIdThird   query   int  true       "三级分类id"
+// @Success 200 {object} models.ReportListResp
+// @router /list/authorized [get]
+func (this *ReportController) AuthorizedListReport() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	keyword := this.GetString("Keyword")
+	classifyIdFirst, _ := this.GetInt("ClassifyIdFirst", 0)
+	classifyIdSecond, _ := this.GetInt("ClassifyIdSecond", 0)
+	classifyIdThird, _ := this.GetInt("ClassifyIdThird", 0)
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize20
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+	var list []*models.ReportList
+
+	// 没有输入信息,那就不展示
+	if keyword == `` && classifyIdFirst <= 0 {
+		page := paging.GetPaging(currentIndex, pageSize, 0)
+		resp := new(models.ReportListResp)
+		resp.Paging = page
+		resp.List = list
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
+		return
+	}
+
+	// 当前用户有权限的报告id列表
+	grantReportIdList := make([]int, 0)
+	{
+		obj := report.ReportGrant{}
+		grantList, err := obj.GetGrantListByAdminId(this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取授权报告id失败,Err:" + err.Error()
+			return
+		}
+		for _, v := range grantList {
+			grantReportIdList = append(grantReportIdList, v.ReportId)
+		}
+	}
+
+	var condition string
+	var pars []interface{}
+
+	if classifyIdFirst > 0 {
+		condition += ` AND a.classify_id_first = ? `
+		pars = append(pars, classifyIdFirst)
+	}
+	if classifyIdSecond > 0 {
+		condition += ` AND a.classify_id_second = ? `
+		pars = append(pars, classifyIdSecond)
+	}
+	if classifyIdThird > 0 {
+		condition += ` AND a.classify_id_third = ? `
+		pars = append(pars, classifyIdSecond)
+	}
+
+	if keyword != `` {
+		condition += ` AND a.title LIKE ? `
+		pars = utils.GetLikeKeywordPars(pars, keyword, 1)
+	}
+
+	var err error
+	var total int
+
+	orCondition := `AND ( (a.is_public_publish = ? AND a.state in (2,6)) or a.admin_id = ? `
+	pars = append(pars, 1, this.SysUser.AdminId)
+
+	// 当前用户有权限的报告id列表
+	num := len(grantReportIdList)
+	if num > 0 {
+		orCondition += ` OR a.id in (` + utils.GetOrmInReplace(num) + `)`
+		pars = append(pars, grantReportIdList)
+	}
+	orCondition += ` ) `
+
+	condition += orCondition
+
+	total, err = models.GetReportListCountByAuthorized(condition, pars)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+	list, err = models.GetReportListByAuthorized(condition, pars, startSize, pageSize)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	//for _, item := range list {
+	//	if item.HasChapter == 1 {
+	//		item.CanEdit = true
+	//	} else {
+	//		markStatus, err := services.UpdateReportEditMark(item.Id, this.SysUser.AdminId, 2, this.SysUser.RealName, this.Lang)
+	//		if err != nil {
+	//			br.Msg = "查询标记状态失败"
+	//			br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
+	//			return
+	//		}
+	//		if markStatus.Status == 0 {
+	//			item.CanEdit = true
+	//		} else {
+	//			item.Editor = markStatus.Editor
+	//		}
+	//	}
+	//}
+
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(models.ReportListResp)
+	resp.Paging = page
+	resp.List = list
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// BaseDetail
+// @Title 获取报告基础信息详情接口
+// @Description 获取报告基础信息详情接口
+// @Param	request	body models.ReportDetailReq true "type json string"
+// @Success 200 {object} models.Report
+// @router /detail/base [get]
+func (this *ReportController) BaseDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	/*var req models.ReportDetailReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}*/
+	reportId, err := this.GetInt("ReportId")
+	if err != nil {
+		br.Msg = "获取参数失败!"
+		br.ErrMsg = "获取参数失败,Err:" + err.Error()
+		return
+	}
+	if reportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	reportInfo, err := models.GetReportById(reportId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	// 基础信息就不获取章节信息了
+	chapterList := make([]*models.ReportChapter, 0)
+
+	reportInfo.Content = html.UnescapeString(reportInfo.Content)
+	reportInfo.ContentSub = html.UnescapeString(reportInfo.ContentSub)
+
+	grandAdminList := make([]models.ReportDetailViewAdmin, 0)
+	permissionList := make([]models.ReportDetailViewPermission, 0)
+
+	// 处理报告授权用户列表
+	{
+		obj := report.ReportGrant{}
+		grantList, tmpErr := obj.GetGrantListById(reportId)
+		if tmpErr != nil {
+			br.Msg = "获取章节id授权用户列表失败"
+			br.ErrMsg = "获取章节id授权用户列表失败, Err: " + tmpErr.Error()
+			return
+		}
+
+		if len(grantList) > 0 {
+			grandAdminIdList := make([]int, 0)
+			for _, v := range grantList {
+				grandAdminIdList = append(grandAdminIdList, v.AdminId)
+			}
+			adminList, tmpErr := system.GetAdminListByIdList(grandAdminIdList)
+			if tmpErr != nil {
+				br.Msg = "获取章节id授权用户列表失败"
+				br.ErrMsg = "获取章节id授权用户列表失败, Err: " + tmpErr.Error()
+				return
+			}
+			for _, v := range adminList {
+				grandAdminList = append(grandAdminList, models.ReportDetailViewAdmin{
+					AdminId:   v.AdminId,
+					AdminName: v.RealName,
+				})
+			}
+		}
+
+	}
+
+	// 处理章节id关联品种id列表
+	{
+		minClassifyId := reportInfo.ClassifyIdThird
+		if minClassifyId <= 0 {
+			minClassifyId = reportInfo.ClassifyIdSecond
+		}
+		if minClassifyId <= 0 {
+			minClassifyId = reportInfo.ClassifyIdFirst
+		}
+		if minClassifyId <= 0 {
+			br.Msg = "分类异常"
+			br.ErrMsg = "分类异常"
+			return
+		}
+
+		// 获取分类关联的品种id
+		classifyPermissionList, tmpErr := models.GetPermission(minClassifyId)
+		if tmpErr != nil {
+			br.Msg = "获取分类信息失败"
+			br.ErrMsg = "获取失败,Err:" + tmpErr.Error()
+			return
+		}
+
+		if len(classifyPermissionList) > 0 {
+			permissionIdList := make([]int, 0)
+			for _, v := range classifyPermissionList {
+				permissionIdList = append(permissionIdList, v.ChartPermissionId)
+			}
+			adminList, tmpErr := models.GetChartPermissionByIdList(permissionIdList)
+			if tmpErr != nil {
+				br.Msg = "获取章节id授权用户列表失败"
+				br.ErrMsg = "获取章节id授权用户列表失败, Err: " + tmpErr.Error()
+				return
+			}
+			for _, v := range adminList {
+				permissionList = append(permissionList, models.ReportDetailViewPermission{
+					PermissionId:   v.ChartPermissionId,
+					PermissionName: v.ChartPermissionName,
+				})
+			}
+		}
+
+	}
+
+	resp := &models.ReportDetailView{
+		ReportDetail:   reportInfo,
+		ChapterList:    chapterList,
+		GrandAdminList: grandAdminList,
+		PermissionList: permissionList,
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// TODO 报告发布后,图片和pdf的生成

+ 35 - 6
controllers/sandbox/sandbox.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/sandbox/request"
 	"eta/eta_api/models/sandbox/response"
+	"eta/eta_api/services/data"
 	sandboxService "eta/eta_api/services/sandbox"
 	"eta/eta_api/utils"
 	"fmt"
@@ -1029,7 +1030,7 @@ func (this *SandboxController) EditSandboxClassify() {
 		br.ErrMsg = "查询子级分类id失败,Err:" + err.Error()
 		return
 	}
-	err  = sandbox.UpdateSandboxClassifyChartPermissionById(req.ChartPermissionId, req.ChartPermissionName, ids)
+	err = sandbox.UpdateSandboxClassifyChartPermissionById(req.ChartPermissionId, req.ChartPermissionName, ids)
 	if err != nil {
 		br.Msg = "修改子级分类错误"
 		br.ErrMsg = "修改子级分类错误,Err:" + err.Error()
@@ -1646,7 +1647,7 @@ func (this *SandboxController) ChartClassifyMove() {
 					br.ErrMsg = "获取上级分类信息失败,Err:" + err.Error()
 					return
 				}
-				err  = sandbox.UpdateSandboxClassifyChartPermissionById(parentChartClassifyInfo.ChartPermissionId, parentChartClassifyInfo.ChartPermissionName, ids)
+				err = sandbox.UpdateSandboxClassifyChartPermissionById(parentChartClassifyInfo.ChartPermissionId, parentChartClassifyInfo.ChartPermissionName, ids)
 				if err != nil {
 					br.Msg = "修改子级分类错误"
 					br.ErrMsg = "修改子级分类错误,Err:" + err.Error()
@@ -1802,6 +1803,7 @@ func (this *SandboxController) SaveV2() {
 
 	var errMsg string
 
+	var sandBoxData *sandbox.Sandbox
 	if req.SandboxId <= 0 {
 		//新增沙盘
 		sandboxResp, err = sandboxService.AddSandboxV2(req, sysUser.AdminId, sysUser.RealName)
@@ -1813,6 +1815,7 @@ func (this *SandboxController) SaveV2() {
 			br.ErrMsg = "保存失败,Err:" + err.Error()
 			return
 		}
+		sandBoxData = sandboxResp.Sandbox
 	} else {
 		//编辑沙盘
 		sandboxInfo := &sandbox.Sandbox{
@@ -1841,8 +1844,12 @@ func (this *SandboxController) SaveV2() {
 			br.ErrMsg = "保存失败,Err:" + err.Error()
 			return
 		}
+		sandBoxData = sandboxInfo
 	}
 
+	//解析逻辑图的指标
+	_ = data.SaveSandBoxEdbInfoRelation(sandBoxData.SandboxId, sandBoxData.Content)
+
 	msg := "保存成功"
 	br.Ret = 200
 	br.Success = true
@@ -2376,8 +2383,15 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		br.ErrMsg = "获取指标信息失败,err:" + err.Error()
 		return
 	}
+	edbList := make([]*sandbox.SandboxLinkCheckItem, 0)
 	for _, v := range edbInfoList {
-		resp.EdbInfoIdList = append(resp.EdbInfoIdList, v.EdbInfoId)
+		tmp := &sandbox.SandboxLinkCheckItem{
+			Id:         v.EdbInfoId,
+			Name:       v.EdbName,
+			UniqueCode: v.UniqueCode,
+			ClassifyId: v.ClassifyId,
+		}
+		edbList = append(edbList, tmp)
 	}
 
 	chartList, err := data_manage.GetChartInfoByIdList(req.ChartInfoIdList)
@@ -2386,8 +2400,15 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		br.ErrMsg = `获取图表列表失败,ERR:` + err.Error()
 		return
 	}
+	chartListTmp := make([]*sandbox.SandboxLinkCheckItem, 0)
 	for _, v := range chartList {
-		resp.ChartInfoIdList = append(resp.ChartInfoIdList, v.ChartInfoId)
+		tmp := &sandbox.SandboxLinkCheckItem{
+			Id:         v.ChartInfoId,
+			Name:       v.ChartName,
+			UniqueCode: v.UniqueCode,
+			ClassifyId: v.ChartClassifyId,
+		}
+		chartListTmp = append(chartListTmp, tmp)
 	}
 
 	reportList, err := models.GetSimpleReportByIds(req.ReportIdList)
@@ -2396,10 +2417,18 @@ func (this *SandboxController) LinkEdbInfoCheck() {
 		br.ErrMsg = `获取报告列表失败,ERR:` + err.Error()
 		return
 	}
+	reportListTmp := make([]*sandbox.SandboxLinkCheckItem, 0)
 	for _, v := range reportList {
-		resp.ReportIdList = append(resp.ReportIdList, v.Id)
+		tmp := &sandbox.SandboxLinkCheckItem{
+			Id:         v.Id,
+			Name:       v.Title,
+			UniqueCode: v.ReportCode,
+		}
+		reportListTmp = append(reportListTmp, tmp)
 	}
-
+	resp.EdbInfoIdList = edbList
+	resp.ChartInfoIdList = chartListTmp
+	resp.ReportIdList = reportListTmp
 	br.Ret = 200
 	br.Msg = "检测成功"
 	br.Success = true

+ 7 - 8
controllers/smart_report/smart_report.go

@@ -79,7 +79,7 @@ func (this *SmartReportController) Add() {
 	stageMax += 1
 
 	// 根据审批开关及审批流判断当前报告状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, req.ClassifyIdFirst, req.ClassifyIdSecond, models.ReportOperateAdd)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, req.ClassifyIdFirst, req.ClassifyIdSecond, 0, models.ReportOperateAdd)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -247,7 +247,7 @@ func (this *SmartReportController) Edit() {
 		contentModify = true
 	}
 	cols := []string{"ClassifyIdFirst", "ClassifyNameFirst", "ClassifyIdSecond", "ClassifyNameSecond", "Title", "Abstract", "Author",
-		"Frequency", "Content", "ContentSub", "ContentStruct", "ModifyTime", "HeadImg", "EndImg", "CanvasColor","HeadResourceId", "EndResourceId"}
+		"Frequency", "Content", "ContentSub", "ContentStruct", "ModifyTime", "HeadImg", "EndImg", "CanvasColor", "HeadResourceId", "EndResourceId"}
 	item.ClassifyIdFirst = req.ClassifyIdFirst
 	item.ClassifyNameFirst = req.ClassifyNameFirst
 	item.ClassifyIdSecond = req.ClassifyIdSecond
@@ -484,7 +484,7 @@ func (this *SmartReportController) Publish() {
 	}
 
 	// 根据审批开关及审批流判断当前报告状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, item.ClassifyIdFirst, item.ClassifyIdSecond, operate)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, item.ClassifyIdFirst, item.ClassifyIdSecond, 0, operate)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告当前状态失败, Err: " + e.Error()
@@ -851,7 +851,7 @@ func (this *SmartReportController) SaveContent() {
 		item.CanvasColor = req.CanvasColor
 		item.HeadResourceId = req.HeadResourceId
 		item.EndResourceId = req.EndResourceId
-		cols := []string{"Content", "ContentSub", "ContentStruct", "ContentModifyTime", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime", "HeadImg", "EndImg", "CanvasColor","HeadResourceId", "EndResourceId"}
+		cols := []string{"Content", "ContentSub", "ContentStruct", "ContentModifyTime", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime", "HeadImg", "EndImg", "CanvasColor", "HeadResourceId", "EndResourceId"}
 		if e = item.Update(cols); e != nil {
 			br.Msg = "操作失败"
 			br.ErrMsg = "更新报告内容失败"
@@ -1404,7 +1404,7 @@ func (this *SmartReportController) SubmitApprove() {
 	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateSubmitApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateSubmitApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
@@ -1427,7 +1427,7 @@ func (this *SmartReportController) SubmitApprove() {
 	}
 
 	// 提交审批
-	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeSmart, reportItem.SmartReportId, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, sysUser.AdminId, sysUser.RealName)
+	approveId, e := services.SubmitReportApprove(report_approve.FlowReportTypeSmart, reportItem.SmartReportId, reportItem.Title, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, sysUser.AdminId, sysUser.RealName)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "提交审批失败, Err: " + e.Error()
@@ -1495,7 +1495,7 @@ func (this *SmartReportController) CancelApprove() {
 	}
 
 	// 校验当前审批配置, 返回下一个状态
-	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, models.ReportOperateCancelApprove)
+	state, e := services.CheckReportCurrState(report_approve.FlowReportTypeSmart, reportItem.ClassifyIdFirst, reportItem.ClassifyIdSecond, 0, models.ReportOperateCancelApprove)
 	if e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "校验报告状态失败, Err: " + e.Error()
@@ -1543,4 +1543,3 @@ func (this *SmartReportController) CancelApprove() {
 	br.Success = true
 	br.Msg = "操作成功"
 }
-

+ 3 - 3
controllers/sys_team.go

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

+ 41 - 6
controllers/target.go

@@ -183,6 +183,14 @@ func (this *TargetController) DataAdd() {
 		br.ErrMsg = "新增失败,Err:" + err.Error()
 		return
 	}
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, edbdata.TradeCode)
+		if err != nil {
+			fmt.Println("DataAdd CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+		}
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "新增成功"
@@ -314,6 +322,13 @@ func (this *TargetController) DataEdit() {
 			}
 		}
 	}
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, edbdata.TradeCode)
+		if err != nil {
+			fmt.Println("DataEdit CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+		}
+	}
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "编辑成功"
@@ -344,11 +359,13 @@ func (this *TargetController) BatchDataEdit() {
 	}
 
 	edbDataEditList := make([]data.EdbDataEdit, 0)
+	edbCodeMap := make(map[string]string)
 	for _, trade := range req.List {
 		if trade.TradeCode == "" {
 			br.Msg = "指标编码不可为空!"
 			return
 		}
+		edbCodeMap[trade.TradeCode] = trade.TradeCode
 
 		close := ""
 		loc := reflect.ValueOf(trade.Close).Kind().String()
@@ -379,6 +396,15 @@ func (this *TargetController) BatchDataEdit() {
 		br.ErrMsg = "批量修改失败:" + err.Error()
 		return
 	}
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		for _, edbCode := range edbCodeMap {
+			err = utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, edbCode)
+			if err != nil {
+				fmt.Println("BatchDataEdit CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+			}
+		}
+	}
 	br.Ret = 200
 	br.Success = true
 	br.Data = failEdbDataList
@@ -1647,6 +1673,15 @@ func (this *TargetController) DataDelete() {
 		br.ErrMsg = "删除失败,Err:" + err.Error()
 		return
 	}
+
+	//将该指标的code加入到 “手工数据导入后刷新” 缓存
+	if utils.Re == nil {
+		err := utils.Rc.LPush(utils.CACHE_IMPORT_MANUAL_DATA, req.TradeCode)
+		if err != nil {
+			fmt.Println("DataDelete CACHE_IMPORT_MANUAL_DATA LPush Err:" + err.Error())
+		}
+	}
+
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "删除成功"
@@ -2436,13 +2471,13 @@ func (this *TargetController) TargetFrequencyList() {
 
 func sortEdbFrequency(frequencyList []string) (newFrequencyList []string) {
 	var frequencyMap1 = map[string]int{
-		"日度":  1,
-		"周度":  2,
-		"旬度":  3,
-		"月度":  4,
-		"季度":  5,
+		"日度":   1,
+		"周度":   2,
+		"旬度":   3,
+		"月度":   4,
+		"季度":   5,
 		"半年度": 6,
-		"年度":  7,
+		"年度":   7,
 	}
 
 	var frequencyMap2 = map[int]string{

+ 1 - 1
go.mod

@@ -39,7 +39,7 @@ require (
 	github.com/silenceper/wechat/v2 v2.1.6
 	github.com/spf13/viper v1.7.0
 	github.com/tealeg/xlsx v1.0.5
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.880
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.880
 	github.com/xuri/excelize/v2 v2.8.1

+ 2 - 3
go.sum

@@ -560,9 +560,8 @@ github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2K
 github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/tealeg/xlsx v1.0.5 h1:+f8oFmvY8Gw1iUXzPk+kz+4GpbDZPK1FhPiQRd+ypgE=
 github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873 h1:CbeN5Fdzq3xea36+ZKPQcuRwwJk0ZYQRxcyWkyK5768=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.873/go.mod h1:vzSh5OxbOCyFt+SdlEd9oCQGBb1oObkD7Xfod/UPvVk=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.873/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.880 h1:keIcDofAxKjSlh1EmBkXIA7aCFkEWH9UP19NbV9KGas=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.880/go.mod h1:J+pg3uRzo+jcSBSUYpEuUD4CE5OfEKsMohHLZne9Pa0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880 h1:0Ok1pZ06/zZMCiW8Dm8wYOGJK1HCU5OXwNSyE5UVOAM=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.880/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/ses v1.0.880 h1:PnzU5KS7x3LQGE0yetGLEGwJtLb6Uzsd79mbCiRh1rw=

+ 1 - 2
models/business_conf.go

@@ -42,11 +42,10 @@ const (
 	BusinessConfLoginEmailTemplateContent = "LoginEmailTemplateContent"
 	BusinessConfLdapBindUserSuffix        = "LdapBindUserSuffix"
 	BusinessConfLdapUserFilter            = "LdapUserFilter"
-
+	BusinessConfSmsJhgjVariable           = "SmsJhgjVariable" // 聚合国际短信变量
 	BusinessConfTencentApiSecretId           = "TencentApiSecretId"           // 腾讯云API-密钥对
 	BusinessConfTencentApiSecretKey          = "TencentApiSecretKey"          // 腾讯云API-密钥对
 	BusinessConfTencentApiRecTaskCallbackUrl = "TencentApiRecTaskCallbackUrl" // 腾讯云API-语音识别回调地址
-	BusinessConfSmsJhgjVariable              = "SmsJhgjVariable"              // 聚合国际短信变量
 )
 
 const (

+ 29 - 0
models/chart_permission.go

@@ -215,6 +215,14 @@ func (c *ChartPermission) GetFirstChartPermissionByParentId(parentId int) (item
 	return
 }
 
+// GetChartPermissionList 获取品种权限列表
+func GetChartPermissionList() (list []*ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("weekly")
+	sql := `SELECT * FROM chart_permission ORDER BY product_id ASC, sort ASC`
+	_, err = o.Raw(sql).QueryRows(&list)
+	return
+}
+
 // GetChartPermissionById 主键获取品种
 func GetChartPermissionById(permissionId int) (item *ChartPermission, err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -246,6 +254,7 @@ func FormatChartPermission2Simple(origin *ChartPermission) (item *SimpleChartPer
 	item.ChartPermissionId = origin.ChartPermissionId
 	item.ChartPermissionName = origin.PermissionName
 	item.Sort = origin.Sort
+
 	return
 }
 
@@ -254,5 +263,25 @@ func GetChartPermissionsByProductId() (list []*ChartPermission, err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := `SELECT * FROM chart_permission WHERE product_id = ? AND enabled = 1 ORDER BY parent_id ASC, sort ASC, created_time ASC`
 	_, err = o.Raw(sql, FiccProductId).QueryRows(&list)
+
+	return
+}
+
+// GetChartPermissionByIdList
+// @Description: 根据品种ID列表获取权限列表
+// @author: Roc
+// @datetime 2024-06-07 10:32:29
+// @param permissionIdList []int
+// @return items []*ChartPermission
+// @return err error
+func GetChartPermissionByIdList(permissionIdList []int) (items []*ChartPermission, err error) {
+	num := len(permissionIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM chart_permission WHERE chart_permission_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, permissionIdList).QueryRows(&items)
+
 	return
 }

+ 3 - 2
models/data_manage/base_from_trade_index.go

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

+ 9 - 0
models/data_manage/chart_edb_mapping.go

@@ -210,6 +210,15 @@ func GetChartEdbMappingByEdbInfoId(edbInfoId int) (item *ChartEdbInfoMapping, er
 	return
 }
 
+// GetEdbMappingListByEdbInfoId 根据指标id获取edb_mapping
+func GetEdbMappingListByEdbInfoId(edbInfoId int) (item []*ChartEdbInfoMapping, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM chart_edb_mapping
+			 WHERE edb_info_id = ? limit 1`
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&item)
+	return
+}
+
 // GetChartEdbMappingByFutureGoodEdbInfoId 根据指标id获取edb_mapping
 func GetChartEdbMappingByFutureGoodEdbInfoId(edbInfoId int) (item *ChartEdbInfoMapping, err error) {
 	o := orm.NewOrmUsingDB("data")

+ 105 - 75
models/data_manage/chart_info.go

@@ -991,85 +991,115 @@ func EditChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr string, calenda
 	}
 	chartEdbMappingIdList := make([]string, 0)
 
-	for _, v := range chartEdbInfoList {
-		// 查询该指标是否存在,如果存在的话,那么就去修改,否则新增
-		var tmpChartEdbMapping *ChartEdbMapping
-		csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND edb_info_id=? AND source = ? `
-		err = to.Raw(csql, req.ChartInfoId, v.EdbInfoId, utils.CHART_SOURCE_DEFAULT).QueryRow(&tmpChartEdbMapping)
-		if err != nil && err.Error() != utils.ErrNoRow() {
-			fmt.Println("QueryRow Err:", err.Error())
-			return err
-		}
-		if tmpChartEdbMapping != nil {
-			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(tmpChartEdbMapping.ChartEdbMappingId))
-			tmpChartEdbMapping.ModifyTime = time.Now()
-			tmpChartEdbMapping.MaxData = v.MaxData
-			tmpChartEdbMapping.MinData = v.MinData
-			tmpChartEdbMapping.IsOrder = v.IsOrder
-			tmpChartEdbMapping.IsAxis = v.IsAxis
-			tmpChartEdbMapping.EdbInfoType = v.EdbInfoType
-			tmpChartEdbMapping.LeadValue = v.LeadValue
-			tmpChartEdbMapping.LeadUnit = v.LeadUnit
-			tmpChartEdbMapping.ChartStyle = v.ChartStyle
-			tmpChartEdbMapping.ChartColor = v.ChartColor
-			tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
-			tmpChartEdbMapping.ChartWidth = v.ChartWidth
-			tmpChartEdbMapping.EdbAliasName = v.EdbAliasName
-			tmpChartEdbMapping.IsConvert = v.IsConvert
-			tmpChartEdbMapping.ConvertType = v.ConvertType
-			tmpChartEdbMapping.ConvertValue = v.ConvertValue
-			tmpChartEdbMapping.ConvertUnit = v.ConvertUnit
-			tmpChartEdbMapping.ConvertEnUnit = v.ConvertEnUnit
-			_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName",
-				"IsConvert", "ConvertType", "ConvertValue", "ConvertUnit", "ConvertEnUnit")
-			if err != nil {
-				fmt.Println("chart_edb_mapping Err:" + err.Error())
-				return err
-			}
-		} else {
-			mapItem := new(ChartEdbMapping)
-			mapItem.ChartInfoId = req.ChartInfoId
-			mapItem.EdbInfoId = v.EdbInfoId
-			mapItem.CreateTime = time.Now()
-			mapItem.ModifyTime = time.Now()
-			timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
-			mapItem.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp + "_" + strconv.Itoa(v.EdbInfoId))
-			mapItem.MaxData = v.MaxData
-			mapItem.MinData = v.MinData
-			mapItem.IsOrder = v.IsOrder
-			mapItem.IsAxis = v.IsAxis
-			mapItem.EdbInfoType = v.EdbInfoType
-			mapItem.LeadValue = v.LeadValue
-			mapItem.LeadUnit = v.LeadUnit
-			mapItem.ChartStyle = v.ChartStyle
-			mapItem.ChartColor = v.ChartColor
-			mapItem.PredictChartColor = v.PredictChartColor
-			mapItem.ChartWidth = v.ChartWidth
-			mapItem.Source = utils.CHART_SOURCE_DEFAULT
-			mapItem.EdbAliasName = v.EdbAliasName
-			mapItem.IsConvert = v.IsConvert
-			mapItem.ConvertType = v.ConvertType
-			mapItem.ConvertValue = v.ConvertValue
-			mapItem.ConvertUnit = v.ConvertUnit
-			mapItem.ConvertEnUnit = v.ConvertEnUnit
-			tmpId, err := to.Insert(mapItem)
-			if err != nil {
-				fmt.Println("AddChartEdbMapping Err:" + err.Error())
-				return err
+	// 获取已经配置的关联指标列表
+	var tmpChartEdbMappingList []*ChartEdbMapping
+	csql := `SELECT *  FROM chart_edb_mapping WHERE chart_info_id=? AND source = ? ORDER BY chart_edb_mapping_id ASC`
+	_, err = to.Raw(csql, req.ChartInfoId, utils.CHART_SOURCE_DEFAULT).QueryRows(&tmpChartEdbMappingList)
+	if err != nil {
+		fmt.Println("获取已经配置的关联指标列表 Err:", err.Error())
+		return err
+	}
+
+	// 已经配置的关联指标列表长度下标
+	tmpEdbIndex := len(tmpChartEdbMappingList) - 1
+	// 当下要配置的关联指标列表长度下标
+	reqEdbIndex := len(chartEdbInfoList) - 1
+
+	addChartEdbList := make([]*ChartEdbMapping, 0)
+	removeIdList := make([]int, 0)
+	for k, v := range chartEdbInfoList {
+		// 如果当前下标小于等于已经配置的关联指标的最大长度,那么就校验
+		if k <= tmpEdbIndex {
+			tmpChartEdbMapping := tmpChartEdbMappingList[k]
+
+			// 顺序未变
+			if tmpChartEdbMapping.EdbInfoId == v.EdbInfoId {
+				chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(tmpChartEdbMapping.ChartEdbMappingId))
+				tmpChartEdbMapping.ModifyTime = time.Now()
+				tmpChartEdbMapping.MaxData = v.MaxData
+				tmpChartEdbMapping.MinData = v.MinData
+				tmpChartEdbMapping.IsOrder = v.IsOrder
+				tmpChartEdbMapping.IsAxis = v.IsAxis
+				tmpChartEdbMapping.EdbInfoType = v.EdbInfoType
+				tmpChartEdbMapping.LeadValue = v.LeadValue
+				tmpChartEdbMapping.LeadUnit = v.LeadUnit
+				tmpChartEdbMapping.ChartStyle = v.ChartStyle
+				tmpChartEdbMapping.ChartColor = v.ChartColor
+				tmpChartEdbMapping.PredictChartColor = v.PredictChartColor
+				tmpChartEdbMapping.ChartWidth = v.ChartWidth
+				tmpChartEdbMapping.EdbAliasName = v.EdbAliasName
+				tmpChartEdbMapping.IsConvert = v.IsConvert
+				tmpChartEdbMapping.ConvertType = v.ConvertType
+				tmpChartEdbMapping.ConvertValue = v.ConvertValue
+				tmpChartEdbMapping.ConvertUnit = v.ConvertUnit
+				tmpChartEdbMapping.ConvertEnUnit = v.ConvertEnUnit
+				_, err = to.Update(tmpChartEdbMapping, "ModifyTime", "MaxData", "MinData", "IsOrder", "IsAxis", "EdbInfoType", "LeadValue", "LeadUnit", "ChartStyle", "ChartColor", "PredictChartColor", "ChartWidth", "EdbAliasName",
+					"IsConvert", "ConvertType", "ConvertValue", "ConvertUnit", "ConvertEnUnit")
+				if err != nil {
+					fmt.Println("chart_edb_mapping Err:" + err.Error())
+					return err
+				}
+				continue
+			} else {
+				// 如果是指标的顺序变了,那么需要删除该配置,进行新的配置
+				removeIdList = append(removeIdList, tmpChartEdbMapping.ChartEdbMappingId)
 			}
-			mapItem.ChartEdbMappingId = int(tmpId)
-			chartEdbMappingIdList = append(chartEdbMappingIdList, strconv.Itoa(mapItem.ChartEdbMappingId))
+		}
+
+		// 如果是指标的顺序变了 或者
+		// 如果当前下标是超过了已经配置的关联指标的最大长度,那么就新增
+		mapItem := new(ChartEdbMapping)
+		mapItem.ChartInfoId = req.ChartInfoId
+		mapItem.EdbInfoId = v.EdbInfoId
+		mapItem.CreateTime = time.Now()
+		mapItem.ModifyTime = time.Now()
+		timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+		mapItem.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp + "_" + strconv.Itoa(v.EdbInfoId))
+		mapItem.MaxData = v.MaxData
+		mapItem.MinData = v.MinData
+		mapItem.IsOrder = v.IsOrder
+		mapItem.IsAxis = v.IsAxis
+		mapItem.EdbInfoType = v.EdbInfoType
+		mapItem.LeadValue = v.LeadValue
+		mapItem.LeadUnit = v.LeadUnit
+		mapItem.ChartStyle = v.ChartStyle
+		mapItem.ChartColor = v.ChartColor
+		mapItem.PredictChartColor = v.PredictChartColor
+		mapItem.ChartWidth = v.ChartWidth
+		mapItem.Source = utils.CHART_SOURCE_DEFAULT
+		mapItem.EdbAliasName = v.EdbAliasName
+		mapItem.IsConvert = v.IsConvert
+		mapItem.ConvertType = v.ConvertType
+		mapItem.ConvertValue = v.ConvertValue
+		mapItem.ConvertUnit = v.ConvertUnit
+		mapItem.ConvertEnUnit = v.ConvertEnUnit
+
+		addChartEdbList = append(addChartEdbList, mapItem)
+	}
+
+	// 当前保存的指标数与已有的指标数不一致,需要删除已有的指标关联配置
+	if reqEdbIndex < tmpEdbIndex {
+		for i := reqEdbIndex + 1; i <= tmpEdbIndex; i++ {
+			removeIdList = append(removeIdList, tmpChartEdbMappingList[i].ChartEdbMappingId)
 		}
 	}
-	if len(chartEdbMappingIdList) > 0 {
-		chartEdbMappingIdStr := strings.Join(chartEdbMappingIdList, ",")
-		dsql := `DELETE FROM chart_edb_mapping WHERE chart_info_id=? AND chart_edb_mapping_id NOT IN(` + chartEdbMappingIdStr + `)`
-		_, err = to.Raw(dsql, req.ChartInfoId).Exec()
+
+	// 删除已经移除了的指标关联配置
+	removeNum := len(removeIdList)
+	if removeNum > 0 {
+		dsql := `DELETE FROM chart_edb_mapping WHERE chart_info_id=? AND chart_edb_mapping_id  IN(` + utils.GetOrmInReplace(removeNum) + `)`
+		_, err = to.Raw(dsql, req.ChartInfoId, removeIdList).Exec()
 		if err != nil {
 			fmt.Println("delete err:" + err.Error())
 			return err
 		}
 	}
+
+	// 将新的指标关联配置写入
+	if len(addChartEdbList) > 0 {
+		_, err = to.InsertMulti(500, addChartEdbList)
+	}
+
 	return
 }
 
@@ -1763,10 +1793,10 @@ func GetChartInfoByClassifyIdAndName(classifyId int, chartName string) (item *Ch
 
 // BatchChartRefreshReq 批量刷新图表请求
 type BatchChartRefreshReq struct {
-	ChartInfoCode   []string `description:"图表编码数组"`
-	ReportId        int      `description:"报告id"`
-	ReportChapterId int      `description:"报告章节id"`
-	Source          string   `description:"来源,枚举值:report、english_report、smart_report"`
+	ChartInfoCode []string `description:"图表编码数组"`
+	PrimaryId     int      `description:"研报/智能研报/PPT主键"`
+	SubId         int      `description:"报告章节ID"`
+	Source        string   `description:"来源,枚举值:report、english_report、smart_report、ppt"`
 }
 
 // GetChartInfoListByUniqueCodeSlice 根据图表编码获取图表列表数据

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

@@ -72,6 +72,22 @@ func GetChartInfoCrossVarietyByChartInfoId(id int) (item *ChartInfoCrossVariety,
 	return
 }
 
+func GetChartInfoCrossVarietyByXEdbInfoId(edbInfoId int) (items []*ChartInfoCrossVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.* FROM chart_info_cross_variety a 
+         join chart_tag_variety b on a.chart_x_tag_id=b.chart_tag_id WHERE b.edb_info_id = ? `
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
+	return
+}
+
+func GetChartInfoCrossVarietyByYEdbInfoId(edbInfoId int) (items []*ChartInfoCrossVariety, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT a.* FROM chart_info_cross_variety a 
+         join chart_tag_variety b on a.chart_y_tag_id=b.chart_tag_id WHERE b.edb_info_id = ? `
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
+	return
+}
+
 // CreateChart
 // @Description: 新增跨品种图表
 // @author: Roc

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

@@ -260,3 +260,14 @@ func GetChartTagVarietyListByTagIdList(chartTagIdList []int) (items []*ChartTagV
 
 	return
 }
+
+func DeleteChartTagVarietyByEdbInfoId(edbInfoId int) (err error) {
+	// 删除不存在的品种
+	o := orm.NewOrmUsingDB("data")
+	sql := ` DELETE FROM chart_tag_variety WHERE edb_info_id=?`
+	_, err = o.Raw(sql, edbInfoId, edbInfoId).Exec()
+	if err != nil {
+		return
+	}
+	return
+}

+ 13 - 3
models/data_manage/edb_classify.go

@@ -298,10 +298,20 @@ type EdbClassifyListResp struct {
 }
 
 type ClassifyDeleteCheckResp struct {
-	DeleteStatus int    `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:若目录关联指标不可删除,2:确认删除当前目录及包含的子目录吗,3:当前指标已用作画图,不可删除"`
-	TipsMsg      string `description:"提示信息"`
+	DeleteStatus int              `description:"检测状态:0:默认值,如果为0,继续走其他校验,1:若目录关联指标不可删除,2:确认删除当前目录及包含的子目录吗,3:当前指标已用作画图,不可删除"`
+	TipsMsg      string           `description:"提示信息"`
+	TableList    []*ExcelBaseInfo `description:"关联的表格"`
+}
+type ExcelBaseInfo struct {
+	ExcelInfoId     int    `orm:"column(excel_info_id);pk"`
+	Source          int    `description:"表格来源,1:excel插件的表格,2:自定义表格,3:混合表格,4:自定义分析,默认:1"`
+	ExcelType       int    `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName       string `description:"表格名称"`
+	UniqueCode      string `description:"表格唯一编码"`
+	ExcelClassifyId int    `description:"表格分类id"`
+	//SysUserId       int    `description:"操作人id"`
+	//SysUserRealName string `description:"操作人真实姓名"`
 }
-
 type ClassifyDeleteCheckReq struct {
 	ClassifyId int `description:"分类id"`
 	EdbInfoId  int `description:"指标id"`

+ 15 - 5
models/data_manage/edb_data_base.go

@@ -331,13 +331,15 @@ func GetBaseIndexInfoByEdbCode(edbCode string, source int) (item *BaseIndexInfo,
 	return
 }
 
-func GetBaseIndexTableName(source int) (tableName string) {
-	edbSource := EdbSourceIdMap[source]
-	if edbSource != nil {
-		tableName = edbSource.IndexTableName
-	}
+func GetEdbDataBaseByCodeAndDate(source, subSource int, edbCode string, startDate string) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	tableName := GetEdbDataTableName(source, subSource)
+	sql := ` SELECT COUNT(1) AS count FROM %s WHERE edb_code=? AND data_time=? `
+	sql = fmt.Sprintf(sql, tableName)
+	err = o.Raw(sql, edbCode, startDate).QueryRow(&count)
 	return
 }
+
 func GetEdbDataAllByEdbCodeAndSubSource(edbCode string, source, subSource, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCode)
@@ -380,6 +382,14 @@ func GetEdbDataTableNameAndSubSource(source, subSource int) (tableName string) {
 	return
 }
 
+func GetBaseIndexTableName(source int) (tableName string) {
+	edbSource := EdbSourceIdMap[source]
+	if edbSource != nil {
+		tableName = edbSource.IndexTableName
+	}
+	return
+}
+
 func GetEdbDataAllByEdbCodes(edbCodes []string, limit int) (items []*EdbInfoSearchData, err error) {
 	var pars []interface{}
 	pars = append(pars, edbCodes)

+ 32 - 0
models/data_manage/edb_data_wind.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"eta/eta_api/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -63,3 +64,34 @@ type EdbDataFromWind struct {
 	Dt     map[string]int64   `json:"DT"`
 	ErrMsg string
 }
+
+func WindEdbInfoUpdateStatusByEdbInfoId(edbInfoId, isStop, subSource int, calculateEdbInfoIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 更改指标的更新状态
+	sql := ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_info_id=? `
+	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_WIND, subSource, edbInfoId).Exec()
+	if err != nil {
+		return
+	}
+	if len(calculateEdbInfoIds) > 0 {
+		// 批量更新相关联的指标ID
+		sql = ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}

+ 161 - 4
models/data_manage/edb_info.go

@@ -1,6 +1,8 @@
 package data_manage
 
 import (
+	"encoding/json"
+	"eta/eta_api/models/data_manage/line_equation/request"
 	"eta/eta_api/models/mgo"
 	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
@@ -8,6 +10,7 @@ import (
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
 	"go.mongodb.org/mongo-driver/bson"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -32,6 +35,7 @@ type EdbInfo struct {
 	UniqueCode       string `description:"指标唯一编码"`
 	CreateTime       time.Time
 	ModifyTime       time.Time
+	BaseModifyTime   time.Time
 	MinValue         float64 `description:"指标最小值"`
 	MaxValue         float64 `description:"指标最大值"`
 	CalculateFormula string  `description:"计算公式"`
@@ -48,8 +52,6 @@ type EdbInfo struct {
 	Calendar         string  `description:"公历/农历" orm:"default(公历);"`
 	DataDateType     string  `orm:"column(data_date_type);size(255);null;default(交易日)"`
 	ManualSave       int     `description:"是否有手动保存过上下限: 0-否; 1-是"`
-	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
-	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	TerminalCode     string  `description:"终端编码,用于配置在机器上"`
 	DataUpdateTime   string  `description:"最近一次数据发生变化的时间"`
 	ErDataUpdateDate string  `description:"本次更新,数据发生变化的最早日期"`
@@ -58,6 +60,8 @@ type EdbInfo struct {
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
 	StockCode        string  `description:"证券代码"`
+	EmptyType        int     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	Extra            string  `description:"指标额外配置"`
 	IsJoinPermission int     `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
 }
@@ -247,10 +251,21 @@ func DeleteEdbInfoAndData(edbInfoId, source, subSource int) (err error) {
 	// 删除计算指标的关系
 	sql = ` DELETE FROM edb_info_calculate_mapping WHERE edb_info_id=? `
 	_, err = to.Raw(sql, edbInfoId).Exec()
-
+	if err != nil {
+		return
+	}
 	// 删除预测指标的配置
 	sql = ` DELETE FROM predict_edb_conf WHERE predict_edb_info_id=? `
 	_, err = to.Raw(sql, edbInfoId).Exec()
+	if err != nil {
+		return
+	}
+	// 删除跨品种分析标签绑定的指标
+	sql = ` DELETE FROM chart_tag_variety WHERE edb_info_id=?`
+	_, err = to.Raw(sql, edbInfoId).Exec()
+	if err != nil {
+		return
+	}
 	return
 }
 
@@ -851,7 +866,123 @@ func ReplaceChartEdb(oldEdbInfo, newEdbInfo *EdbInfo) (relationEdbInfoIdList []i
 			return
 		}
 		replaceChartTotal = len(chartEdbMappingList)
+		// 查询所有的相关的图表信息
+		chartInfoIds := make([]string, 0)
+		if len(chartEdbMappingList) > 0 {
+			for _, chartEdbMapping := range chartEdbMappingList {
+				chartInfoIds = append(chartInfoIds, strconv.Itoa(chartEdbMapping.ChartInfoId))
+			}
+		}
 
+		if len(chartInfoIds) > 0 {
+			chartInfoList, e := GetChartInfoListByChartIdList(chartInfoIds)
+			if e != nil {
+				err = e
+				errmsg = "获取图表信息失败:Err:" + e.Error()
+				return
+			}
+			for _, chartInfo := range chartInfoList {
+				updateStr := make([]string, 0)
+				if chartInfo.EdbInfoIds != "" && strings.Contains(chartInfo.EdbInfoIds, strconv.Itoa(oldEdbInfo.EdbInfoId)) {
+					//需要更换
+					//解析字符串
+					edbInfoIds := strings.Split(chartInfo.EdbInfoIds, ",")
+					for i, edbInfoId := range edbInfoIds {
+						if edbInfoId == strconv.Itoa(oldEdbInfo.EdbInfoId) {
+							edbInfoIds[i] = strconv.Itoa(newEdbInfo.EdbInfoId)
+						}
+					}
+					chartInfo.EdbInfoIds = strings.Join(edbInfoIds, ",")
+					updateStr = append(updateStr, "EdbInfoIds")
+				}
+				if chartInfo.ExtraConfig != "" {
+					//判断是否是拟合方程或者散点图截面图
+					if chartInfo.Source == utils.CHART_SOURCE_LINE_EQUATION {
+						//解析配置内容
+						var lineChartInfoConfig request.LineChartInfoReq
+						err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &lineChartInfoConfig)
+						if err != nil {
+							errmsg = "获取图表配置信息失败 json.Unmarshal:Err:" + e.Error()
+							return
+						}
+						xEdbInfoIdList := lineChartInfoConfig.XEdbInfoIdList
+						yEdbInfoIdList := lineChartInfoConfig.YEdbInfoIdList
+						if len(xEdbInfoIdList) > 0 {
+							// 循环判断是否存在
+							for k, xEdbInfoId := range xEdbInfoIdList {
+								if xEdbInfoId == oldEdbInfo.EdbInfoId {
+									xEdbInfoIdList[k] = newEdbInfo.EdbInfoId
+								}
+							}
+						}
+						if len(yEdbInfoIdList) > 0 {
+							// 循环判断是否存在
+							for k, yEdbInfoId := range yEdbInfoIdList {
+								if yEdbInfoId == oldEdbInfo.EdbInfoId {
+									yEdbInfoIdList[k] = newEdbInfo.EdbInfoId
+								}
+							}
+						}
+						// 替换新的指标信息
+						lineChartInfoConfig.XEdbInfoIdList = xEdbInfoIdList
+						lineChartInfoConfig.YEdbInfoIdList = yEdbInfoIdList
+						// 重新序列化
+						lineChartInfoConfigJson, e := json.Marshal(lineChartInfoConfig)
+						if e != nil {
+							err = e
+							errmsg = "图表配置信息序列化失败:json.Marshal Err: " + e.Error()
+							return
+						}
+						lineChartInfoConfigStr := string(lineChartInfoConfigJson)
+						// 更新图表配置信息
+						chartInfo.ExtraConfig = lineChartInfoConfigStr
+						updateStr = append(updateStr, "ExtraConfig")
+					} else if chartInfo.ChartType == utils.CHART_TYPE_SECTION_SCATTER {
+						//解析配置内容
+						var tmpExtraConfig SectionScatterReq
+						err = json.Unmarshal([]byte(chartInfo.ExtraConfig), &tmpExtraConfig)
+						if err != nil {
+							errmsg = "获取截面散点图配置信息失败 json.Unmarshal:Err:" + e.Error()
+							return
+						}
+						//找到指标信息,并替换
+						if len(tmpExtraConfig.SeriesList) > 0 {
+							for k1, series := range tmpExtraConfig.SeriesList {
+								for k2, item := range series.EdbInfoList {
+									if item.XEdbInfoId == oldEdbInfo.EdbInfoId {
+										tmpExtraConfig.SeriesList[k1].EdbInfoList[k2].XEdbInfoId = newEdbInfo.EdbInfoId
+									}
+									if item.YEdbInfoId == oldEdbInfo.EdbInfoId {
+										tmpExtraConfig.SeriesList[k1].EdbInfoList[k2].YEdbInfoId = newEdbInfo.EdbInfoId
+									}
+								}
+							}
+						}
+						// 重新序列化
+						sectionScatterConfigJson, e := json.Marshal(tmpExtraConfig)
+						if e != nil {
+							err = e
+							errmsg = "图表配置信息序列化失败:json.Marshal Err: " + e.Error()
+							return
+						}
+						sectionScatterConfigStr := string(sectionScatterConfigJson)
+						// 更新图表配置信息
+						chartInfo.ExtraConfig = sectionScatterConfigStr
+						updateStr = append(updateStr, "ExtraConfig")
+					}
+				}
+				if len(updateStr) > 0 {
+					updateStr = append(updateStr, "ModifyTime")
+					chartInfo.ModifyTime = time.Now()
+					err = chartInfo.Update(updateStr)
+					if err != nil {
+						errmsg = "更新图表信息失败:chartInfo.Update Err: " + err.Error()
+						return
+					}
+				}
+			}
+		}
+		// 查询所有的图表信息
 		if len(chartEdbMappingList) > 0 {
 			chartInfoIdList := make([]string, 0)
 			for _, mv := range chartEdbMappingList {
@@ -863,6 +994,8 @@ func ReplaceChartEdb(oldEdbInfo, newEdbInfo *EdbInfo) (relationEdbInfoIdList []i
 					errmsg = "获取图表所有指标信息失败:Err:" + err.Error()
 					return
 				}
+				// 查询图表信息
+
 				var minData, maxData float64
 				minData = newEdbInfo.MinValue
 				maxData = newEdbInfo.MaxValue
@@ -982,11 +1115,11 @@ type EdbInfoView struct {
 	IsUpdate         int     `description:"当天是否已更新,1:未更新,2:已更新"`
 	LatestDate       string  `description:"数据最新日期(实际日期)"`
 	LatestValue      float64 `description:"数据最新值(实际值)"`
+	EndValue         float64 `description:"数据的最新值(预测日期的最新值)"`
 	SubSource        int     `description:"子数据来源:0:经济数据库,1:日期序列"`
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
 	StockCode        string  `description:"证券代码"`
-	EndValue         float64 `description:"数据的最新值(预测日期的最新值)"`
 }
 
 // 获取指标的所有计算指标,以及计算指标所依赖计算指标
@@ -1545,6 +1678,25 @@ func GetEdbInfoByNameArr(names []string, edbInfoType int) (items []*EdbInfo, err
 	return
 }
 
+type EdbInfoEditRecord struct {
+	EdbInfoId           int    `description:"指标ID"`
+	EdbName             string `description:"指标名称"`
+	Frequency           string `description:"频率"`
+	Unit                string `description:"单位"`
+	ClassifyId          int    `description:"分类id"`
+	CalculateFormula    string `description:"计算公式"`
+	OperateUserId       int    `description:"操作人id"`
+	OperateUserRealName string `description:"操作人姓名"`
+}
+
+func ModifyEdbInfoBaseTimeById(edbInfoId int, cTime time.Time) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	// 更新修改时间
+	sql := ` UPDATE edb_info SET base_modify_time = ? WHERE edb_info_id = ? `
+	_, err = o.Raw(sql, cTime, edbInfoId).Exec()
+	return
+}
+
 // GetEdbCodesBySource 根据来源获取指标编码
 func GetEdbCodesBySource(source int) (items []*EdbInfo, err error) {
 	o := orm.NewOrmUsingDB("data")
@@ -1651,3 +1803,8 @@ func getAllDataByMongo(edbInfoId, source, subSource int, startDataTime string) (
 
 	return
 }
+
+type ReplaceEdbInfoItem struct {
+	OldEdbInfo *EdbInfo
+	NewEdbInfo *EdbInfo
+}

+ 2 - 0
models/data_manage/edb_info_calculate.go

@@ -254,6 +254,8 @@ type EdbInfoCalculateBatchEditReqByEdbLib struct {
 	Frequency     string `description:"频度"`
 	Unit          string `description:"单位"`
 	ClassifyId    int    `description:"分类id"`
+	AdminId       int    `description:"操作人id"`
+	AdminName     string `description:"操作人姓名"`
 	Formula       string `description:"N值"`
 	EdbInfoId     int    `description:"编辑指标id"`
 	FromEdbInfoId int    `description:"计算来源指标id"`

+ 28 - 0
models/data_manage/edb_info_record.go

@@ -0,0 +1,28 @@
+package data_manage
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type EdbInfoRecord struct {
+	EdbInfoRecordId     int       `orm:"column(edb_info_record_id);pk"`
+	EdbInfoId           int       `orm:"column(edb_info_id)"`
+	OldEdbName          string    `description:"旧的指标名称"`
+	OldFrequency        string    `description:"旧的频率"`
+	OldUnit             string    `description:"旧的单位"`
+	NewEdbName          string    `description:"新的指标名称"`
+	NewFrequency        string    `description:"新的频率"`
+	NewUnit             string    `description:"新的单位"`
+	OperateUserId       int       `description:"执行人id"`
+	OperateUserRealName string    `description:"执行人名称"`
+	CreateTime          time.Time `description:"记录的生成时间"`
+	Timestamp           int64     `description:"时间戳"`
+}
+
+func AddEditEdbInfoRcord(edbRecord *EdbInfoRecord) (e error) {
+	o := orm.NewOrmUsingDB("data")
+	_, e = o.Insert(edbRecord)
+	return
+}

+ 107 - 0
models/data_manage/edb_info_relation.go

@@ -0,0 +1,107 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type EdbInfoRelation struct {
+	EdbInfoRelationId  int       `orm:"column(edb_info_relation_id);pk"`
+	EdbInfoId          int       `description:"指标id"`
+	Source             int       `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,9:手工指标,10:隆众"`
+	EdbName            string    `description:"指标名称"`
+	EdbCode            string    `description:"指标编码"`
+	ReferObjectId      int       `description:"引用对象ID(图表ID,ETA逻辑ID等)"`
+	ReferObjectType    int       `description:"引用对象ID类型(1.图表,2.ETA逻辑)"`
+	ReferObjectSubType int       `description:"引用对象子类"`
+	CreateTime         time.Time `description:"创建时间"`
+	ModifyTime         time.Time `description:"修改时间"`
+}
+
+func (e *EdbInfoRelation) TableName() string {
+	return "edb_info_relation"
+}
+
+// GetEdbInfoRelationByEdbInfoIds 查询引用的指标ID
+func GetEdbInfoRelationByEdbInfoIds(edbInfoIds []int) (edbIds []int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	msql := ` SELECT edb_info_id FROM edb_info_relation WHERE edb_info_id in (` + utils.GetOrmInReplace(len(edbInfoIds)) + `)  GROUP BY edb_info_id `
+	_, err = o.Raw(msql, edbInfoIds).QueryRows(&edbIds)
+	return
+}
+
+// GetEdbInfoRelationByReferObjectId 查询引用的指标ID
+func GetEdbInfoRelationByReferObjectId(referObjectId int, referObjectType int) (items []*EdbInfoRelation, err error) {
+	o := orm.NewOrmUsingDB("data")
+	msql := ` SELECT * FROM edb_info_relation WHERE refer_object_id =? AND refer_object_type=?  GROUP BY edb_info_id `
+	_, err = o.Raw(msql, referObjectId, referObjectType).QueryRows(&items)
+	return
+}
+
+// GetEdbInfoRelationByReferObjectIds 查询引用的指标ID
+func GetEdbInfoRelationByReferObjectIds(referObjectIds []int, referObjectType int) (items []*EdbInfoRelation, err error) {
+	o := orm.NewOrmUsingDB("data")
+	msql := ` SELECT * FROM edb_info_relation WHERE refer_object_id in (` + utils.GetOrmInReplace(len(referObjectIds)) + `) AND refer_object_type=?`
+	_, err = o.Raw(msql, referObjectIds, referObjectType).QueryRows(&items)
+	return
+}
+
+// 新增记录
+func AddOrUpdateEdbInfoRelation(relationList []*EdbInfoRelation, deleteIds []int, refreshEdbInfoIds []int, indexCodeList []string) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	if len(deleteIds) > 0 {
+		sql := ` DELETE FROM edb_info_relation WHERE edb_info_relation_id in (` + utils.GetOrmInReplace(len(deleteIds)) + `) `
+		_, err = o.Raw(sql, deleteIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+	if len(relationList) > 0 {
+		_, err = o.InsertMulti(len(relationList), relationList)
+		if err != nil {
+			return
+		}
+	}
+
+	if len(refreshEdbInfoIds) > 0 {
+		//更新指标的刷新状态
+		sql := ` UPDATE edb_info SET no_update = 0 WHERE source in (?, ?) AND edb_info_id IN (` + utils.GetOrmInReplace(len(refreshEdbInfoIds)) + `) AND  no_update = 1`
+		_, err = o.Raw(sql, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, utils.DATA_SOURCE_WIND, refreshEdbInfoIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	//更新数据源钢联化工指标
+	if len(indexCodeList) > 0 {
+		// 更改数据源的更新状态
+		sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = 0 WHERE index_code IN (` + utils.GetOrmInReplace(len(indexCodeList)) + `) and is_stop=1`
+		_, err = o.Raw(sql, indexCodeList).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// todo 由此被禁用的计算指标是否能恢复刷新
+	return
+}
+
+// 删除指标引用内容
+func DeleteEdbRelationByObjectIds(referObjectIds []int, referObjectType int) (err error) {
+	o := orm.NewOrm()
+	sql := ` DELETE FROM edb_info_relation WHERE refer_object_id in (` + utils.GetOrmInReplace(len(referObjectIds)) + `) AND refer_object_type=?`
+	_, err = o.Raw(sql, referObjectIds, referObjectType).Exec()
+	return
+}

+ 7 - 0
models/data_manage/edb_refresh/request/edb_info_refresh.go

@@ -50,3 +50,10 @@ type SaveEdbRefreshStatusReq struct {
 	EdbSelectIdList []int  `description:"选择的指标id列表"`
 	ModifyStatus    string `description:"需要更改的状态,枚举值:启用、暂停"`
 }
+
+// SaveEdbRefreshStatusSingleReq
+// @Description: 设置单个指标的刷新状态
+type SaveEdbRefreshStatusSingleReq struct {
+	EdbInfoId    int
+	ModifyStatus string `description:"需要更改的状态,枚举值:启用、暂停"`
+}

+ 23 - 2
models/data_manage/excel/excel_edb_mapping.go

@@ -31,12 +31,19 @@ func (e *ExcelEdbMapping) Add() (err error) {
 	return
 }
 
+// Update 更新 excel表格基础信息
+func (e *ExcelEdbMapping) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
 // GetExcelEdbMappingByEdbInfoId 根据指标id获取配置关系
-func GetExcelEdbMappingByEdbInfoId(edbInfoId int) (item *ExcelEdbMapping, err error) {
+func GetExcelEdbMappingByEdbInfoId(edbInfoId int) (items []*ExcelEdbMapping, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT *  FROM excel_edb_mapping WHERE 1=1 AND edb_info_id = ? `
 
-	err = o.Raw(sql, edbInfoId).QueryRow(&item)
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
 	return
 }
 
@@ -89,6 +96,20 @@ func GetNoCustomAnalysisExcelEdbMappingCount(edbInfoId int) (count int, err erro
 	return
 }
 
+type ExcelEdbMappingWithParentIdItem struct {
+	ExcelInfoId int
+	ParentId    int
+}
+
+func GetNoCustomAnalysisExcelEdbMapping(edbInfoId int) (items []ExcelEdbMappingWithParentIdItem, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT b.excel_info_id, b.parent_id FROM excel_edb_mapping a 
+                          join excel_info b on a.excel_info_id=b.excel_info_id
+                          WHERE edb_info_id=? AND a.source != 4 AND b.is_delete = 0`
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
+	return
+}
+
 // GetAllExcelEdbMappingByExcelInfoId 根据excel的id获取所有的指标
 func GetAllExcelEdbMappingByExcelInfoId(excelInfoId int) (items []*ExcelEdbMapping, err error) {
 	o := orm.NewOrmUsingDB("data")

+ 74 - 5
models/data_manage/excel/excel_info.go

@@ -1,9 +1,11 @@
 package excel
 
 import (
+	"eta/eta_api/models/data_manage"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"strconv"
 	"time"
 )
 
@@ -412,7 +414,6 @@ FROM excel_info WHERE 1=1 AND is_delete=0 `
 	_, err = o.Raw(sql, pars).QueryRows(&item)
 	return
 }
-
 func GetExcelListCountByCondition(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT COUNT(1) AS count FROM excel_info WHERE 1=1 AND is_delete=0 `
@@ -615,10 +616,10 @@ func SaveExcelInfoAndSheet(excelInfo *ExcelInfo, updateExcelInfoParam []string,
 
 // BatchRefreshExcelReq 批量刷新表格请求
 type BatchRefreshExcelReq struct {
-	ExcelCodes      []string `description:"表格编码"`
-	ReportId        int      `description:"报告ID"`
-	ReportChapterId int      `description:"报告章节ID"`
-	Source          string   `description:"来源,枚举值:report、english_report、smart_report"`
+	ExcelCodes []string `description:"表格编码"`
+	PrimaryId  int      `description:"研报/智能研报/PPT主键"`
+	SubId      int      `description:"报告章节ID"`
+	Source     string   `description:"来源,枚举值:report、english_report、smart_report"`
 }
 
 // GetExcelMaxSortByClassifyId 获取当前分类下,且排序数最大的excel
@@ -713,6 +714,74 @@ func ModifyExcelInfoUserIdByOldUserId(oldUserIdList []int, userId int, userName
 	return
 }
 
+func GetExcelBaseInfoByExcelInfoIdList(excelInfoIdList []int) (items []*data_manage.ExcelBaseInfo, err error) {
+	num := len(excelInfoIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT excel_info_id,source,excel_type,excel_name,unique_code,excel_classify_id,sys_user_id,sys_user_real_name FROM excel_info WHERE excel_info_id in (` + utils.GetOrmInReplace(num) + `) order by excel_info_id DESC `
+	_, err = o.Raw(sql, excelInfoIdList).QueryRows(&items)
+
+	return
+}
+
+// ReplaceEdbInExcel 替换表格中的指标
+func ReplaceEdbInExcel(oldEdbInfoId, newEdbInfoId int, updateExcelList []*ExcelInfo) (err error) {
+	var errmsg string
+	logMsg := `` // 记录替换的日志
+	replaceTotal := 0
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+			if logMsg != `` {
+				utils.FileLog.Info(fmt.Sprintf("替换表格中的指标记录,替换总表格数:%d,旧的指标id:%d,新的指标id:%d;%s", replaceTotal, oldEdbInfoId, newEdbInfoId, logMsg))
+			}
+		}
+		if errmsg != "" {
+			fmt.Println("errmsg:" + errmsg)
+		}
+		if err != nil && errmsg != "" {
+			//go alarm_msg.SendAlarmMsg("替换替换配置中的指标记录失败提醒,errmsg:"+errmsg, 3)
+		}
+	}()
+	// 替换表格中的内容
+	for _, excelInfo := range updateExcelList {
+		//更新配置中的指标A
+		sql := `UPDATE excel_info SET content=?, modify_time=? WHERE excel_info_id=?`
+		_, err = to.Raw(sql, excelInfo.Content, time.Now(), excelInfo.ExcelInfoId).Exec()
+		if err != nil {
+			errmsg = "更新表格内容失败:Err:" + err.Error()
+			return
+		}
+		//更新配置中的指标B
+		// 判断是否已存在绑定,如果存在则删除
+		sql = `DELETE FROM excel_edb_mapping WHERE excel_info_id=? and edb_info_id=?`
+		_, err = to.Raw(sql, excelInfo.ExcelInfoId, newEdbInfoId).Exec()
+		if err != nil {
+			errmsg = "删除指标B关联图表配置信息失败:Err:" + err.Error()
+			return
+		}
+		// 插入新的绑定
+		sql = `UPDATE excel_edb_mapping SET edb_info_id=?, modify_time=? WHERE excel_info_id=? and edb_info_id=?`
+		_, err = to.Raw(sql, newEdbInfoId, time.Now(), excelInfo.ExcelInfoId, oldEdbInfoId).Exec()
+		if err != nil {
+			errmsg = "更新指标B关联图表配置信息失败:Err:" + err.Error()
+			return
+		}
+		logMsg += `涉及到的表格id:` + strconv.Itoa(excelInfo.ExcelInfoId) + ";"
+		replaceTotal += 1
+	}
+	return
+}
+
 // GetChildExcelInfoByParentId 根据id 获取eta表格详情
 func GetChildExcelInfoByParentId(parentId int) (items []*ExcelInfo, err error) {
 	o := orm.NewOrmUsingDB("data")

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

@@ -135,6 +135,16 @@ type CopyExcelInfoReq struct {
 	ExcelClassifyId int    `description:"分类id"`
 }
 
+// AddAndEditSandbox 添加/编辑沙盘的请求数据
+type AddAndEditSandbox struct {
+	ExcelInfoId       int    `description:"excel表格ID"`
+	Name              string `description:"沙盘名称"`
+	ChartPermissionId int    `description:"品种权限id"`
+	Content           string `description:"沙盘内容"`
+	PicUrl            string `description:"沙盘图片地址"`
+	SvgData           string `description:"沙盘svg图片数据"`
+}
+
 // MarkEditExcel 标记编辑表格的请求数据
 type MarkEditExcel struct {
 	ExcelInfoId int `description:"表格id"`

+ 40 - 0
models/data_manage/excel/request/time_table.go

@@ -0,0 +1,40 @@
+package request
+
+// TimeTableDataConfig
+// @Description: 表格配置
+type TimeTableDataConfig struct {
+	EdbInfoIdList    []int                 `description:"指标id列表,从左至右,从上到下的顺序"`
+	Sort             int                   `description:"日期排序,0:倒序,1:正序"`
+	Data             []TimeTableManualData `description:"数据列表"`
+	Num              int                   `description:"实际数据需要列出来的期数"`
+	RemoveDate       []string              `description:"不展示的日期"`
+	ManualDate       []string              `description:"手动配置的日期(未来的日期)"`
+	TableEdbInfoList []TimeTableEdbInfo    `description:"表格内指标信息"`
+	TextRowData      [][]ManualDataReq     `description:"文本列表"`
+}
+
+// TimeTableEdbInfo
+// @Description: 表格指标信息
+type TimeTableEdbInfo struct {
+	EdbInfoId    int    `description:"指标ID"`
+	Tag          string `description:"标签"`
+	EdbName      string `description:"指标名称"`
+	EdbNameEn    string `description:"英文指标名称"`
+	EdbAliasName string `description:"指标别名"`
+	Frequency    string `description:"频度"`
+	Unit         string `description:"单位"`
+	UnitEn       string `description:"英文单位"`
+}
+
+// ManualData
+// @Description: 手工文本配置
+type TimeTableManualData struct {
+	DataType            int               `description:"数据类型,1:普通的,2:插值法,3:手动输入,4:公式计算"`
+	DataTime            string            `description:"所属日期"`
+	DataTimeType        int               `description:"日期类型,1:实际日期;2:未来日期"`
+	ShowValue           string            `description:"展示值"`
+	Value               string            `description:"实际值(计算公式)"`
+	EdbInfoId           int               `description:"指标id"`
+	Tag                 string            `description:"下标"`
+	RelationEdbInfoList []RelationEdbInfo `description:"关联指标(计算公式中关联的指标,用于计算的时候去匹配)"`
+}

+ 126 - 0
models/data_manage/multiple_graph_config.go

@@ -1,7 +1,14 @@
 package data_manage
 
 import (
+	"encoding/json"
+	"eta/eta_api/models/data_manage/line_equation/request"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/utils"
+	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
 	"time"
 )
 
@@ -80,3 +87,122 @@ type RollingCorrelationConfig struct {
 	CalculateValue int    `description:"计算窗口"`
 	CalculateUnit  string `description:"计算频度"`
 }
+
+// ReplaceEdbInfoInLineEquationMultipleGraphConfig 获取拟合方程配置
+func ReplaceEdbInfoInLineEquationMultipleGraphConfig(oldEdbInfo, newEdbInfo *EdbInfo) (replaceConfigTotal int, err error) {
+	var errmsg string
+	logMsg := `` // 记录替换的日志
+
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+			if logMsg != `` {
+				utils.FileLog.Info(fmt.Sprintf("替换拟合方程中的指标记录 替换总数%d,旧的指标id:%d,新的指标id:%d;%s", replaceConfigTotal, oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, logMsg))
+			}
+		}
+		if errmsg != "" {
+			fmt.Println("errmsg:" + errmsg)
+		}
+		if err != nil && errmsg != "" {
+			go alarm_msg.SendAlarmMsg("替换拟合方程中的指标记录失败提醒,errmsg:"+errmsg, 3)
+		}
+	}()
+	//替换multiple_graph_config中的指标
+	{
+		multipleGraphConfigList := make([]*MultipleGraphConfig, 0)
+		csql := `SELECT * FROM multiple_graph_config WHERE edb_info_id_a=0 AND edb_info_id_b=0 AND curve !=""`
+		_, err = to.Raw(csql).QueryRows(&multipleGraphConfigList)
+		if err != nil {
+			errmsg = "获取指标关联图表配置信息失败:Err:" + err.Error()
+			return
+		}
+		if len(multipleGraphConfigList) == 0 {
+			return
+		}
+		updateList := make([]*MultipleGraphConfig, 0)
+		configIds := make([]int, 0)
+		configIdStr := make([]string, 0)
+		for _, mv := range multipleGraphConfigList {
+			if !strings.Contains(mv.Curve, strconv.Itoa(oldEdbInfo.EdbInfoId)) {
+				continue
+			}
+			//解析curve内容
+			var lineChartInfoConfig request.LineChartInfoReq
+			if err = json.Unmarshal([]byte(mv.Curve), &lineChartInfoConfig); err != nil {
+				errmsg = "获取跨品种分析配置信息失败:Err:" + err.Error()
+				return
+			}
+			updateFlag := false
+			// 遍历跨品种配置里的指标列表
+			for k, edbInfoId := range lineChartInfoConfig.XEdbInfoIdList {
+				if edbInfoId == oldEdbInfo.EdbInfoId {
+					updateFlag = true
+					lineChartInfoConfig.XEdbInfoIdList[k] = newEdbInfo.EdbInfoId
+				}
+			}
+			for k, edbInfoId := range lineChartInfoConfig.YEdbInfoIdList {
+				if edbInfoId == oldEdbInfo.EdbInfoId {
+					updateFlag = true
+					lineChartInfoConfig.YEdbInfoIdList[k] = newEdbInfo.EdbInfoId
+				}
+			}
+			if !updateFlag {
+				continue
+			}
+			newCurve, _ := json.Marshal(lineChartInfoConfig)
+			mv.Curve = string(newCurve)
+			//判断如果达到1000个数,则执行更新语句
+			updateList = append(updateList, mv)
+			configIds = append(configIds, mv.MultipleGraphConfigId)
+			configIdStr = append(configIdStr, strconv.Itoa(mv.MultipleGraphConfigId))
+			if len(configIds) >= 10 {
+				numStr := utils.GetOrmInReplace(len(configIds))
+				// 准备批量更新的 SQL 语句
+				updateSQL := `UPDATE multiple_graph_config SET   
+    curve = CASE multiple_graph_config_id  `
+				for _, updateItem := range updateList {
+					updateSQL += `WHEN ` + strconv.Itoa(updateItem.MultipleGraphConfigId) + ` THEN '` + updateItem.Curve + `' `
+				}
+				updateSQL += `END, modify_time = ? WHERE multiple_graph_config_id IN (` + numStr + `)`
+				_, err = to.Raw(updateSQL, time.Now(), configIds).Exec()
+				if err != nil {
+					errmsg = "更新指标A关联图表配置信息失败:Err:" + err.Error()
+					return
+				}
+				logMsg += `涉及到的配置id:` + strings.Join(configIdStr, ",") + ";"
+				replaceConfigTotal += len(configIds)
+				configIds = make([]int, 0)
+				updateList = make([]*MultipleGraphConfig, 0)
+				configIdStr = make([]string, 0)
+			}
+		}
+		if len(configIds) > 0 {
+			numStr := utils.GetOrmInReplace(len(configIds))
+			// 准备批量更新的 SQL 语句
+			updateSQL := `UPDATE multiple_graph_config SET   
+    curve = CASE multiple_graph_config_id  `
+			for _, updateItem := range updateList {
+				updateSQL += `WHEN ` + strconv.Itoa(updateItem.MultipleGraphConfigId) + ` THEN '` + updateItem.Curve + `' `
+			}
+			updateSQL += `END, modify_time = ? WHERE multiple_graph_config_id IN (` + numStr + `)`
+			_, err = to.Raw(updateSQL, time.Now(), configIds).Exec()
+			if err != nil {
+				errmsg = "更新指标A关联图表配置信息失败:Err:" + err.Error()
+				return
+			}
+			logMsg += `涉及到的配置id:` + strings.Join(configIdStr, ",") + ";"
+			replaceConfigTotal += len(configIds)
+			configIds = make([]int, 0)
+			updateList = make([]*MultipleGraphConfig, 0)
+			configIdStr = make([]string, 0)
+		}
+	}
+	return
+}

+ 136 - 0
models/data_manage/multiple_graph_config_chart_mapping.go

@@ -1,7 +1,12 @@
 package data_manage
 
 import (
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/utils"
+	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
 	"time"
 )
 
@@ -60,3 +65,134 @@ func GetMultipleGraphConfigChartMappingListById(configId int) (items []*Multiple
 
 	return
 }
+
+// ReplaceMultipleGraphConfigChartEdb 替换相关性分析配置中的指标
+func ReplaceMultipleGraphConfigChartEdb(oldEdbInfo, newEdbInfo *EdbInfo) (replaceConfigTotal int, err error) {
+	var errmsg string
+	logMsg := `` // 记录替换的日志
+
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+			if logMsg != `` {
+				utils.FileLog.Info(fmt.Sprintf("替换相关性分析中的指标记录 替换总数%d,旧的指标id:%d,新的指标id:%d;%s", replaceConfigTotal, oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, logMsg))
+			}
+		}
+		if errmsg != "" {
+			fmt.Println("errmsg:" + errmsg)
+		}
+		if err != nil && errmsg != "" {
+			go alarm_msg.SendAlarmMsg("替换统计分析配置中的指标记录失败提醒,errmsg:"+errmsg, 3)
+		}
+	}()
+	//替换multiple_graph_config中的指标
+	multipleGraphConfigList := make([]*MultipleGraphConfig, 0)
+	csql := `SELECT * FROM multiple_graph_config WHERE (edb_info_id_a=? or edb_info_id_b=?)`
+	_, err = to.Raw(csql, oldEdbInfo.EdbInfoId, oldEdbInfo.EdbInfoId).QueryRows(&multipleGraphConfigList)
+	if err != nil {
+		errmsg = "获取指标关联图表配置信息失败:Err:" + err.Error()
+		return
+	}
+	if len(multipleGraphConfigList) > 0 {
+		replaceConfigTotal = len(multipleGraphConfigList)
+		configIdMap := make(map[int]int)
+		configIds := make([]int, 0)
+		configIdStr := make([]string, 0)
+		for _, mv := range multipleGraphConfigList {
+			if _, ok := configIdMap[mv.MultipleGraphConfigId]; !ok {
+				//判断如果达到1000个数,则执行更新语句
+				configIds = append(configIds, mv.MultipleGraphConfigId)
+				configIdStr = append(configIdStr, strconv.Itoa(mv.MultipleGraphConfigId))
+				configIdMap[mv.MultipleGraphConfigId] = mv.MultipleGraphConfigId
+				if len(configIds) >= 1000 {
+					numStr := utils.GetOrmInReplace(len(configIds))
+					//更新配置中的指标A
+					sql := `UPDATE multiple_graph_config SET edb_info_id_a=?, modify_time=? WHERE edb_info_id_a=? and multiple_graph_config_id IN (` + numStr + `)`
+					_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+					if err != nil {
+						errmsg = "更新指标A关联图表配置信息失败:Err:" + err.Error()
+						return
+					}
+					//更新配置中的指标B
+					sql = `UPDATE multiple_graph_config SET edb_info_id_b=?, modify_time=? WHERE edb_info_id_b=? and multiple_graph_config_id IN (` + numStr + `)`
+					_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+					if err != nil {
+						errmsg = "更新指标B关联图表配置信息失败:Err:" + err.Error()
+						return
+					}
+
+					// 更新
+					// 更新指标id
+					sql = `UPDATE multiple_graph_config_edb_mapping SET edb_info_id=?, modify_time=? WHERE edb_info_id=? and multiple_graph_config_id IN (` + numStr + `)`
+					_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+					if err != nil {
+						errmsg = "更新指标id关联图表配置信息失败:Err:" + err.Error()
+						return
+					}
+					logMsg += `涉及到的配置id:` + strings.Join(configIdStr, ",") + ";"
+					configIds = make([]int, 0)
+					configIdStr = make([]string, 0)
+				}
+			}
+		}
+		if len(configIds) > 0 {
+			numStr := utils.GetOrmInReplace(len(configIds))
+			//更新配置中的指标A
+			sql := `UPDATE multiple_graph_config SET edb_info_id_a=?, modify_time=? WHERE edb_info_id_a=? and multiple_graph_config_id IN (` + numStr + `)`
+			_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+			if err != nil {
+				errmsg = "更新指标A关联图表配置信息失败:Err:" + err.Error()
+				return
+			}
+			//更新配置中的指标B
+			sql = `UPDATE multiple_graph_config SET edb_info_id_b=?, modify_time=? WHERE edb_info_id_b=? and multiple_graph_config_id IN (` + numStr + `)`
+			_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+			if err != nil {
+				errmsg = "更新指标B关联图表配置信息失败:Err:" + err.Error()
+				return
+			}
+			// 更新指标id
+			sql = `UPDATE multiple_graph_config_edb_mapping SET edb_info_id=?, modify_time=? WHERE edb_info_id=? and multiple_graph_config_id IN (` + numStr + `)`
+			_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId, configIds).Exec()
+			if err != nil {
+				errmsg = "更新指标id关联图表配置信息失败:Err:" + err.Error()
+				return
+			}
+
+			logMsg += `涉及到的配置id:` + strings.Join(configIdStr, ",") + ";"
+			configIds = make([]int, 0)
+			configIdStr = make([]string, 0)
+		}
+	}
+
+	// 更新相关性图表中的
+	sql := `UPDATE chart_info_correlation SET edb_info_id_first=?, modify_time=? WHERE edb_info_id_first=?`
+	_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId).Exec()
+	if err != nil {
+		errmsg = "更新相关性图表中的指标id关联失败:Err:" + err.Error()
+		return
+	}
+	sql = `UPDATE chart_info_correlation SET edb_info_id_second=?, modify_time=? WHERE edb_info_id_second=?`
+	_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId).Exec()
+	if err != nil {
+		errmsg = "更新相关性图表中的指标id关联失败:Err:" + err.Error()
+		return
+	}
+
+	// 替换拟合方程曲线替换指标
+	// 替换跨品种标签绑定得到指标ID
+	sql = `UPDATE chart_tag_variety SET edb_info_id=?, modify_time=? WHERE edb_info_id=?`
+	_, err = to.Raw(sql, newEdbInfo.EdbInfoId, time.Now(), oldEdbInfo.EdbInfoId).Exec()
+	if err != nil {
+		errmsg = "更新指标id关联跨品种分析标签失败:Err:" + err.Error()
+		return
+	}
+	return
+}

+ 10 - 10
models/data_manage/my_chart.go

@@ -870,7 +870,7 @@ func GetMyChartListGroupByCharyInfoIdAndAdminIdByCondition(condition string, par
 func GetRelationChartListByCondition(condition string, pars []interface{}, startSize, pageSize int) (item []*ChartInfoView, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT a.* FROM chart_info AS a 
-	JOIN chart_edb_mapping AS b on a.chart_info_id = b.chart_info_id WHERE 1=1 `
+	WHERE 1=1 `
 	if condition != "" {
 		sql += condition
 	}
@@ -883,7 +883,7 @@ func GetRelationChartListByCondition(condition string, pars []interface{}, start
 func GetRelationChartListCountByCondition(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT COUNT(1) AS count FROM chart_info AS a 
-	JOIN chart_edb_mapping AS b on a.chart_info_id = b.chart_info_id WHERE 1=1 `
+	WHERE 1=1 `
 	if condition != "" {
 		sql += condition
 	}
@@ -914,14 +914,6 @@ func GetChartInfoViewByIdList(chartInfoIdList []int) (items []*ChartInfoView, er
 	return
 }
 
-// GetMyChartClassifyByClassifyId 主键获取分类
-func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err error) {
-	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM my_chart_classify WHERE my_chart_classify_id = ? `
-	err = o.Raw(sql, classifyId).QueryRow(&item)
-	return
-}
-
 // MyChartClassifyItem 我的图表分类信息
 type MyChartClassifyItem struct {
 	MyChartClassifyId   int    `description:"分类ID"`
@@ -971,3 +963,11 @@ func GetMyChartClassifyIdAndNum(cond string, pars []interface{}) (items []*MyCha
 	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
+
+// GetMyChartClassifyByClassifyId 主键获取分类
+func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM my_chart_classify WHERE my_chart_classify_id = ? `
+	err = o.Raw(sql, classifyId).QueryRow(&item)
+	return
+}

+ 46 - 0
models/data_manage/mysteel_chemical_index.go

@@ -524,3 +524,49 @@ func ModifyMysteelChemicalUpdateStatus(edbIdList []int, indexCodeList []string,
 
 	return
 }
+
+// ModifyMysteelChemicalUpdateStatusByEdbInfoId
+// @Description:  修改单个钢联化工指标停更状态,同时停更依赖于该指标的计算指标
+// @author: Roc
+// @datetime 2024-01-08 16:23:31
+// @param edbIdList []int
+// @param indexCodeList []string
+// @param isStop int
+// @return err error
+func ModifyMysteelChemicalUpdateStatusByEdbInfoId(edbInfoId, isStop int, edbCode string, calculateEdbInfoIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+			return
+		}
+		_ = o.Commit()
+	}()
+
+	// 更改数据源的更新状态
+	sql := ` UPDATE base_from_mysteel_chemical_index SET is_stop = ? WHERE index_code = ? `
+	_, err = o.Raw(sql, isStop, edbCode).Exec()
+	if err != nil {
+		return
+	}
+
+	// 更改指标的更新状态
+	sql = ` UPDATE edb_info SET no_update = ? WHERE source = ? AND sub_source= ? AND edb_info_id=? `
+	_, err = o.Raw(sql, isStop, utils.DATA_SOURCE_MYSTEEL_CHEMICAL, 0, edbInfoId).Exec()
+	if err != nil {
+		return
+	}
+	if len(calculateEdbInfoIds) > 0 {
+		// 批量更新相关联的指标ID
+		sql = ` UPDATE edb_info SET no_update = ? WHERE edb_info_id IN (` + utils.GetOrmInReplace(len(calculateEdbInfoIds)) + `) `
+		_, err = o.Raw(sql, isStop, calculateEdbInfoIds).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}

+ 19 - 11
models/db.go

@@ -15,6 +15,7 @@ import (
 	"eta/eta_api/models/eta_trial"
 	"eta/eta_api/models/fe_calendar"
 	"eta/eta_api/models/ppt_english"
+	"eta/eta_api/models/report"
 	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/semantic_analysis"
@@ -23,9 +24,10 @@ import (
 	"eta/eta_api/models/system"
 	"eta/eta_api/models/yb"
 	"eta/eta_api/utils"
-	_ "github.com/go-sql-driver/mysql"
 	"time"
 
+	_ "github.com/go-sql-driver/mysql"
+
 	"github.com/beego/beego/v2/client/orm"
 )
 
@@ -177,15 +179,15 @@ func init() {
 	// 初始化跨品种分析表
 	initCrossVariety()
 
+	// 初始化图表主题
+	initChartTheme()
+
 	//初始化AI
 	initAi()
 
 	// 报告审批
 	initReportApprove()
 
-	// 初始化图表主题
-	initChartTheme()
-
 	// 初始化指标刷新
 	initEdbRefresh()
 
@@ -250,12 +252,15 @@ func initReport() {
 		new(ChartPermission),                     // 权限表
 		new(YbPcSuncode),
 		new(YbSuncodePars),
-		new(ReportAuthor),                  //报告作者
-		new(ClassifyMenu),                  // 报告分类-子目录表
-		new(ClassifyMenuRelation),          // 报告分类-子目录关联表
-		new(ChartPermissionChapterMapping), // 权限mapping表
-		new(ReportChapterType),             // 报告章节类型表
-		new(ReportStateRecord),             // 研报状态修改记录表
+		new(ReportAuthor),                          //报告作者
+		new(ClassifyMenu),                          // 报告分类-子目录表
+		new(ClassifyMenuRelation),                  // 报告分类-子目录关联表
+		new(ChartPermissionChapterMapping),         // 权限mapping表
+		new(ReportChapterType),                     // 报告章节类型表
+		new(ReportStateRecord),                     // 研报状态修改记录表
+		new(report.ReportGrant),                    // 报告授权用户表
+		new(report.ReportChapterGrant),             // 报告章节授权用户表
+		new(report.ReportChapterPermissionMapping), // 报告章节的权限关系表
 	)
 }
 
@@ -311,6 +316,7 @@ func initEdbData() {
 		new(data_manage.BaseFromSmmData),
 		new(data_manage.BaseFromSmmClassify),
 		new(data_manage.EdbInfoLog),
+		new(data_manage.EdbInfoRecord),
 		new(data_manage.EdbInfoCalculateMapping),
 		new(data_manage.PredictEdbConf),                  //预测指标配置
 		new(data_manage.BaseFromMysteelChemicalClassify), //预测指标配置
@@ -336,6 +342,7 @@ func initEdbData() {
 		new(data_manage.EdbDataInsertConfig),      // 指标数据插入配置表
 		new(data_manage.EdbInfoNoPermissionAdmin), //指标不可见用户配置表
 		new(data_manage.EdbTerminal),              //指标终端
+		new(data_manage.EdbInfoRelation),          //指标关系表
 	)
 }
 
@@ -454,7 +461,8 @@ func initBusinessConf() {
 
 func initOutLink() {
 	orm.RegisterModel(
-		new(OutLink)) // 外部链接表
+		new(OutLink), // 外部链接表
+	)
 }
 
 // initEtaTrial 试用平台相关表

+ 2 - 0
models/english_report.go

@@ -94,6 +94,8 @@ 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:"作者"`

+ 3 - 3
models/ppt_v2.go

@@ -222,9 +222,9 @@ type PptV2ConfigResp struct {
 }
 
 type PPT2ReportReq struct {
-	PptId            int    `description:"PPT主键"`
-	ClassifyIdSecond int    `description:"报告二级分类ID"`
-	Title            string `description:"标题"`
+	PptId      int    `description:"PPT主键"`
+	ClassifyId int    `description:"报告二级分类ID"`
+	Title      string `description:"标题"`
 }
 
 // AddPptV2Multi 批量新增ppt

+ 306 - 76
models/report.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"errors"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
@@ -63,6 +64,28 @@ type Report struct {
 	AdminRealName      string    `description:"创建者姓名"`
 	ApproveTime        time.Time `description:"审批时间"`
 	ApproveId          int       `description:"审批ID"`
+	DetailImgUrl       string    `description:"报告详情长图地址"`
+	DetailPdfUrl       string    `description:"报告详情PDF地址"`
+
+	ContentStruct       string    `description:"内容组件"`
+	LastModifyAdminId   int       `description:"最后更新人ID"`
+	LastModifyAdminName string    `description:"最后更新人姓名"`
+	ContentModifyTime   time.Time `description:"内容更新时间"`
+	Pv                  int       `description:"pv"`
+	Uv                  int       `description:"uv"`
+	HeadImg             string    `description:"报告头图地址"`
+	EndImg              string    `description:"报告尾图地址"`
+	CanvasColor         string    `description:"画布颜色"`
+	NeedSplice          int       `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId      int       `description:"版头资源ID"`
+	EndResourceId       int       `description:"版尾资源ID"`
+	ClassifyIdThird     int       `description:"三级分类id"`
+	ClassifyNameThird   string    `description:"三级分类名称"`
+	CollaborateType     int8      `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	IsPublicPublish     int8      `description:"是否公开发布,1:是,2:否"`
+	ReportCreateTime    time.Time `description:"报告时间创建时间"`
+	InheritReportId     int       `description:"待继承的报告ID"`
 }
 
 type ReportList struct {
@@ -106,6 +129,24 @@ type ReportList struct {
 	ApproveTime        string                    `description:"审批时间"`
 	DetailImgUrl       string                    `description:"报告详情长图地址"`
 	DetailPdfUrl       string                    `description:"报告详情PDF地址"`
+
+	CollaborateType     int8      `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	IsPublicPublish     int8      `description:"是否公开发布,1:是,2:否"`
+	ReportCreateTime    time.Time `description:"报告时间创建时间"`
+	ContentStruct       string    `description:"内容组件"`
+	LastModifyAdminId   int       `description:"最后更新人ID"`
+	LastModifyAdminName string    `description:"最后更新人姓名"`
+	ContentModifyTime   time.Time `description:"内容更新时间"`
+	HeadImg             string    `description:"报告头图地址"`
+	EndImg              string    `description:"报告尾图地址"`
+	CanvasColor         string    `description:"画布颜色"`
+	NeedSplice          int       `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId      int       `description:"版头资源ID"`
+	EndResourceId       int       `description:"版尾资源ID"`
+	ClassifyIdThird     int       `description:"三级分类id"`
+	ClassifyNameThird   string    `description:"三级分类名称"`
+	InheritReportId     int       `description:"待继承的报告ID"`
 }
 
 type ReportListResp struct {
@@ -113,17 +154,114 @@ type ReportListResp struct {
 	Paging *paging.PagingItem `description:"分页数据"`
 }
 
-func GetReportListCount(condition string, pars []interface{}, companyType string) (count int, err error) {
-	//产品权限
-	companyTypeSqlStr := ``
-	if companyType == "ficc" {
-		companyTypeSqlStr = " AND classify_id_first != 40 "
-	} else if companyType == "权益" {
-		companyTypeSqlStr = " AND classify_id_first = 40 "
+// GetReportListCountV1
+// @Description: 获取普通报告列表的报告数量
+// @author: Roc
+// @datetime 2024-05-30 15:14:43
+// @param condition string
+// @param pars []interface{}
+// @return count int
+// @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 `
+	if condition != "" {
+		sql += condition
+	}
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetReportListV1
+// @Description: 获取普通报告列表的数据
+// @author: Roc
+// @datetime 2024-05-30 15:14:25
+// @param condition string
+// @param pars []interface{}
+// @param startSize int
+// @param pageSize int
+// @return items []*ReportList
+// @return err error
+func GetReportListV1(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+
+	sql := `SELECT * FROM report as a WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	// 排序:1:未发布;2:已发布;3-待提交;4-待审批;5-已驳回;6-已通过
+	sql += `ORDER BY FIELD(state,3,1,4,5,6,2), modify_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+type ReportPvUv struct {
+	ReportId int
+	PvTotal  int
+	UvTotal  int
+}
+
+func GetReportPvUvByReportIdList(reportIdList []string) (items []ReportPvUv, err error) {
+	num := len(reportIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+
+	sql := `SELECT report_id, COUNT(1) as pv_total,COUNT(DISTINCT user_id) as uv_total  FROM report_view_record  WHERE report_id in (` + utils.GetOrmInReplace(num) + `) GROUP BY report_id`
+	_, err = o.Raw(sql, reportIdList).QueryRows(&items)
+	return
+}
+
+// GetReportListCountByGrant
+// @Description: 获取共享报告列表的报告数量
+// @author: Roc
+// @datetime 2024-05-30 15:14:01
+// @param condition string
+// @param pars []interface{}
+// @return count int
+// @return err error
+func GetReportListCountByGrant(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT a.id  FROM report as a 
+    JOIN report_grant b on a.id=b.report_id 
+ WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	sql += " GROUP BY a.id "
+
+	sql = `SELECT COUNT(1) AS count  FROM (` + sql + `) d`
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetReportListByGrant
+// @Description: 获取共享报告列表的数据
+// @author: Roc
+// @datetime 2024-05-30 15:15:07
+// @param condition string
+// @param pars []interface{}
+// @param startSize int
+// @param pageSize int
+// @return items []*ReportList
+// @return err error
+func GetReportListByGrant(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+
+	sql := `SELECT * FROM report as a JOIN report_grant b on a.id = b.report_id  WHERE 1=1  `
+	if condition != "" {
+		sql += condition
 	}
+	// 排序:1:未发布;2:已发布;3-待提交;4-待审批;5-已驳回;6-已通过
+	sql += ` GROUP BY a.id ORDER BY FIELD(state,3,1,4,5,6,2), modify_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
 
+func GetReportListCount(condition string, pars []interface{}) (count int, err error) {
 	oRddp := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT COUNT(1) AS count  FROM report WHERE 1=1 ` + companyTypeSqlStr
+	sql := `SELECT COUNT(1) AS count  FROM report WHERE 1=1 `
 	if condition != "" {
 		sql += condition
 	}
@@ -131,20 +269,13 @@ func GetReportListCount(condition string, pars []interface{}, companyType string
 	return
 }
 
-func GetReportList(condition string, pars []interface{}, companyType string, startSize, pageSize int) (items []*ReportList, err error) {
+func GetReportList(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	//产品权限
-	companyTypeSqlStr := ``
-	if companyType == "ficc" {
-		companyTypeSqlStr = " AND classify_id_first != 40 "
-	} else if companyType == "权益" {
-		companyTypeSqlStr = " AND classify_id_first = 40 "
-	}
 
 	sql := `SELECT *,
         (SELECT COUNT(1) FROM report_view_record AS rvr WHERE rvr.report_id=report.id) AS pv,
         (SELECT COUNT(DISTINCT user_id) FROM report_view_record AS rvr WHERE rvr.report_id=report.id) AS uv
-        FROM report WHERE 1=1  ` + companyTypeSqlStr
+        FROM report WHERE 1=1  `
 	if condition != "" {
 		sql += condition
 	}
@@ -213,6 +344,26 @@ type ReportDetail struct {
 	ThsMsgIsSend       int    `description:"客户群消息是否已发送,0:否,1:是"`
 	HasChapter         int    `description:"是否有章节 0-否 1-是"`
 	ChapterType        string `description:"章节类型 day-晨报 week-周报"`
+
+	// eta1.8.3(研报改版)相关内容
+	ContentStruct       string    `description:"内容组件"`
+	LastModifyAdminId   int       `description:"最后更新人ID"`
+	LastModifyAdminName string    `description:"最后更新人姓名"`
+	ContentModifyTime   time.Time `description:"内容更新时间"`
+	Pv                  int       `description:"pv"`
+	Uv                  int       `description:"uv"`
+	HeadImg             string    `description:"报告头图地址"`
+	EndImg              string    `description:"报告尾图地址"`
+	CanvasColor         string    `description:"画布颜色"`
+	NeedSplice          int       `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId      int       `description:"版头资源ID"`
+	EndResourceId       int       `description:"版尾资源ID"`
+	ClassifyIdThird     int       `description:"三级分类id"`
+	ClassifyNameThird   string    `description:"三级分类名称"`
+	CollaborateType     int8      `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	IsPublicPublish     int8      `description:"是否公开发布,1:是,2:否"`
+	ReportCreateTime    time.Time `description:"报告时间创建时间"`
 }
 
 func GetReportById(reportId int) (item *ReportDetail, err error) {
@@ -230,39 +381,89 @@ func GetReportByIds(reportIds string) (list []*ReportDetail, err error) {
 }
 
 // GetSimpleReportByIds 根据报告ID查询报告基本信息
-func GetSimpleReportByIds(reportIds []int) (list []*ReportDetail, err error) {
+func GetSimpleReportByIds(reportIds []int) (list []*Report, err error) {
 	if len(reportIds) == 0 {
 		return
 	}
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `SELECT id, title FROM report WHERE id IN (` + utils.GetOrmInReplace(len(reportIds)) + `)`
+	sql := `SELECT id, title, report_code FROM report WHERE id IN (` + utils.GetOrmInReplace(len(reportIds)) + `)`
 	_, err = o.Raw(sql, reportIds).QueryRows(&list)
 	return
 }
 
-func GetReportStage(classifyIdFirst, classifyIdSecond int) (count int, err error) {
+// GetReportStage
+// @Description: 获取报告的最大期数(每一年的最大期数)
+// @author: Roc
+// @datetime 2024-06-03 17:44:14
+// @param classifyIdFirst int
+// @param classifyIdSecond int
+// @param classifyIdThird int
+// @return count int
+// @return err error
+func GetReportStage(classifyIdFirst, classifyIdSecond, classifyIdThird int) (count int, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ``
-	if classifyIdSecond > 0 {
-		sql = "SELECT MAX(stage) AS max_stage FROM report WHERE classify_id_second=? "
-		o.Raw(sql, classifyIdSecond).QueryRow(&count)
+	classifyId := classifyIdThird
+	if classifyId <= 0 {
+		classifyId = classifyIdSecond
+	}
+	if classifyId <= 0 {
+		classifyId = classifyIdFirst
+	}
+	if classifyId <= 0 {
+		err = errors.New("错误的分类id")
+		return
+	}
+	yearStart := time.Date(time.Now().Local().Year(), 1, 1, 0, 0, 0, 0, time.Local)
+
+	sql := `SELECT MAX(stage) AS max_stage FROM report WHERE create_time > ? `
+	if classifyIdThird > 0 {
+		sql += " AND classify_id_third = ? "
+	} else if classifyIdSecond > 0 {
+		sql += " AND classify_id_second = ? "
 	} else {
-		sql = "SELECT MAX(stage) AS max_stage FROM report WHERE classify_id_first=? "
-		o.Raw(sql, classifyIdFirst).QueryRow(&count)
+		sql = " AND classify_id_first = ? "
 	}
+	o.Raw(sql, yearStart, classifyId).QueryRow(&count)
+
 	return
 }
 
-func GetReportStageEdit(classifyIdFirst, classifyIdSecond, reportId int) (count int, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	sql := ``
-	if classifyIdSecond > 0 {
-		sql = "SELECT MAX(stage) AS max_stage FROM report WHERE classify_id_second=? AND id<>? "
-		o.Raw(sql, classifyIdSecond, reportId).QueryRow(&count)
+// GetReportStageEdit
+// @Description: 获取报告的最大期数(每一年的最大期数)
+// @author: Roc
+// @datetime 2024-06-04 13:50:34
+// @param classifyIdFirst int
+// @param classifyIdSecond int
+// @param classifyIdThird int
+// @param reportId int
+// @return count int
+// @return err error
+func GetReportStageEdit(classifyIdFirst, classifyIdSecond, classifyIdThird, reportId int) (count int, err error) {
+	classifyId := classifyIdThird
+	if classifyId <= 0 {
+		classifyId = classifyIdSecond
+	}
+	if classifyId <= 0 {
+		classifyId = classifyIdFirst
+	}
+	if classifyId <= 0 {
+		err = errors.New("错误的分类id")
+		return
+	}
+	yearStart := time.Date(time.Now().Local().Year(), 1, 1, 0, 0, 0, 0, time.Local)
+
+	sql := `SELECT MAX(stage) AS max_stage FROM report WHERE create_time > ? AND id<>?  `
+	if classifyIdThird > 0 {
+		sql += " AND classify_id_third = ? "
+	} else if classifyIdSecond > 0 {
+		sql += " AND classify_id_second = ? "
 	} else {
-		sql = "SELECT MAX(stage) AS max_stage FROM report WHERE classify_id_first=? AND id<>? "
-		o.Raw(sql, classifyIdFirst, reportId).QueryRow(&count)
+		sql = " AND classify_id_first = ? "
 	}
+
+	o := orm.NewOrmUsingDB("rddp")
+	o.Raw(sql, yearStart, reportId, classifyId).QueryRow(&count)
+
 	return
 }
 
@@ -285,6 +486,8 @@ type AddReq 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:"作者"`
@@ -293,6 +496,18 @@ type AddReq struct {
 	Content            string `description:"内容"`
 	CreateTime         string `description:"创建时间"`
 	ReportVersion      int    `description:"1:旧版,2:新版"`
+	ContentStruct      string `description:"内容组件"`
+	HeadImg            string `description:"报告头图地址"`
+	EndImg             string `description:"报告尾图地址"`
+	CanvasColor        string `description:"画布颜色"`
+	NeedSplice         int    `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId     int    `description:"版头资源ID"`
+	EndResourceId      int    `description:"版尾资源ID"`
+	CollaborateType    int8   `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	ReportLayout       int8   `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	IsPublicPublish    int8   `description:"是否公开发布,1:是,2:否"`
+	InheritReportId    int    `description:"待继承的报告ID"`
+	GrantAdminIdList   []int  `description:"授权用户id列表"`
 }
 
 type PrePublishReq struct {
@@ -319,6 +534,8 @@ type EditReq 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:"作者"`
@@ -326,6 +543,17 @@ type EditReq struct {
 	State              int    `description:"状态:1:未发布,2:已发布"`
 	Content            string `description:"内容"`
 	CreateTime         string `description:"创建时间"`
+	ContentStruct      string `description:"内容组件"`
+	HeadImg            string `description:"报告头图地址"`
+	EndImg             string `description:"报告尾图地址"`
+	CanvasColor        string `description:"画布颜色"`
+	NeedSplice         int    `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId     int    `description:"版头资源ID"`
+	EndResourceId      int    `description:"版尾资源ID"`
+	//CollaborateType    int8   `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	//ReportLayout       int8   `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	IsPublicPublish  int8  `description:"是否公开发布,1:是,2:否"`
+	GrantAdminIdList []int `description:"授权用户id列表"`
 }
 
 type EditResp struct {
@@ -357,6 +585,12 @@ func EditReport(item *Report, reportId int64) (err error) {
 	return
 }
 
+func (m *Report) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(m, cols...)
+	return
+}
+
 type ReportDetailReq struct {
 	ReportId int `description:"报告id"`
 }
@@ -438,6 +672,15 @@ type SaveReportContent struct {
 	Content  string `description:"内容"`
 	ReportId int    `description:"报告id"`
 	NoChange int    `description:"内容是否未改变:1:内容未改变"`
+
+	// 以下是智能研报相关
+	ContentStruct  string `description:"内容组件"`
+	HeadImg        string `description:"报告头图地址"`
+	EndImg         string `description:"报告尾图地址"`
+	CanvasColor    string `description:"画布颜色"`
+	NeedSplice     int    `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId int    `description:"版头资源ID"`
+	EndResourceId  int    `description:"版尾资源ID"`
 }
 
 func EditReportContent(reportId int, content, contentSub string) (err error) {
@@ -447,16 +690,16 @@ func EditReportContent(reportId int, content, contentSub string) (err error) {
 	return
 }
 
-func AddReportSaveLog(reportId, adminId int, content, contentSub, adminName string) (err error) {
+func AddReportSaveLog(reportId, adminId int, content, contentSub, contentStruct, canvasColor, adminName string, headResourceId, endResourceId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ` INSERT INTO report_save_log(report_id, content,content_sub,admin_id,admin_name) VALUES (?,?,?,?,?) `
-	_, err = o.Raw(sql, reportId, content, contentSub, adminId, adminName).Exec()
+	sql := ` INSERT INTO report_save_log(report_id, content,content_sub,content_struct,canvas_color,head_resource_id,end_resource_id,admin_id,admin_name) VALUES (?,?,?,?,?) `
+	_, err = o.Raw(sql, reportId, content, contentSub, contentStruct, canvasColor, headResourceId, endResourceId, adminId, adminName).Exec()
 	return
 }
 
 func MultiAddReportChaptersSaveLog(items []*ReportChapter, adminId int, adminRealName string) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	p, err := o.Raw(`INSERT INTO report_save_log(report_id, report_chapter_id, content, content_sub, admin_id, admin_name) VALUES (?,?,?,?,?,?)`).Prepare()
+	p, err := o.Raw(`INSERT INTO report_save_log(report_id, report_chapter_id, content, content_sub,content_struct,canvas_color,head_resource_id,end_resource_id, admin_id, admin_name) VALUES (?,?,?,?,?,?,?,?,?,?)`).Prepare()
 	if err != nil {
 		return
 	}
@@ -464,7 +707,7 @@ func MultiAddReportChaptersSaveLog(items []*ReportChapter, adminId int, adminRea
 		_ = p.Close()
 	}()
 	for _, v := range items {
-		_, err = p.Exec(v.ReportId, v.ReportChapterId, v.Content, v.ContentSub, adminId, adminRealName)
+		_, err = p.Exec(v.ReportId, v.ReportChapterId, v.Content, v.ContentSub, v.ContentStruct, v.CanvasColor, v.HeadResourceId, v.EndResourceId, adminId, adminRealName)
 		if err != nil {
 			return
 		}
@@ -518,38 +761,6 @@ func GetDayWeekReportStage(classifyIdFirst int, yearStart time.Time) (count int,
 	return
 }
 
-// AddReportAndChapter 新增报告及章节
-func AddReportAndChapter(reportItem *Report, chapterItemList []*ReportChapter) (reportId int64, err error) {
-	o := orm.NewOrmUsingDB("rddp")
-	to, err := o.Begin()
-	if err != nil {
-		return
-	}
-	defer func() {
-		if err != nil {
-			_ = to.Rollback()
-		} else {
-			_ = to.Commit()
-		}
-	}()
-
-	if reportId, err = to.Insert(reportItem); err != nil {
-		return
-	}
-	if len(chapterItemList) > 0 {
-		for _, chapterItem := range chapterItemList {
-			chapterItem.ReportId = int(reportId)
-			cpId, tmpErr := to.Insert(chapterItem)
-			if tmpErr != nil {
-				return
-			}
-			chapterItem.ReportChapterId = int(cpId)
-		}
-	}
-
-	return
-}
-
 // GetReportByReportId 主键获取报告
 func GetReportByReportId(reportId int) (item *Report, err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -601,10 +812,27 @@ func (reportInfo *Report) UpdateReport(cols []string) (err error) {
 	return
 }
 
-// 晨周报详情
+// ReportDetailView
+// @Description: 晨周报详情
 type ReportDetailView struct {
 	*ReportDetail
-	ChapterList []*ReportChapter
+	ChapterList    []*ReportChapter
+	GrandAdminList []ReportDetailViewAdmin
+	PermissionList []ReportDetailViewPermission
+}
+
+// ReportDetailViewAdmin
+// @Description: 报告里面的授权人
+type ReportDetailViewAdmin struct {
+	AdminId   int
+	AdminName string
+}
+
+// ReportDetailViewPermission
+// @Description: 报告分类关联的品种权限
+type ReportDetailViewPermission struct {
+	PermissionId   int
+	PermissionName string
 }
 
 func GetUnPublishDayReport(startTime time.Time, endTime time.Time) (item *Report, err error) {
@@ -642,6 +870,7 @@ type ElasticReportDetail struct {
 	ClassifyNameSecond string `description:"二级分类名称"`
 	Categories         string `description:"关联的品种名称(包括品种别名)"`
 	StageStr           string `description:"报告期数"`
+	BodyMd5            string `description:"MD5加密之后的内容"`
 }
 
 // GetLastPublishedDayWeekReport 获取上一篇已发布的晨周报
@@ -1033,8 +1262,9 @@ func UpdateReportChapterPublishTime(reportId int, videoNameDate string) (err err
 
 // MarkEditReport 标记编辑英文研报的请求数据
 type MarkEditReport struct {
-	ReportId int `description:"研报id"`
-	Status   int `description:"标记状态,1:编辑中,2:编辑完成"`
+	ReportId        int `description:"研报id"`
+	ReportChapterId int `description:"研报章节id"`
+	Status          int `description:"标记状态,1:编辑中,2:编辑完成"`
 }
 
 type MarkReportResp struct {
@@ -1173,4 +1403,4 @@ func UpdatePdfUrlReportById(reportId int) (err error) {
 	sql := `UPDATE report SET detail_img_url = '',detail_pdf_url='',modify_time=NOW() WHERE id = ? `
 	_, err = o.Raw(sql, reportId).Exec()
 	return
-}
+}

+ 110 - 0
models/report/report_chapter_grant.go

@@ -0,0 +1,110 @@
+package report
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ReportChapterGrant
+// @Description: 报告章节授权用户表
+type ReportChapterGrant struct {
+	GrantId         int       `orm:"column(grant_id)"` // 授权id
+	ReportChapterId int       `description:"报告章节id"`
+	AdminId         int       `description:"授权的用户id"`
+	CreateTime      time.Time `description:"授权时间"`
+}
+
+// MultiAddReportChapterGrantGrant
+// @Description: 批量添加报告授权用户
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:36:02
+// @param reportChapterId int
+// @param list []*ReportChapterGrant
+// @return err error
+func (m ReportChapterGrant) MultiAddReportChapterGrantGrant(reportChapterId int, list []*ReportChapterGrant) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := "DELETE from report_chapter_grant where report_chapter_id=?"
+	_, err = to.Raw(sql, reportChapterId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 新增授权记录
+	if len(list) > 0 {
+		_, tmpErr := to.InsertMulti(500, list)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+
+	return
+}
+
+// GetGrantListById
+// @Description: 根据id获取授权列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportChapterId int
+// @return list []*ReportChapterGrant
+// @return err error
+func (m ReportChapterGrant) GetGrantListById(reportChapterId int) (list []*ReportChapterGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter_grant WHERE report_chapter_id=? `
+	_, err = o.Raw(sql, reportChapterId).QueryRows(&list)
+
+	return
+}
+
+// GetGrantListByIdList
+// @Description: 根据id列表获取授权列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportChapterIdList []int
+// @return list []*ReportChapterGrant
+// @return err error
+func (m ReportChapterGrant) GetGrantListByIdList(reportChapterIdList []int) (list []*ReportChapterGrant, err error) {
+	num := len(reportChapterIdList)
+	if num <= 0 {
+		return
+	}
+
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter_grant WHERE report_chapter_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, reportChapterIdList).QueryRows(&list)
+
+	return
+}
+
+// GetGrantByIdAndAdmin
+// @Description: 根据reportId和操作人获取报告章节权限配置
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:49:59
+// @param reportChapterId int
+// @param sysUserId int
+// @return item *ReportGrant
+// @return err error
+func (m ReportChapterGrant) GetGrantByIdAndAdmin(reportChapterId, sysUserId int) (item *ReportGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter_grant WHERE report_chapter_id = ? AND admin_id = ? `
+	err = o.Raw(sql, reportChapterId, sysUserId).QueryRow(&item)
+
+	return
+}

+ 93 - 0
models/report/report_chapter_permission_mapping.go

@@ -0,0 +1,93 @@
+package report
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ReportChapterPermissionMapping
+// @Description: 报告章节的权限关系表
+type ReportChapterPermissionMapping struct {
+	ReportChapterPermissionMappingId int `orm:"column(report_chapter_permission_mapping_id)"`
+	ReportChapterId                  int `description:"报告章节的id"` // 报告章节的id
+	ChartPermissionId                int `description:"权限id"`    // 权限id
+	CreateTime                       time.Time
+}
+
+// MultiAddReportChapterPermissionMappingPermission
+// @Description: 批量添加报告品种权限用户
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:36:02
+// @param reportChapterId int
+// @param list []*ReportChapterPermissionMapping
+// @return err error
+func (m ReportChapterPermissionMapping) MultiAddReportChapterPermissionMappingPermission(reportChapterId int, list []*ReportChapterPermissionMapping) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := "DELETE from report_chapter_permission_mapping where report_chapter_id=?"
+	_, err = to.Raw(sql, reportChapterId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 新增品种权限记录
+	if len(list) > 0 {
+		_, tmpErr := to.InsertMulti(500, list)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+
+	return
+}
+
+// GetPermissionListById
+// @Description: 根据id获取品种权限列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportChapterId int
+// @return list []*ReportChapterPermissionMapping
+// @return err error
+func (m ReportChapterPermissionMapping) GetPermissionListById(reportChapterId int) (list []*ReportChapterPermissionMapping, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter_permission_mapping WHERE report_chapter_id=? `
+	_, err = o.Raw(sql, reportChapterId).QueryRows(&list)
+
+	return
+}
+
+// GetPermissionListByIdList
+// @Description: 根据id列表获取品种权限列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportChapterIdList []int
+// @return list []*ReportChapterPermissionMapping
+// @return err error
+func (m ReportChapterPermissionMapping) GetPermissionListByIdList(reportChapterIdList []int) (list []*ReportChapterPermissionMapping, err error) {
+	num := len(reportChapterIdList)
+	if num <= 0 {
+		return
+	}
+
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_chapter_permission_mapping WHERE report_chapter_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, reportChapterIdList).QueryRows(&list)
+
+	return
+}

+ 126 - 0
models/report/report_grant.go

@@ -0,0 +1,126 @@
+package report
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// ReportGrant
+// @Description: 报告授权用户表
+type ReportGrant struct {
+	GrantId    int       `orm:"column(grant_id)"` // 授权id
+	ReportId   int       `description:"报告id"`
+	AdminId    int       `description:"授权的用户id"`
+	CreateTime time.Time `description:"授权时间"`
+}
+
+// MultiAddReportGrantGrant
+// @Description: 批量添加报告授权用户
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:36:02
+// @param reportId int
+// @param list []*ReportGrant
+// @return err error
+func (m ReportGrant) MultiAddReportGrantGrant(reportId int, list []*ReportGrant) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := "DELETE from report_grant where report_id=?"
+	_, err = to.Raw(sql, reportId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 新增授权记录
+	if len(list) > 0 {
+		_, tmpErr := to.InsertMulti(500, list)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+
+	return
+}
+
+// GetGrantListById
+// @Description: 根据id获取授权列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportId int
+// @return list []*ReportGrant
+// @return err error
+func (m ReportGrant) GetGrantListById(reportId int) (list []*ReportGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_grant WHERE report_id=? `
+	_, err = o.Raw(sql, reportId).QueryRows(&list)
+
+	return
+}
+
+// GetGrantListByIdList
+// @Description: 根据id列表获取授权列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param reportIdList []int
+// @return list []*ReportGrant
+// @return err error
+func (m ReportGrant) GetGrantListByIdList(reportIdList []int) (list []*ReportGrant, err error) {
+	num := len(reportIdList)
+	if num <= 0 {
+		return
+	}
+
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_grant WHERE report_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, reportIdList).QueryRows(&list)
+
+	return
+}
+
+// GetGrantByIdAndAdmin
+// @Description: 根据reportId和操作人获取报告权限配置
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:49:59
+// @param reportId int
+// @param sysUserId int
+// @return item *ReportGrant
+// @return err error
+func (m ReportGrant) GetGrantByIdAndAdmin(reportId, sysUserId int) (item *ReportGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_grant WHERE report_id = ? AND admin_id = ? `
+	err = o.Raw(sql, reportId, sysUserId).QueryRow(&item)
+
+	return
+}
+
+// GetGrantListByAdminId
+// @Description: 根据id获取授权列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-04 15:33:58
+// @param adminId int
+// @return list []*ReportGrant
+// @return err error
+func (m ReportGrant) GetGrantListByAdminId(adminId int) (list []*ReportGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_grant WHERE admin_id=? `
+	_, err = o.Raw(sql, adminId).QueryRows(&list)
+
+	return
+}

+ 6 - 1
models/report_approve/report_approve.go

@@ -17,6 +17,7 @@ type ReportApprove struct {
 	ReportTitle      string    `description:"报告标题"`
 	ClassifyFirstId  int       `description:"一级分类ID"`
 	ClassifySecondId int       `description:"二级分类ID"`
+	ClassifyThirdId  int       `description:"三级分类ID"`
 	State            int       `description:"审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
 	FlowId           int       `description:"审批流ID"`
 	FlowVersion      int       `description:"审批流版本"`
@@ -37,6 +38,7 @@ var ReportApproveCols = struct {
 	ReportTitle      string `description:"报告标题"`
 	ClassifyFirstId  string `description:"一级分类ID"`
 	ClassifySecondId string `description:"二级分类ID"`
+	ClassifyThirdId  string `description:"三级分类ID"`
 	State            string
 	FlowId           string
 	FlowVersion      string
@@ -55,6 +57,7 @@ var ReportApproveCols = struct {
 	ReportTitle:      "report_title",
 	ClassifyFirstId:  "classify_first_id",
 	ClassifySecondId: "classify_second_id",
+	ClassifyThirdId:  "classify_third_id",
 	State:            "state",
 	FlowId:           "flow_id",
 	FlowVersion:      "flow_version",
@@ -271,6 +274,8 @@ type ReportApproveItemOrm struct {
 	HandleTime            time.Time `description:"处理时间"`
 	CreateTime            time.Time `description:"创建时间"`
 	ModifyTime            time.Time `description:"修改时间"`
+	NodeState             int       `description:"当前节点审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回" json:"-"`
+	NodeApproveTime       time.Time `description:"当前节点审批时间" json:"-"`
 }
 
 // GetApprovingReportApproveCount 获取待处理的审批分页列表总数
@@ -320,7 +325,7 @@ func GetApprovedReportApprovePageList(cond string, pars []interface{}, orderRule
 	if orderRule != "" {
 		order = ` ORDER BY ` + orderRule
 	}
-	sql := fmt.Sprintf(`SELECT a.report_approve_record_id, a.state AS record_state, a.approve_time AS handle_time, b.*
+	sql := fmt.Sprintf(`SELECT a.report_approve_record_id, a.state AS record_state,a.node_state,a.node_approve_time, a.approve_time AS handle_time, b.*
 		FROM report_approve_record AS a
 		JOIN report_approve AS b ON a.report_approve_id = b.report_approve_id
 		WHERE 1 = 1 %s %s

+ 3 - 0
models/report_approve/report_approve_flow.go

@@ -16,6 +16,7 @@ type ReportApproveFlow struct {
 	ReportType          int       `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
 	ClassifyFirstId     int       `description:"一级分类ID"`
 	ClassifySecondId    int       `description:"二级分类ID"`
+	ClassifyThirdId     int       `description:"三级分类ID"`
 	CurrVersion         int       `description:"当前版本号"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"修改时间"`
@@ -27,6 +28,7 @@ var ReportApproveFlowCols = struct {
 	ReportType          string
 	ClassifyFirstId     string
 	ClassifySecondId    string
+	ClassifyThirdId     string
 	CurrVersion         string
 	CreateTime          string
 	ModifyTime          string
@@ -36,6 +38,7 @@ var ReportApproveFlowCols = struct {
 	ReportType:          "report_type",
 	ClassifyFirstId:     "classify_first_id",
 	ClassifySecondId:    "classify_second_id",
+	ClassifyThirdId:     "classify_third_id",
 	CurrVersion:         "curr_version",
 	CreateTime:          "create_time",
 	ModifyTime:          "modify_time",

+ 39 - 0
models/report_approve/report_approve_record.go

@@ -25,6 +25,10 @@ type ReportApproveRecord struct {
 	ApproveTime           time.Time `description:"审批时间"`
 	CreateTime            time.Time `description:"创建时间"`
 	ModifyTime            time.Time `description:"修改时间"`
+	NodeState             int       `description:"当前节点审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	NodeApproveUserId     int       `description:"当前节点审批人ID"`
+	NodeApproveUserName   string    `description:"当前节点审批人姓名"`
+	NodeApproveTime       time.Time `description:"当前节点审批时间"`
 }
 
 var ReportApproveRecordCols = struct {
@@ -43,6 +47,10 @@ var ReportApproveRecordCols = struct {
 	ApproveTime           string
 	CreateTime            string
 	ModifyTime            string
+	NodeState             string `description:"当前节点审批状态:1-待审批;2-已审批;3-已驳回;4-已撤回"`
+	NodeApproveUserId     string `description:"当前节点审批人ID"`
+	NodeApproveUserName   string `description:"当前节点审批人姓名"`
+	NodeApproveTime       string `description:"当前节点审批时间"`
 }{
 	ReportApproveRecordId: "report_approve_record_id",
 	ReportApproveId:       "report_approve_id",
@@ -59,6 +67,10 @@ var ReportApproveRecordCols = struct {
 	ApproveTime:           "approve_time",
 	CreateTime:            "create_time",
 	ModifyTime:            "modify_time",
+	NodeState:             "node_state",
+	NodeApproveUserId:     "node_approve_user_id",
+	NodeApproveUserName:   "node_approve_user_name",
+	NodeApproveTime:       "node_approve_time",
 }
 
 func (m *ReportApproveRecord) TableName() string {
@@ -209,6 +221,33 @@ func FormatReportApproveRecord2Item(origin *ReportApproveRecord) (item *ReportAp
 	return
 }
 
+// UpdateNodeState
+// @Description: 将该审批的同一个节点的记录标记为已审批
+// @author: Roc
+// @receiver m
+// @datetime 2024-06-11 13:57:20
+// @param reportApproveId int
+// @param nodeId int
+// @param nodeState int
+// @param nodeApproveUserId int
+// @param nodeApproveUserName string
+// @param nodeApproveTime time.Time
+// @return err error
+func (m *ReportApproveRecord) UpdateNodeState(reportApproveId, nodeId, nodeState, nodeApproveUserId int, nodeApproveUserName string, nodeApproveTime time.Time) (err error) {
+	pars := make([]interface{}, 0)
+	pars = append(pars, nodeState, nodeApproveUserId, nodeApproveUserName, nodeApproveTime)
+
+	// 更新条件
+	whereParas := []interface{}{reportApproveId, nodeId}
+	pars = append(pars, whereParas)
+
+	o := orm.NewOrmUsingDB("rddp")
+	sql := fmt.Sprintf(`UPDATE %s SET node_state=?,node_approve_user_id=?,node_approve_user_name=?,node_approve_time=? WHERE report_approve_id = ? AND node_id = ?`, m.TableName())
+	_, err = o.Raw(sql, pars).Exec()
+
+	return
+}
+
 // ReportApproveDetailNodeUserRecord 审批详情-节点用户审批记录
 type ReportApproveDetailNodeUserRecord struct {
 	ReportApproveRecordId int    `description:"审批记录ID"`

+ 231 - 29
models/report_chapter.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"eta/eta_api/models/report"
 	"eta/eta_api/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
@@ -8,33 +9,61 @@ import (
 
 // ReportChapter 报告章节
 type ReportChapter struct {
-	ReportChapterId   int       `orm:"column(report_chapter_id);pk" description:"报告章节ID"`
-	ReportId          int       `description:"报告ID"`
-	ReportType        string    `description:"报告类型 day-晨报 week-周报"`
-	ClassifyIdFirst   int       `description:"一级分类id"`
-	ClassifyNameFirst string    `description:"一级分类名称"`
-	TypeId            int       `description:"品种ID"`
-	TypeName          string    `description:"品种名称"`
-	Title             string    `description:"标题"`
-	Abstract          string    `description:"摘要"`
-	AddType           int       `description:"新增方式:1:新增报告,2:继承报告"`
-	Author            string    `description:"作者"`
-	Content           string    `description:"内容"`
-	ContentSub        string    `description:"内容前两个章节"`
-	Stage             int       `description:"期数"`
-	Trend             string    `description:"趋势观点"`
-	Sort              int       `description:"排序: 数值越小越靠前"`
-	IsEdit            int       `description:"是否已编辑 0-待编辑 1-已编辑"`
-	PublishState      int       `description:"发布状态 1-待发布,2-已发布"`
-	PublishTime       time.Time `description:"发布时间"`
-	VideoUrl          string    `description:"音频文件URL"`
-	VideoName         string    `description:"音频文件名称"`
-	VideoPlaySeconds  string    `description:"音频播放时长"`
-	VideoSize         string    `description:"音频文件大小,单位M"`
-	VideoKind         int       `description:"音频生成方式:1,手动上传,2:自动生成"`
-	CreateTime        string    `description:"创建时间"`
-	ModifyTime        time.Time `description:"修改时间"`
-	OriginalVideoUrl  string    `description:"原始音频文件URL"`
+	ReportChapterId     int       `orm:"column(report_chapter_id);pk" description:"报告章节ID"`
+	ReportId            int       `description:"报告ID"`
+	ReportType          string    `description:"报告类型 day-晨报 week-周报"`
+	ClassifyIdFirst     int       `description:"一级分类id"`
+	ClassifyNameFirst   string    `description:"一级分类名称"`
+	TypeId              int       `description:"品种ID"`
+	TypeName            string    `description:"品种名称"`
+	Title               string    `description:"标题"`
+	Abstract            string    `description:"摘要"`
+	AddType             int       `description:"新增方式:1:新增报告,2:继承报告"`
+	Author              string    `description:"作者"`
+	Content             string    `description:"内容"`
+	ContentSub          string    `description:"内容前两个章节"`
+	Stage               int       `description:"期数"`
+	Trend               string    `description:"趋势观点"`
+	Sort                int       `description:"排序: 数值越小越靠前"`
+	IsEdit              int       `description:"是否已编辑 0-待编辑 1-已编辑"`
+	PublishState        int       `description:"发布状态 1-待发布,2-已发布"`
+	PublishTime         time.Time `description:"发布时间"`
+	VideoUrl            string    `description:"音频文件URL"`
+	VideoName           string    `description:"音频文件名称"`
+	VideoPlaySeconds    string    `description:"音频播放时长"`
+	VideoSize           string    `description:"音频文件大小,单位M"`
+	VideoKind           int       `description:"音频生成方式:1,手动上传,2:自动生成"`
+	CreateTime          string    `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+	OriginalVideoUrl    string    `description:"原始音频文件URL"`
+	ClassifyIdSecond    int       `description:"二级分类id"`
+	ClassifyNameSecond  string    `description:"二级分类名称"`
+	ClassifyIdThird     int       `description:"三级分类id"`
+	ClassifyNameThird   string    `description:"三级分类名称"`
+	ContentStruct       string    `description:"内容组件"`
+	LastModifyAdminId   int       `description:"最后更新人ID"`
+	LastModifyAdminName string    `description:"最后更新人姓名"`
+	ContentModifyTime   time.Time `description:"内容更新时间"`
+	CanvasColor         string    `description:"画布颜色"`
+	HeadResourceId      int       `description:"版头资源ID"`
+	EndResourceId       int       `description:"版尾资源ID"`
+	CollaborateType     int8      `description:"协作方式,1:个人,2:多人协作。默认:1"`
+	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
+	ReportCreateTime    time.Time `description:"报告时间创建时间"`
+}
+
+// ReportChapterItem
+// @Description: 章节详情(带有一些额外的数据)
+type ReportChapterItem struct {
+	ReportChapter
+	GrandAdminIdList []int  `description:"授权的用户id列表"`
+	PermissionIdList []int  `description:"关联的品种id列表"`
+	CanEdit          bool   `description:"是否可编辑"`
+	Editor           string `description:"编辑人"`
+	HeadImg          string `description:"报告头图地址"`
+	EndImg           string `description:"报告尾图地址"`
+	HeadStyle        string `description:"版头样式"`
+	EndStyle         string `description:"版尾样式"`
 }
 
 type ReportChapterResp struct {
@@ -62,6 +91,10 @@ type ReportChapterResp struct {
 	PublishTime      string `description:"发布时间"`
 	CreateTime       string `description:"创建时间"`
 	ModifyTime       string `description:"修改时间"`
+	GrandAdminIdList []int  `description:"授权的用户id列表"`
+	PermissionIdList []int  `description:"关联的品种id列表"`
+	CanEdit          bool   `description:"是否可编辑"`
+	Editor           string `description:"编辑人"`
 }
 
 // GetChapterListByReportId 根据ReportId获取章节列表
@@ -82,6 +115,15 @@ func GetPublishedChapterListByReportId(reportId int) (list []*ReportChapter, err
 	return
 }
 
+// AddReportChapterReq
+// @Description: 新增报告章节请求体
+type AddReportChapterReq struct {
+	ReportId         int    `description:"报告ID"`
+	Title            string `description:"标题"`
+	PermissionIdList []int  `description:"报告关联的品种权限"`
+	AdminIdList      []int  `description:"授权的编辑人id列表"`
+}
+
 // EditReportChapterReq 编辑报告章节请求体
 type EditReportChapterReq struct {
 	ReportChapterId  int            `description:"报告章节ID"`
@@ -95,6 +137,15 @@ type EditReportChapterReq struct {
 	VideoName        string         `description:"音频文件名称"`
 	VideoPlaySeconds string         `description:"音频播放时长"`
 	VideoSize        string         `description:"音频文件大小,单位M"`
+
+	// 以下是智能研报相关
+	ContentStruct  string `description:"内容组件"`
+	HeadImg        string `description:"报告头图地址"`
+	EndImg         string `description:"报告尾图地址"`
+	CanvasColor    string `description:"画布颜色"`
+	NeedSplice     int    `description:"是否拼接版头版位的标记,主要是为了兼容历史报告。0-不需要 1-需要"`
+	HeadResourceId int    `description:"版头资源ID"`
+	EndResourceId  int    `description:"版尾资源ID"`
 }
 
 type EditTickList struct {
@@ -121,10 +172,27 @@ func GetLastPublishedReportChapter(typeId int, reportType string) (item *ReportC
 	return
 }
 
+// Add
+// @Description: 新增章节报告
+// @author: Roc
+// @receiver chapterInfo
+// @datetime 2024-06-04 15:14:41
+// @return err error
+func (chapterChapterInfo *ReportChapter) Add() (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	lastId, err := o.Insert(chapterChapterInfo)
+	if err != nil {
+		return
+	}
+	chapterChapterInfo.ReportChapterId = int(lastId)
+
+	return
+}
+
 // UpdateChapter 更新报表章节
-func (chapterInfo *ReportChapter) UpdateChapter(cols []string) (err error) {
+func (chapterChapterInfo *ReportChapter) UpdateChapter(cols []string) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	_, err = o.Update(chapterInfo, cols...)
+	_, err = o.Update(chapterChapterInfo, cols...)
 
 	return
 }
@@ -305,3 +373,137 @@ func CountReportChapterByTypeId(typeId int) (count int, err error) {
 	err = o.Raw(sql, typeId).QueryRow(&count)
 	return
 }
+
+// AddReportChapter
+// @Description: 待添加的报告章节
+type AddReportChapter struct {
+	ReportChapter *ReportChapter
+	GrantList     []*report.ReportChapterGrant
+}
+
+// EditReportChapterBaseInfoAndPermissionReq
+// @Description: 编辑报告章节的基础信息请求
+type EditReportChapterBaseInfoAndPermissionReq struct {
+	ReportChapterId  int    `description:"报告章节ID"`
+	Title            string `description:"标题"`
+	PermissionIdList []int  `description:"报告关联的品种权限"`
+	AdminIdList      []int  `description:"授权的编辑人id列表"`
+}
+
+// GetReportChapterIdList
+// @Description: 获取报告的所有章节id列表
+// @author: Roc
+// @datetime 2024-06-05 11:09:40
+// @param reportId int
+// @return list []int
+// @return err error
+func GetReportChapterIdList(reportId int) (list []int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT report_chapter_id FROM report_chapter
+			WHERE report_id = ? 
+			ORDER BY report_chapter_id ASC `
+	_, err = o.Raw(sql, reportId).QueryRows(&list)
+
+	return
+}
+
+// ReportChapterMoveReq
+// @Description:  报告章节移动请求
+type ReportChapterMoveReq struct {
+	ReportChapterId int `description:"报告章节id"`
+	//	ParentChartPermissionId int `description:"父级品种id"`
+	PrevReportChapterId int `description:"上一个兄弟节点报告章节id"`
+	NextReportChapterId int `description:"下一个兄弟节点报告章节id"`
+}
+
+// GetReportChapterById
+// @Description: 获取具体章节
+// @author: Roc
+// @receiver r
+// @datetime 2024-06-06 09:32:40
+// @param reportChapterId int
+// @return item *ReportChapter
+// @return err error
+func (chapterChapterInfo *ReportChapter) GetReportChapterById(reportChapterId int) (item *ReportChapter, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM report_chapter WHERE report_chapter_id = ?`
+	err = o.Raw(sql, reportChapterId).QueryRow(&item)
+	return
+}
+
+// UpdateReportChapterSortByReportId
+// @Description: 根据父类id更新排序
+// @author: Roc
+// @receiver chapterChapterInfo
+// @datetime 2024-06-06 09:39:28
+// @param reportId int
+// @param reportChapterId int
+// @param nowSort int
+// @param updateSort string
+// @return err error
+func (chapterChapterInfo *ReportChapter) UpdateReportChapterSortByReportId(reportId, reportChapterId, nowSort int, updateSort string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	pars := make([]interface{}, 0)
+	sql := ` update report_chapter set sort = ` + updateSort + ` WHERE report_id = ? AND sort > ?`
+	pars = append(pars, reportId, nowSort)
+
+	if reportChapterId > 0 {
+		sql += ` or ( report_chapter_id > ?  and sort = ? )`
+		pars = append(pars, reportChapterId, nowSort)
+	}
+
+	_, err = o.Raw(sql, pars).Exec()
+
+	return
+}
+
+// GetFirstReportChapterByReportId
+// @Description: 获取当前报告下,且排序数相同 的排序第一条的数据
+// @author: Roc
+// @receiver chapterChapterInfo
+// @datetime 2024-06-06 09:45:32
+// @param reportId int
+// @return item *ReportChapter
+// @return err error
+func (chapterChapterInfo *ReportChapter) GetFirstReportChapterByReportId(reportId int) (item *ReportChapter, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM report_chapter WHERE 1 = 1 AND report_id = ? ORDER BY sort ASC, report_chapter_id ASC LIMIT 1`
+	err = o.Raw(sql, reportId).QueryRow(&item)
+	return
+}
+
+// GetMaxSortByReportId
+// @Description: 获取最大的排序值
+// @author: Roc
+// @receiver chapterChapterInfo
+// @datetime 2024-06-06 09:44:13
+// @param reportId int
+// @return maxSort int
+// @return err error
+func (chapterChapterInfo *ReportChapter) GetMaxSortByReportId(reportId int) (maxSort int, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT max(sort) AS sort FROM report_chapter WHERE report_id = ?`
+	err = o.Raw(sql, reportId).QueryRow(&maxSort)
+
+	return
+}
+
+// Update
+// @Description: 数据变更
+// @author: Roc
+// @receiver chapterChapterInfo
+// @datetime 2024-06-06 09:47:46
+// @param cols []string
+// @return err error
+func (chapterChapterInfo *ReportChapter) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	_, err = o.Update(chapterChapterInfo, cols...)
+
+	return
+}
+
+// DelReportChapterReq
+// @Description: 删除报告章节请求体
+type DelReportChapterReq struct {
+	ReportChapterId int `description:"报告章节ID"`
+}

+ 17 - 2
models/report_chapter_type.go

@@ -30,6 +30,7 @@ type ReportChapterType struct {
 	IsSet                  int       `description:"是否设置:0为设置,1已设置"`
 	YbIconUrl              string    `description:"研报小程序icon"`
 	YbBottomIcon           string    `description:"研报小程序详情底部icon"`
+	ReportClassifyId       int       `description:"所属分类id"`
 }
 
 func (r *ReportChapterType) Create() (err error) {
@@ -341,7 +342,7 @@ type ReportChapterTypeListItem struct {
 // ReportChapterTypeAddReq 新增章节类型请求体
 type ReportChapterTypeAddReq struct {
 	ReportChapterTypeName string `description:"报告章节类型名称"`
-	ResearchType          string `description:"研报类型"`
+	ClassifyId            int    `description:"所属报告分类id"`
 	ChartPermissionIdList []int  `description:"权限id数组"`
 	/*SelectedImage         string `description:"选中时的icon"`
 	UnselectedImage       string `description:"未选中时的icon"`
@@ -354,7 +355,7 @@ type ReportChapterTypeAddReq struct {
 type ReportChapterTypeEditReq struct {
 	ReportChapterTypeId   int    `description:"报告章节类型id"`
 	ReportChapterTypeName string `description:"报告章节类型名称"`
-	ResearchType          string `description:"研报类型"`
+	ClassifyId            int    `description:"所属报告分类id"`
 	ChartPermissionIdList []int  `description:"权限id数组"`
 	/*SelectedImage         string `description:"选中时的icon"`
 	UnselectedImage       string `description:"未选中时的icon"`
@@ -447,3 +448,17 @@ func (r *ReportChapterType) SetEnabled(id, enabled int) (err error) {
 	_, err = o.Raw(sql, enabled, id).Exec()
 	return
 }
+
+// GetReportChapterTypeListByClassifyId
+// @Description: 通过报告类型获取章节类型列表
+// @author: Roc
+// @datetime 2024-06-03 16:00:12
+// @param classifyId int
+// @return list []*ReportChapterType
+// @return err error
+func GetReportChapterTypeListByClassifyId(classifyId int) (list []*ReportChapterType, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM report_chapter_type WHERE report_classify_id = ? AND enabled = 1`
+	_, err = o.Raw(sql, classifyId).QueryRows(&list)
+	return
+}

+ 47 - 22
models/report_chapter_type_permission.go

@@ -16,16 +16,22 @@ type ReportChapterTypePermission struct {
 	CreatedTime           time.Time `description:"创建时间"`
 }
 
-// GetChapterTypePermissionByTypeIdAndResearchType 根据章节类型ID及研报类型获取章节类型权限列表
-func GetChapterTypePermissionByTypeIdAndResearchType(typeId int, researchType string) (list []*ReportChapterTypePermission, err error) {
+// GetChapterTypePermissionByReportChapterTypeId
+// @Description: 根据章节类型ID获取章节类型权限列表
+// @author: Roc
+// @datetime 2024-06-03 15:42:47
+// @param typeId int
+// @return list []*ReportChapterTypePermission
+// @return err error
+func GetChapterTypePermissionByReportChapterTypeId(typeId int) (list []*ReportChapterTypePermission, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := ` SELECT * FROM report_chapter_type_permission WHERE report_chapter_type_id = ? AND research_type = ? ORDER BY chart_permission_id ASC `
-	_, err = o.Raw(sql, typeId, researchType).QueryRows(&list)
+	sql := ` SELECT * FROM report_chapter_type_permission WHERE report_chapter_type_id = ?  ORDER BY chart_permission_id ASC `
+	_, err = o.Raw(sql, typeId).QueryRows(&list)
 	return
 }
 
 // SetReportChapterTypePermission 设置报告章节类型权限
-func SetReportChapterTypePermission(chapterTypeId int, researchType string, newPermissions []*ReportChapterTypePermission, newWeekPermissions []*ChartPermissionChapterMapping) (err error) {
+func SetReportChapterTypePermission(chapterTypeId int, newPermissions []*ReportChapterTypePermission) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	to, err := o.Begin()
 	if err != nil {
@@ -40,8 +46,8 @@ func SetReportChapterTypePermission(chapterTypeId int, researchType string, newP
 	}()
 
 	// 删除原章节类型权限
-	sql := `DELETE FROM report_chapter_type_permission WHERE report_chapter_type_id = ? AND research_type = ?`
-	_, err = to.Raw(sql, chapterTypeId, researchType).Exec()
+	sql := `DELETE FROM report_chapter_type_permission WHERE report_chapter_type_id = ?`
+	_, err = to.Raw(sql, chapterTypeId).Exec()
 	if err != nil {
 		return
 	}
@@ -55,22 +61,23 @@ func SetReportChapterTypePermission(chapterTypeId int, researchType string, newP
 	}
 
 	// 周报章节调整chart_permission_chapter_mapping表
-	if researchType == utils.REPORT_TYPE_WEEK {
-		// 删除原权限
-		sql = `DELETE FROM chart_permission_chapter_mapping WHERE report_chapter_type_id = ? AND research_type = ?`
-		_, err = to.Raw(sql, chapterTypeId, researchType).Exec()
-		if err != nil {
-			return
-		}
+	//if researchType == utils.REPORT_TYPE_WEEK {
+	//	// 删除原权限
+	//	sql = `DELETE FROM chart_permission_chapter_mapping WHERE report_chapter_type_id = ? AND research_type = ?`
+	//	_, err = to.Raw(sql, chapterTypeId, researchType).Exec()
+	//	if err != nil {
+	//		return
+	//	}
+	//
+	//	// 新增权限
+	//	if len(newWeekPermissions) > 0 {
+	//		_, err = to.InsertMulti(len(newWeekPermissions), newWeekPermissions)
+	//		if err != nil {
+	//			return
+	//		}
+	//	}
+	//}
 
-		// 新增权限
-		if len(newWeekPermissions) > 0 {
-			_, err = to.InsertMulti(len(newWeekPermissions), newWeekPermissions)
-			if err != nil {
-				return
-			}
-		}
-	}
 	return
 }
 
@@ -81,3 +88,21 @@ func GetChapterTypePermissionByResearchType(researchType string) (list []*Report
 	_, err = o.Raw(sql, researchType).QueryRows(&list)
 	return
 }
+
+// GetChapterTypePermissionByChapterTypeIdList
+// @Description: 根据章节类型ID列表获取章节类型权限列表
+// @author: Roc
+// @datetime 2024-06-03 14:10:17
+// @param chapterTypeIdList []int
+// @return list []*ReportChapterTypePermission
+// @return err error
+func GetChapterTypePermissionByChapterTypeIdList(chapterTypeIdList []int) (list []*ReportChapterTypePermission, err error) {
+	num := len(chapterTypeIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` SELECT * FROM report_chapter_type_permission WHERE report_chapter_type_id in (` + utils.GetOrmInReplace(num) + `) ORDER BY chart_permission_id ASC `
+	_, err = o.Raw(sql, chapterTypeIdList).QueryRows(&list)
+	return
+}

+ 66 - 0
models/report_grant.go

@@ -0,0 +1,66 @@
+package models
+
+import (
+	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+)
+
+// ReportGrant Ppt授权表
+type ReportGrant struct {
+	GrantId      int64     `orm:"column(grant_id);pk;auto" description:"自增序号"`
+	ReportId     int64     `description:"report ID"`
+	DepartmentId int64     `description:"授权部门id"`
+	GrantAdminId int64     `description:"授权部门id"`
+	CreateTime   time.Time `orm:"auto_now_add;type(datetime)" description:"创建时间"`
+}
+
+// GetReportGrantInfo 获取已经有权限的report列表
+func GetReportGrantInfo(reportId int) (list []*ReportGrant, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM report_grant WHERE report_id=? `
+	_, err = o.Raw(sql, reportId).QueryRows(&list)
+	return
+}
+
+// MultiAddReportGrant 批量添加授权记录
+func MultiAddReportGrant(reportId int, list []*ReportGrant) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := "DELETE from report_grant where report_id=?"
+	_, err = to.Raw(sql, reportId).Exec()
+	if err != nil {
+		return
+	}
+
+	// 新增授权记录
+	if len(list) > 0 {
+		_, tmpErr := to.InsertMulti(len(list), list)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+	}
+
+	return
+}
+
+// DeleteReportGrant 移除授权记录
+func DeleteReportGrant(reportId int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := "DELETE from report_grant where report_id=?"
+	_, err = o.Raw(sql, reportId).Exec()
+
+	return
+}

+ 359 - 0
models/report_v2.go

@@ -0,0 +1,359 @@
+package models
+
+import (
+	"eta/eta_api/models/report"
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+)
+
+// AddReportAndChapter
+// @Description: 新增报告及章节
+// @author: Roc
+// @datetime 2024-06-06 17:08:34
+// @param reportItem *Report
+// @param allGrantUserList []*report.ReportGrant
+// @param addReportChapterList []AddReportChapter
+// @return reportId int64
+// @return err error
+func AddReportAndChapter(reportItem *Report, allGrantUserList []*report.ReportGrant, addReportChapterList []AddReportChapter) (reportId int64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 新增报告
+	reportId, err = to.Insert(reportItem)
+	if err != nil {
+		return
+	}
+	reportItem.Id = int(reportId)
+
+	// 新增报告授权
+	if len(allGrantUserList) > 0 {
+		for _, v := range allGrantUserList {
+			v.ReportId = reportItem.Id
+		}
+		_, err = to.InsertMulti(500, allGrantUserList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 新增报告章节
+	if len(addReportChapterList) > 0 {
+		for _, addReportChapter := range addReportChapterList {
+			// 新增章节
+			chapterItem := addReportChapter.ReportChapter
+			chapterItem.ReportId = int(reportId)
+			cpId, tmpErr := to.Insert(chapterItem)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			chapterItem.ReportChapterId = int(cpId)
+
+			// 新增章节授权
+			if len(addReportChapter.GrantList) > 0 {
+				grantList := addReportChapter.GrantList
+				for _, v := range grantList {
+					v.ReportChapterId = chapterItem.ReportChapterId
+				}
+				_, err = to.InsertMulti(500, grantList)
+				if err != nil {
+					return
+				}
+			}
+
+		}
+	}
+
+	return
+}
+
+// EditReportAndPermission
+// @Description: 修改报告的基础信息、授权用户权限
+// @author: Roc
+// @datetime 2024-06-06 17:11:12
+// @param reportInfo *Report
+// @param updateCols []string
+// @param addReportGrantList []*report.ReportGrant
+// @param delReportGrantIdList []int
+// @return err error
+func EditReportAndPermission(reportInfo *Report, updateCols []string, addReportGrantList []*report.ReportGrant, delReportGrantIdList []int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 变更报告章节信息
+	if len(updateCols) > 0 {
+		_, err = to.Update(reportInfo, updateCols...)
+		if err != nil {
+			return
+		}
+	}
+
+	// 新增报告授权用户
+	if len(addReportGrantList) > 0 {
+		_, err = to.InsertMulti(500, addReportGrantList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告授权用户
+	delNum := len(delReportGrantIdList)
+	if delNum > 0 {
+		sql := `DELETE FROM report_grant WHERE grant_id IN (` + utils.GetOrmInReplace(delNum) + `)`
+		_, err = to.Raw(sql, delReportGrantIdList).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// AddChapterBaseInfoAndPermission
+// @Description: 新增报告章节的基础信息、授权用户权限
+// @author: Roc
+// @datetime 2024-06-11 15:33:50
+// @param reportChapterInfo *ReportChapter
+// @param addReportChapterGrantList []*report.ReportChapterGrant
+// @param addChapterPermissionMap []*report.ReportChapterPermissionMapping
+// @return err error
+func AddChapterBaseInfoAndPermission(reportChapterInfo *ReportChapter, addReportChapterGrantList []*report.ReportChapterGrant, addChapterPermissionMap []*report.ReportChapterPermissionMapping) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	lastId, err := to.Insert(reportChapterInfo)
+	if err != nil {
+		return
+	}
+	reportChapterInfo.ReportChapterId = int(lastId)
+
+	// 新增报告章节授权用户
+	if len(addReportChapterGrantList) > 0 {
+		for k, _ := range addReportChapterGrantList {
+			addReportChapterGrantList[k].ReportChapterId = reportChapterInfo.ReportChapterId
+		}
+		_, err = to.InsertMulti(500, addReportChapterGrantList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 新增报告章节的品种配置
+	if len(addChapterPermissionMap) > 0 {
+		for k, _ := range addChapterPermissionMap {
+			addChapterPermissionMap[k].ReportChapterId = reportChapterInfo.ReportChapterId
+		}
+
+		_, err = to.InsertMulti(500, addChapterPermissionMap)
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// EditChapterBaseInfoAndPermission
+// @Description: 修改报告章节的基础信息、授权用户权限、品种权限
+// @author: Roc
+// @datetime 2024-06-05 11:45:04
+// @param reportChapterInfo *ReportChapter
+// @param updateCols []string
+// @param addReportChapterGrantList []report.ReportChapterGrant
+// @param addChapterPermissionMap []*report.ReportChapterPermissionMapping
+// @param delReportChapterGrantIdList []int
+// @param delChapterPermissionMappingIdList []int
+// @return err error
+func EditChapterBaseInfoAndPermission(reportChapterInfo *ReportChapter, updateCols []string, addReportChapterGrantList []*report.ReportChapterGrant, addChapterPermissionMap []*report.ReportChapterPermissionMapping, delReportChapterGrantIdList, delChapterPermissionMappingIdList []int) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 变更报告章节信息
+	if len(updateCols) > 0 {
+		_, err = to.Update(reportChapterInfo, updateCols...)
+		if err != nil {
+			return
+		}
+	}
+
+	// 新增报告章节授权用户
+	if len(addReportChapterGrantList) > 0 {
+		_, err = to.InsertMulti(500, addReportChapterGrantList)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告章节授权用户
+	delNum := len(delReportChapterGrantIdList)
+	if delNum > 0 {
+		sql := `DELETE FROM report_chapter_grant WHERE grant_id IN (` + utils.GetOrmInReplace(delNum) + `)`
+		_, err = to.Raw(sql, delReportChapterGrantIdList).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 新增报告章节的品种配置
+	if len(addChapterPermissionMap) > 0 {
+		_, err = to.InsertMulti(500, addChapterPermissionMap)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告章节的品种配置
+	delNum = len(delChapterPermissionMappingIdList)
+	if delNum > 0 {
+		sql := `DELETE FROM report_chapter_permission_mapping WHERE report_chapter_permission_mapping_id IN (` + utils.GetOrmInReplace(delNum) + `)`
+		_, err = to.Raw(sql, delChapterPermissionMappingIdList).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// DelChapterAndPermission
+// @Description: 删除报告章节、授权用户权限、品种权限
+// @author: Roc
+// @datetime 2024-06-06 17:25:47
+// @param reportInfo *Report
+// @param updateReportCols []string
+// @param reportChapterInfo *ReportChapter
+// @return err error
+func DelChapterAndPermission(reportInfo *Report, updateReportCols []string, reportChapterInfo *ReportChapter) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	// 变更报告信息
+	if len(updateReportCols) > 0 {
+		_, err = to.Update(reportInfo, updateReportCols...)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告对应章节
+	{
+		_, err = to.Delete(reportChapterInfo)
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告章节的授权用户权限
+	{
+		sql := `DELETE FROM report_chapter_grant WHERE report_chapter_id = ? `
+		_, err = to.Raw(sql, reportChapterInfo.ReportChapterId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	// 删除报告章节的品种配置
+	{
+		sql := `DELETE FROM report_chapter_permission_mapping WHERE report_chapter_id = ? `
+		_, err = to.Raw(sql, reportChapterInfo.ReportChapterId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// GetReportListCountByAuthorized
+// @Description: 获取有权限的报告列表的报告数量
+// @author: Roc
+// @datetime 2024-05-30 15:14:01
+// @param condition string
+// @param pars []interface{}
+// @return count int
+// @return err error
+func GetReportListCountByAuthorized(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  `
+	if condition != "" {
+		sql += condition
+	}
+
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+// GetReportListByAuthorized
+// @Description: 获取有权限的报告列表的数据
+// @author: Roc
+// @datetime 2024-05-30 15:15:07
+// @param condition string
+// @param pars []interface{}
+// @param startSize int
+// @param pageSize int
+// @return items []*ReportList
+// @return err error
+func GetReportListByAuthorized(condition string, pars []interface{}, startSize, pageSize int) (items []*ReportList, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+
+	sql := `SELECT id,classify_id_first,classify_name_first,classify_id_second,classify_name_second,classify_id_third,classify_name_third,title,stage,create_time,author,report_layout,collaborate_type,is_public_publish FROM report as a WHERE 1=1  `
+	if condition != "" {
+		sql += condition
+	}
+	// 排序:1:未发布;2:已发布;3-待提交;4-待审批;5-已驳回;6-已通过
+	sql += ` GROUP BY a.id ORDER BY FIELD(state,3,1,4,5,6,2), modify_time DESC LIMIT ?,?`
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}

+ 54 - 0
models/sandbox/sandbox.go

@@ -402,3 +402,57 @@ func GetFirstSandboxByClassifyId(classifyId int) (item *Sandbox, err error) {
 	err = o.Raw(sql, classifyId).QueryRow(&item)
 	return
 }
+
+// UpdateSandboxContent 更新沙盘内容
+func UpdateSandboxContent(list []Sandbox) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	//循环更新沙盘内容
+	for _, sandbox := range list {
+		_, err = to.Update(&sandbox, "Content", "ModifyTime")
+		if err != nil {
+			return
+		}
+	}
+
+	return
+}
+
+// ContentDataStruct 沙盘内容结构体
+type ContentDataStruct struct {
+	Cells []struct {
+		Data *NodeData `json:"data,omitempty"`
+	} `json:"cells"`
+}
+
+type NodeData struct {
+	LinkData []*LinkData `json:"linkData"`
+	LinkFold bool        `json:"linkFold"`
+}
+
+type LinkData struct {
+	RId          string       `json:"RId"`
+	Id           int          `json:"Id"`
+	Name         string       `json:"Name"`
+	Type         int          `json:"Type"`
+	Editing      bool         `json:"editing"`
+	DatabaseType int          `json:"databaseType"`
+	DetailParams DetailParams `json:"detailParams"`
+}
+
+type DetailParams struct {
+	Code       string `json:"code"`
+	Id         int    `json:"id"`
+	ClassifyId int    `json:"classifyId"`
+}

+ 12 - 5
models/sandbox/sandbox_classify.go

@@ -247,10 +247,17 @@ type SandboxLinkCheckReq struct {
 	ReportIdList    []int `description:"报告id列表"`
 }
 
+type SandboxLinkCheckItem struct {
+	Id         int    `description:"id"`
+	Name       string `description:"名称"`
+	UniqueCode string `description:"唯一编码"`
+	ClassifyId int    `description:"分类id"`
+}
+
 type SandboxLinkCheckResp struct {
-	EdbInfoIdList   []int `description:"指标id列表"`
-	ChartInfoIdList []int `description:"图库id列表"`
-	ReportIdList    []int `description:"报告id列表"`
+	EdbInfoIdList   []*SandboxLinkCheckItem `description:"指标id列表"`
+	ChartInfoIdList []*SandboxLinkCheckItem `description:"图库id列表"`
+	ReportIdList    []*SandboxLinkCheckItem `description:"报告id列表"`
 }
 
 // 获取所有子级分类id
@@ -272,7 +279,7 @@ WHERE sc.parent_id = @pv
 // UpdateSandboxClassifyChartPermissionById 根据沙盘id更新品种
 func UpdateSandboxClassifyChartPermissionById(ChartPermissionId int, ChartPermissionName, Ids string) (err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` UPDATE sandbox_classify SET chart_permission_id = ?, chart_permission_name = ? WHERE sandbox_classify_id IN ( `+Ids +` ) `
+	sql := ` UPDATE sandbox_classify SET chart_permission_id = ?, chart_permission_name = ? WHERE sandbox_classify_id IN ( ` + Ids + ` ) `
 	_, err = o.Raw(sql, ChartPermissionId, ChartPermissionName).Exec()
 	return
-}
+}

+ 19 - 0
models/system/sys_admin.go

@@ -1,6 +1,7 @@
 package system
 
 import (
+	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
@@ -377,3 +378,21 @@ func GetSysAdminList(condition string, pars []interface{}, fieldArr []string, or
 	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
+
+// GetSysAdminByIdList
+// @Description: 根据账户id列表获取账户信息列表
+// @author: Roc
+// @datetime 2024-06-05 10:49:50
+// @param adminIdList []int
+// @return items []*Admin
+// @return err error
+func GetSysAdminByIdList(adminIdList []int) (items []*Admin, err error) {
+	num := len(adminIdList)
+	if num <= 0 {
+		return
+	}
+	sql := `SELECT * FROM admin WHERE admin_id in (` + utils.GetOrmInReplace(num) + `) `
+	o := orm.NewOrm()
+	_, err = o.Raw(sql, adminIdList).QueryRows(&items)
+	return
+}

+ 69 - 15
routers/commentsRouter.go

@@ -3607,6 +3607,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: "SaveEdbRefreshStatusSingle",
+            Router: `/edb_info/single_refresh/status/save`,
+            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: "SmmEdbInfoBatchAdd",
@@ -4914,23 +4923,23 @@ func init() {
 
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
         beego.ControllerComments{
-            Method: "IcpiClassifyList",
-            Router: `/icpi/classify/list`,
+            Method: "ExportIcpiDataList",
+            Router: `/icpi/export/icpiDataList`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"],
         beego.ControllerComments{
-            Method: "ExportIcpiDataList",
-            Router: `/icpi/export/icpiDataList`,
+            Method: "IcpiClassifyList",
+            Router: `/icpi/classify/list`,
             AllowHTTPMethods: []string{"get"},
             MethodParams: param.Make(),
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceController"],
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_source:DataSourceIcpiController"],
         beego.ControllerComments{
             Method: "IcpiData",
             Router: `/icpi/index/data`,
@@ -7990,15 +7999,6 @@ func init() {
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
-        beego.ControllerComments{
-            Method: "AddDayWeekReport",
-            Router: `/addDayWeekReport`,
-            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: "CancelApprove",
@@ -8026,6 +8026,42 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "AddChapter",
+            Router: `/chapter/add`,
+            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: "EditChapterBaseInfoAndPermission",
+            Router: `/chapter/base_info/edit`,
+            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: "DelChapter",
+            Router: `/chapter/del`,
+            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: "ChapterMove",
+            Router: `/chapter/move`,
+            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: "ClassifyIdDetail",
@@ -8053,6 +8089,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: "BaseDetail",
+            Router: `/detail/base`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "Edit",
@@ -8197,6 +8242,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: "AuthorizedListReport",
+            Router: `/list/authorized`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:ReportController"],
         beego.ControllerComments{
             Method: "MarkEditStatus",

+ 20 - 12
routers/router.go

@@ -292,6 +292,12 @@ func init() {
 				&controllers.OutLinkController{},
 			),
 		),
+		web.NSNamespace("/user_login",
+			web.NSInclude(
+				&controllers.UserLoginController{},
+				&controllers.UserLoginAuthController{},
+			),
+		),
 		web.NSNamespace("/eta_trial",
 			web.NSInclude(
 				&eta_trial.EtaTrialController{},
@@ -314,21 +320,15 @@ func init() {
 				&data_stat.EdbTerminalController{},
 			),
 		),
-		web.NSNamespace("/chart_framework",
-			web.NSInclude(
-				&data_manage.ChartFrameworkController{},
-			),
-		),
 		web.NSNamespace("/smart_report",
 			web.NSInclude(
 				&smart_report.SmartReportController{},
 				&smart_report.SmartReportResourceController{},
 			),
 		),
-		web.NSNamespace("/ai",
+		web.NSNamespace("/chart_framework",
 			web.NSInclude(
-				&ai.AiController{},
-				&ai.AiFileController{},
+				&data_manage.ChartFrameworkController{},
 			),
 		),
 		web.NSNamespace("/cross_variety", //跨品种分析
@@ -345,9 +345,17 @@ func init() {
 				&report_approve.ReportApproveFlowController{},
 			),
 		),
+		web.NSNamespace("/ai",
+			web.NSInclude(
+				&ai.AiController{},
+				&ai.AiController{},
+				&ai.AiFileController{},
+			),
+		),
 		web.NSNamespace("/data_source",
 			web.NSInclude(
 				&data_source.DataSourceController{},
+				&data_source.DataSourceIcpiController{},
 			),
 		),
 		web.NSNamespace("/permission",
@@ -364,14 +372,14 @@ func init() {
 				&speech_recognition.SpeechRecognitionTagMenuController{},
 			),
 		),
-		web.NSNamespace("/message",
+		web.NSNamespace("/fe_calendar",
 			web.NSInclude(
-				&controllers.MessageController{},
+				&fe_calendar.FeCalendarMatterController{},
 			),
 		),
-		web.NSNamespace("/fe_calendar",
+		web.NSNamespace("/message",
 			web.NSInclude(
-				&fe_calendar.FeCalendarMatterController{},
+				&controllers.MessageController{},
 			),
 		),
 	)

+ 34 - 12
services/data/chart_info.go

@@ -687,6 +687,7 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 	}
 	endYear := lastDateT.Year()
 	nowYear := time.Now().Year()
+	chartLegendMaxYear := 0
 	dataMap := make(map[string]data_manage.QuarterXDateItem, 0)
 
 	quarterDataList := make([]*data_manage.QuarterData, 0)
@@ -732,6 +733,7 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 			EndDate:   endT,
 			ShowName:  showName,
 		}
+		chartLegendMaxYear = endT.Year()
 		dataMap[name] = item
 		chartLegendMap[name] = idx
 		idx++
@@ -744,7 +746,7 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 	lenYear := len(dataMap)
 	for k, v := range dataMap {
 		if i, ok := chartLegendMap[k]; ok {
-			v.ChartLegend = strconv.Itoa(endYear - lenYear + i)
+			v.ChartLegend = strconv.Itoa(chartLegendMaxYear - lenYear + i)
 		}
 		dataMap[k] = v
 	}
@@ -877,6 +879,7 @@ func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, late
 	}
 	endYear := lastDateT.Year()
 	nowYear := time.Now().Year()
+	chartLegendMaxYear := 0
 	dataMap := make(map[string]data_manage.QuarterXDateItem, 0)
 
 	quarterDataList := make([]*data_manage.QuarterData, 0)
@@ -921,6 +924,7 @@ func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, late
 			EndDate:   endT,
 			ShowName:  showName,
 		}
+		chartLegendMaxYear = endT.Year()
 		dataMap[showName] = item
 		fmt.Println("年份" + showName + "日期" + startStr + " " + endStr)
 		startTmpT = startT
@@ -935,7 +939,7 @@ func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, late
 	lenYear := len(dataMap)
 	for k, v := range dataMap {
 		if i, ok := chartLegendMap[k]; ok {
-			v.ChartLegend = strconv.Itoa(endYear - lenYear + i)
+			v.ChartLegend = strconv.Itoa(chartLegendMaxYear - lenYear + i)
 		}
 		dataMap[k] = v
 	}
@@ -1350,7 +1354,22 @@ func BatchChartInfoRefreshV2(chartInfoList []*data_manage.ChartInfo, redisKey st
 	if totalEdbInfo > 20 { // 关联指标过多的时候,异步刷新
 		isAsync = true
 		isDeleteCache = false // 不删除缓存
-		go refreshChartEdbInfo(chartInfoList, redisKey, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
+		//go refreshChartEdbInfo(chartInfoList, redisKey, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
+
+		// 加入队列刷新
+		var refreshItem EdbQueueRefreshReq
+		refreshItem.RefreshKey = redisKey
+		for _, v := range chartInfoList {
+			key := utils.HZ_CHART_LIB_DETAIL + v.UniqueCode
+			refreshItem.ItemRefreshKeys = append(refreshItem.ItemRefreshKeys, key)
+		}
+		refreshItem.BaseEdbInfoArr = newBaseEdbInfoArr
+		refreshItem.BasePredictEdbInfoArr = newBasePredictEdbInfoArr
+		refreshItem.CalculateMap = newCalculateMap
+		refreshItem.PredictCalculateMap = newPredictCalculateMap
+		refreshItem.CalculateArr = calculateArr
+		refreshItem.PredictCalculateArr = predictCalculateArr
+		go PushEdb2Refresh(refreshItem)
 	} else {
 		err = edbInfoRefreshAll(false, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
 
@@ -1395,15 +1414,15 @@ func refreshChartEdbInfo(chartInfoList []*data_manage.ChartInfo, redisKey string
 // @author: Roc
 // @datetime 2023-11-30 13:30:26
 // @param source string
-// @param reportId int
-// @param reportChapterId int
+// @param primaryId int
+// @param subId int
 // @return string
-func GetBatchChartRefreshKey(source string, reportId, reportChapterId int) string {
+func GetBatchChartRefreshKey(source string, primaryId, subId int) string {
 	if source == `` {
 		return ``
 	}
 
-	return fmt.Sprint("batch_chart_refresh:", source, ":", reportId, ":", reportChapterId)
+	return fmt.Sprint("batch_chart_refresh:", source, ":", primaryId, ":", subId)
 }
 
 // CheckBatchChartRefreshResult
@@ -1411,12 +1430,12 @@ func GetBatchChartRefreshKey(source string, reportId, reportChapterId int) strin
 // @author: Roc
 // @datetime 2023-11-30 13:30:26
 // @param source string
-// @param reportId int
-// @param reportChapterId int
+// @param primaryId int
+// @param subId int
 // @return string
-func CheckBatchChartRefreshResult(source string, reportId, reportChapterId int) (refreshResult bool) {
+func CheckBatchChartRefreshResult(source string, primaryId, subId int) (refreshResult bool) {
 	refreshResult = true
-	redisKey := GetBatchChartRefreshKey(source, reportId, reportChapterId)
+	redisKey := GetBatchChartRefreshKey(source, primaryId, subId)
 	if redisKey != `` {
 		// 如果找到了key,那么就是还在更新中
 		isOk := utils.Rc.IsExist(redisKey)
@@ -2231,7 +2250,8 @@ func AddChartInfo(req data_manage.AddChartInfoReq, sysUserId int, sysUserRealNam
 		err = errors.New("保存失败,Err:" + err.Error())
 		return
 	}
-
+	// 添加指标引用记录
+	_ = SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据
 	go EsAddOrEditChartInfo(chartInfo.ChartInfoId)
 
@@ -2583,6 +2603,8 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	resp.UniqueCode = chartItem.UniqueCode
 	resp.ChartType = req.ChartType
 
+	// todo 添加指标引用记录
+	_ = SaveChartEdbInfoRelation(edbInfoIdArr, chartItem)
 	//添加es数据
 	go EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据

+ 4 - 0
services/data/correlation/chart_info.go

@@ -913,6 +913,8 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 		return
 	}
 
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartInfoId)
 
@@ -1154,6 +1156,8 @@ func EditChartInfo(req data_manage.EditChartInfoReq, sysUser *system.Admin, lang
 	resp.UniqueCode = chartItem.UniqueCode
 	resp.ChartType = req.ChartType
 
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartItem)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据

+ 9 - 3
services/data/cross_variety/chart.go

@@ -650,6 +650,7 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 		}
 	}
 
+	edbInfoIdArr := make([]int, 0)
 	// 数据校验(品种、标签、指标)
 	{
 		// 标签m
@@ -691,6 +692,7 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 			isSendEmail = false
 			return
 		}
+		edbInfoIdArr = edbInfoIdList
 		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
 		if tmpErr != nil {
 			errMsg = "获取指标信息失败"
@@ -793,7 +795,9 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 		err = errors.New("新增相关性图表失败, Err: " + e.Error())
 		return
 	}
-
+	chartInfo.ChartInfoId = chartInfoId
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartInfoId)
 
@@ -905,7 +909,7 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string)
 		isSendEmail = false
 		return
 	}
-	
+	edbInfoIdArr := make([]int, 0)
 	// 数据校验(品种、标签、指标)
 	{
 		// 标签m
@@ -947,6 +951,7 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string)
 			isSendEmail = false
 			return
 		}
+		edbInfoIdArr = edbInfoIdList
 		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
 		if tmpErr != nil {
 			errMsg = "获取指标信息失败"
@@ -1032,7 +1037,8 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string)
 	resp.ChartInfoId = chartItem.ChartInfoId
 	resp.UniqueCode = chartItem.UniqueCode
 	//resp.ChartType = req.ChartType
-
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartItem)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据

+ 88 - 16
services/data/edb_classify.go

@@ -449,7 +449,7 @@ func EditEdbClassify(classifyId int, classifyName, lang string, sysUser *system.
 }
 
 // DeleteCheck 删除检测
-func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus int, tipsMsg string, err error, errMsg string) {
+func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus int, tipsMsg string, tableList []*data_manage.ExcelBaseInfo, err error, errMsg string) {
 	//删除分类
 	if classifyId > 0 && edbInfoId == 0 {
 		// 查找分类
@@ -557,7 +557,7 @@ func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus
 			}
 			if calculateCount > 0 {
 				deleteStatus = 4
-				tipsMsg = "当前指标已用作指标运算,不可删除"
+				tipsMsg = "当前指标已用作指标运算,不可删除"
 				return
 			}
 		}
@@ -571,7 +571,7 @@ func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus
 				return
 			}
 			if predictEdbInfoCount > 0 {
-				deleteStatus = 3
+				deleteStatus = 5
 				tipsMsg = "当前指标已用作预测指标,不可删除"
 				return
 			}
@@ -579,22 +579,66 @@ func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus
 
 		// 判断指标是否用作表格引用
 		{
-			calculateCount, tmpErr := excel.GetNoCustomAnalysisExcelEdbMappingCount(edbInfoId)
+			tableItems, tmpErr := excel.GetNoCustomAnalysisExcelEdbMapping(edbInfoId)
 			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
 				errMsg = "删除失败"
 				err = errors.New("判断指标是否用作表格引用,GetNoCustomAnalysisExcelEdbMappingCount Err:" + tmpErr.Error())
 				return
 			}
-			if calculateCount > 0 {
-				deleteStatus = 3
-				tipsMsg = "当前指标已添加到表格,不可删除"
+			//英文翻译:
+			//1、当前指标已用作画图,不可删除:The current metric is in use for charting and cannot be deleted
+			//2、当前指标已被表格引用,不可删除:The current metric is referenced by a table and cannot be deleted
+			//3、删除失败:Deletion failed
+			//4、知道了:Understood
+			if len(tableItems) > 0 {
+				deleteStatus = 6
+				tipsMsg = "当前指标已被表格引用,不可删除"
+				var excelIds []int
+				for _, tableItem := range tableItems {
+					if tableItem.ParentId > 0 {
+						excelIds = append(excelIds, tableItem.ParentId)
+					} else {
+						excelIds = append(excelIds, tableItem.ExcelInfoId)
+					}
+				}
+				tableList, tmpErr = excel.GetExcelBaseInfoByExcelInfoIdList(excelIds)
+				if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+					errMsg = "删除失败"
+					err = errors.New("判断指标是否用作表格引用,GetExcelBaseInfoByExcelInfoIdList Err:" + tmpErr.Error())
+					return
+				}
 				return
 			}
 		}
 
 		// 判断指标是否用作跨品种图表使用
 		{
-			calculateCount, tmpErr := cross_variety.GetCountByEdbInfoId(edbInfoId)
+			// todo 如果绑定的标签未画图,则允许删除绑定
+			// 查询跨品种的图表
+			tagXList, tmpErr := cross_variety.GetChartInfoCrossVarietyByXEdbInfoId(edbInfoId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "删除失败"
+				err = errors.New("判断指标是否用作跨品种图表使用,GetChartInfoCrossVarietyByXEdbInfoId Err:" + tmpErr.Error())
+				return
+			}
+			if len(tagXList) > 0 {
+				deleteStatus = 7
+				tipsMsg = "当前指标已添加到跨品种分析,不可删除"
+				return
+			}
+			tagYList, tmpErr := cross_variety.GetChartInfoCrossVarietyByYEdbInfoId(edbInfoId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "删除失败"
+				err = errors.New("判断指标是否用作跨品种图表使用,GetChartInfoCrossVarietyByYEdbInfoId Err:" + tmpErr.Error())
+				return
+			}
+
+			if len(tagYList) > 0 {
+				deleteStatus = 7
+				tipsMsg = "当前指标已添加到跨品种分析,不可删除"
+				return
+			}
+			/*calculateCount, tmpErr := cross_variety.GetCountByEdbInfoId(edbInfoId)
 			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
 				errMsg = "删除失败"
 				err = errors.New("判断指标是否用作跨品种图表使用,GetCountByEdbInfoId Err:" + tmpErr.Error())
@@ -604,14 +648,14 @@ func DeleteCheck(classifyId, edbInfoId int, sysUser *system.Admin) (deleteStatus
 				deleteStatus = 3
 				tipsMsg = "当前指标已添加到跨品种分析,不可删除"
 				return
-			}
+			}*/
 		}
 	}
 	return
 }
 
 // Delete 删除分类/指标
-func Delete(classifyId, edbInfoId int, sysUser *system.Admin, requestBody, requestUrl string) (nextItem *data_manage.EdbInfo, err error, errMsg string) {
+func Delete(classifyId, edbInfoId int, sysUser *system.Admin, requestBody, requestUrl string) (nextItem *data_manage.EdbInfo, tableList []*data_manage.ExcelBaseInfo, err error, errMsg string) {
 	//删除分类
 	if classifyId > 0 && edbInfoId == 0 {
 		// 查找分类
@@ -733,21 +777,49 @@ func Delete(classifyId, edbInfoId int, sysUser *system.Admin, requestBody, reque
 
 		// 判断指标是否用作表格引用
 		{
-			calculateCount, tmpErr := excel.GetNoCustomAnalysisExcelEdbMappingCount(edbInfoId)
+			tableItems, tmpErr := excel.GetNoCustomAnalysisExcelEdbMapping(edbInfoId)
 			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
 				errMsg = "删除失败"
 				err = errors.New("判断指标是否用作表格引用,GetNoCustomAnalysisExcelEdbMappingCount Err:" + tmpErr.Error())
 				return
 			}
-			if calculateCount > 0 {
-				errMsg = "当前指标已添加到表格,不可删除"
+			//英文翻译:
+			//1、当前指标已用作画图,不可删除:The current metric is in use for charting and cannot be deleted
+			//2、当前指标已被表格引用,不可删除:The current metric is referenced by a table and cannot be deleted
+			//3、删除失败:Deletion failed
+			//4、知道了:Understood
+			if len(tableItems) > 0 {
+				errMsg = "当前指标已被表格引用,不可删除"
 				return
 			}
 		}
-
 		// 判断指标是否用作跨品种图表使用
 		{
-			calculateCount, tmpErr := cross_variety.GetCountByEdbInfoId(edbInfoId)
+			// todo 如果绑定的标签未画图,则允许删除绑定
+			// 查询跨品种的图表
+			tagXList, tmpErr := cross_variety.GetChartInfoCrossVarietyByXEdbInfoId(edbInfoId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "删除失败"
+				err = errors.New("判断指标是否用作跨品种图表使用,GetChartInfoCrossVarietyByXEdbInfoId Err:" + tmpErr.Error())
+				return
+			}
+			if len(tagXList) > 0 {
+				errMsg = "当前指标已添加到跨品种分析,不可删除"
+				return
+			}
+			tagYList, tmpErr := cross_variety.GetChartInfoCrossVarietyByYEdbInfoId(edbInfoId)
+			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+				errMsg = "删除失败"
+				err = errors.New("判断指标是否用作跨品种图表使用,GetChartInfoCrossVarietyByYEdbInfoId Err:" + tmpErr.Error())
+				return
+			}
+
+			if len(tagYList) > 0 {
+				errMsg = "当前指标已添加到跨品种分析,不可删除"
+				return
+			}
+
+			/*calculateCount, tmpErr := cross_variety.GetCountByEdbInfoId(edbInfoId)
 			if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
 				errMsg = "删除失败"
 				err = errors.New("判断指标是否用作跨品种图表使用,GetCountByEdbInfoId Err:" + tmpErr.Error())
@@ -756,7 +828,7 @@ func Delete(classifyId, edbInfoId int, sysUser *system.Admin, requestBody, reque
 			if calculateCount > 0 {
 				errMsg = "当前指标已添加到跨品种分析,不可删除"
 				return
-			}
+			}*/
 		}
 
 		//真实删除

+ 30 - 18
services/data/edb_info.go

@@ -2619,24 +2619,36 @@ func BatchRefreshEdbByEdbIds(edbIdList []int, redisKey string, refreshKeys []str
 	if totalEdbInfo > 20 {
 		syncing = true
 
-		go func() {
-			defer func() {
-				if err != nil {
-					alarm_msg.SendAlarmMsg("BatchRefreshEdbByEdbIds, ErrMsg: "+err.Error(), 3)
-				}
-			}()
-
-			err = edbInfoRefreshAll(false, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
-
-			if redisKey != `` {
-				_ = utils.Rc.Delete(redisKey)
-			}
-			if len(refreshKeys) > 0 {
-				for _, v := range refreshKeys {
-					_ = utils.Rc.Delete(v)
-				}
-			}
-		}()
+		//go func() {
+		//	defer func() {
+		//		if err != nil {
+		//			alarm_msg.SendAlarmMsg("BatchRefreshEdbByEdbIds, ErrMsg: "+err.Error(), 3)
+		//		}
+		//	}()
+		//
+		//	err = edbInfoRefreshAll(false, newBaseEdbInfoArr, newBasePredictEdbInfoArr, newCalculateMap, newPredictCalculateMap, calculateArr, predictCalculateArr)
+		//
+		//	if redisKey != `` {
+		//		_ = utils.Rc.Delete(redisKey)
+		//	}
+		//	if len(refreshKeys) > 0 {
+		//		for _, v := range refreshKeys {
+		//			_ = utils.Rc.Delete(v)
+		//		}
+		//	}
+		//}()
+
+		// 加入队列刷新
+		var refreshItem EdbQueueRefreshReq
+		refreshItem.RefreshKey = redisKey
+		refreshItem.ItemRefreshKeys = refreshKeys
+		refreshItem.BaseEdbInfoArr = newBaseEdbInfoArr
+		refreshItem.BasePredictEdbInfoArr = newBasePredictEdbInfoArr
+		refreshItem.CalculateMap = newCalculateMap
+		refreshItem.PredictCalculateMap = newPredictCalculateMap
+		refreshItem.CalculateArr = calculateArr
+		refreshItem.PredictCalculateArr = predictCalculateArr
+		go PushEdb2Refresh(refreshItem)
 		return
 	}
 

+ 0 - 287
services/data/edb_info_calculate.go

@@ -62,293 +62,6 @@ type CalculateItems struct {
 	DataMap   map[string]float64
 }
 
-func ReplaceFormula(edbInfoIdArr []*data_manage.EdbInfo, valArr map[int]float64, formulaMap map[string]string, formulaStr string, edbInfoIdBytes []string) string {
-	// todo 处理min和max
-	funMap := GetFormulaMap()
-	for k, v := range funMap {
-		formulaStr = strings.Replace(formulaStr, k, v, -1)
-	}
-	replaceCount := 0
-	for dk, dv := range edbInfoIdArr {
-		if dk == 0 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				} else {
-					fmt.Println("valArr not found:", valArr, valOk)
-				}
-			} else {
-				fmt.Println("formulaMap not found:", dKey, dk)
-			}
-		}
-		if dk == 1 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				} else {
-					fmt.Println("valArr not found:", valArr, valOk)
-				}
-			} else {
-				fmt.Println("formulaMap not found:", dKey, dk)
-			}
-		}
-		if dk == 2 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 3 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 4 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 5 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 6 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 7 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 8 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 9 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 10 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 11 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 12 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 13 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 14 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 15 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 16 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 17 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 18 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 19 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 20 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 21 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 22 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 23 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 24 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-		if dk == 25 {
-			dKey := edbInfoIdBytes[dk]
-			if _, ok := formulaMap[dKey]; ok { //公式中存在
-				if val, valOk := valArr[dv.EdbInfoId]; valOk { //值存在
-					dvStr := fmt.Sprintf("%v", val)
-					formulaStr = strings.Replace(formulaStr, dKey, dvStr, -1)
-					replaceCount++
-				}
-			}
-		}
-	}
-	for k, v := range funMap {
-		formulaStr = strings.Replace(formulaStr, v, k, -1)
-	}
-	if replaceCount == len(formulaMap) {
-		return formulaStr
-	} else {
-		return ""
-	}
-}
-
 func GetFormulaMap() map[string]string {
 	funMap := make(map[string]string)
 	funMap["MAX"] = "[@@]"

+ 30 - 0
services/data/edb_info_record.go

@@ -0,0 +1,30 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"time"
+)
+
+func AddEditEdbInfoRcord(oldEdbInfo *data_manage.EdbInfo, newEdbInfo *data_manage.EdbInfoEditRecord) (err error) {
+	if oldEdbInfo.EdbName != newEdbInfo.EdbName || oldEdbInfo.Frequency != newEdbInfo.Frequency || oldEdbInfo.Unit != newEdbInfo.Unit {
+		ctime := time.Now()
+		edbRecord := new(data_manage.EdbInfoRecord)
+		edbRecord.EdbInfoId = oldEdbInfo.EdbInfoId
+		edbRecord.OldEdbName = oldEdbInfo.EdbName
+		edbRecord.OldFrequency = oldEdbInfo.Frequency
+		edbRecord.OldUnit = oldEdbInfo.Unit
+		edbRecord.NewEdbName = newEdbInfo.EdbName
+		edbRecord.NewFrequency = newEdbInfo.Frequency
+		edbRecord.NewUnit = newEdbInfo.Unit
+		edbRecord.OperateUserId = newEdbInfo.OperateUserId
+		edbRecord.OperateUserRealName = newEdbInfo.OperateUserRealName
+		edbRecord.CreateTime = ctime
+		edbRecord.Timestamp = ctime.Unix()
+		err = data_manage.AddEditEdbInfoRcord(edbRecord)
+		if err != nil {
+			return
+		}
+		err = data_manage.ModifyEdbInfoBaseTimeById(edbRecord.EdbInfoId, ctime)
+	}
+	return
+}

+ 242 - 0
services/data/edb_info_relation.go

@@ -0,0 +1,242 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/services/sandbox"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+// SaveChartEdbInfoRelation 添加/编辑图表指标引用关联记录
+func SaveChartEdbInfoRelation(edbInfoIds []int, chartInfo *data_manage.ChartInfo) (err error) {
+	//更新指标刷新状态为启用
+	err = saveEdbInfoRelation(edbInfoIds, chartInfo.ChartInfoId, utils.EDB_RELATION_CHART, chartInfo.Source)
+	return
+}
+
+// saveEdbInfoRelation 添加/编辑图表指标引用关联记录
+func saveEdbInfoRelation(edbInfoIds []int, objectId, objectType, objectSubType int) (err error) {
+	// 实现添加引用记录的逻辑
+	if len(edbInfoIds) == 0 {
+		return
+	}
+	defer func() {
+		if err != nil {
+			tips := "实现添加引用记录的逻辑-添加/编辑图表指标引用关联记录失败, ErrMsg:\n" + err.Error()
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+	}()
+	refreshIds := make([]int, 0)
+	indexCodeList := make([]string, 0)
+	// 查询指标信息
+	edbInfoList, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		err = fmt.Errorf("查询指标信息失败,%s", e.Error())
+		return
+	}
+	// 只统计钢联化工和wind来源的指标
+	for _, edbInfo := range edbInfoList {
+		if edbInfo.Source != utils.DATA_SOURCE_WIND && edbInfo.Source != utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+			continue
+		}
+		refreshIds = append(refreshIds, edbInfo.EdbInfoId)
+		if edbInfo.Source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+			indexCodeList = append(indexCodeList, edbInfo.EdbCode)
+		}
+	}
+	// 循转组装引用
+	// 查询已有的引用关系
+	existList, e := data_manage.GetEdbInfoRelationByReferObjectId(objectId, objectType)
+	if e != nil {
+		err = fmt.Errorf("查询已有的引用关系失败,%s", e.Error())
+		return
+	}
+	deleteMap := make(map[int]bool)
+	relationMap := make(map[int]bool)
+	for _, exist := range existList {
+		deleteMap[exist.EdbInfoId] = true
+		relationMap[exist.EdbInfoId] = true
+	}
+	// 新增不存在的引用关系
+	// 删除不再需要的引用关系
+	nowTime := time.Now()
+	addList := make([]*data_manage.EdbInfoRelation, 0)
+	deleteRelationIds := make([]int, 0)
+	for _, edbInfo := range edbInfoList {
+		if edbInfo.Source != utils.DATA_SOURCE_WIND && edbInfo.Source != utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+			continue
+		}
+		if _, ok := relationMap[edbInfo.EdbInfoId]; ok {
+			delete(deleteMap, edbInfo.EdbInfoId)
+		} else {
+			tmp := &data_manage.EdbInfoRelation{
+				ReferObjectId:      objectId,
+				ReferObjectType:    objectType,
+				ReferObjectSubType: objectSubType,
+				EdbInfoId:          edbInfo.EdbInfoId,
+				EdbName:            edbInfo.EdbName,
+				Source:             edbInfo.Source,
+				EdbCode:            edbInfo.EdbCode,
+				CreateTime:         nowTime,
+				ModifyTime:         nowTime,
+			}
+			addList = append(addList, tmp)
+		}
+	}
+
+	// 删除不再需要的引用关系
+	for deleteId, _ := range deleteMap {
+		deleteRelationIds = append(deleteRelationIds, deleteId)
+	}
+	//更新指标刷新状态为启用
+	err = data_manage.AddOrUpdateEdbInfoRelation(addList, deleteRelationIds, refreshIds, indexCodeList)
+	if err != nil {
+		err = fmt.Errorf("删除不再需要的引用关系失败,%s", err.Error())
+		return
+	}
+	return
+}
+
+// SaveSandBoxEdbInfoRelation 添加/编辑 eta逻辑图指标引用
+func SaveSandBoxEdbInfoRelation(sandBoxId int, sandBoxContent string) (err error) {
+	edbInfoIds, err := sandbox.GetSandBoxEdbIdsByContent(sandBoxContent)
+	if err != nil {
+		return
+	}
+	if len(edbInfoIds) == 0 {
+		return
+	}
+	//更新指标刷新状态为启用
+	err = saveEdbInfoRelation(edbInfoIds, sandBoxId, utils.EDB_RELATION_SANDBOX, 0)
+	return
+}
+
+// SaveCalendarEdbInfoRelation 添加/编辑 事件日历指标引用
+func SaveCalendarEdbInfoRelation(chartPermissionId int, matterDate string, editMatters, removeMatters []*fe_calendar.FeCalendarMatter) (err error) {
+
+	//整理相关的事件ID
+	matterIds := make([]int, 0)
+	updateMatterMap := make(map[int]*fe_calendar.FeCalendarMatter)
+	deleteMatterMap := make(map[int]struct{})
+	for _, matter := range removeMatters {
+		deleteMatterMap[matter.FeCalendarMatterId] = struct{}{}
+		matterIds = append(matterIds, matter.FeCalendarMatterId)
+	}
+	for _, matter := range editMatters {
+		updateMatterMap[matter.FeCalendarMatterId] = matter
+		matterIds = append(matterIds, matter.FeCalendarMatterId)
+	}
+
+	//删除ID,先删除
+	deleteRelationIds := make([]int, 0)
+	if len(matterIds) > 0 {
+		relationList, e := data_manage.GetEdbInfoRelationByReferObjectIds(matterIds, utils.EDB_RELATION_CALENDAR)
+		if e != nil {
+			err = fmt.Errorf("查询事件日历指标引用失败,%s", e.Error())
+			return
+		}
+		for _, relation := range relationList {
+			if _, ok := deleteMatterMap[relation.ReferObjectId]; ok {
+				deleteRelationIds = append(deleteRelationIds, relation.EdbInfoRelationId)
+			}
+			if newMatter, ok := updateMatterMap[relation.ReferObjectId]; ok {
+				if relation.EdbInfoId != newMatter.EdbInfoId {
+					deleteRelationIds = append(deleteRelationIds, relation.EdbInfoRelationId)
+				}
+			}
+		}
+	}
+	if len(deleteRelationIds) > 0 {
+		err = data_manage.DeleteEdbRelationByObjectIds(deleteRelationIds, utils.EDB_RELATION_CALENDAR)
+		if err != nil {
+			err = fmt.Errorf("删除事件日历指标引用失败,%s", err.Error())
+			return
+		}
+		deleteRelationIds = make([]int, 0)
+	}
+
+	// 获取已有事项
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	cond := fmt.Sprintf(` AND %s = ? AND %s = ?`, fe_calendar.FeCalendarMatterCols.ChartPermissionId, fe_calendar.FeCalendarMatterCols.MatterDate)
+	pars := make([]interface{}, 0)
+	pars = append(pars, chartPermissionId, matterDate)
+	order := fmt.Sprintf(`%s ASC`, fe_calendar.FeCalendarMatterCols.Sort)
+	matters, e := matterOb.GetItemsByCondition(cond, pars, []string{}, order)
+	if e != nil {
+		err = fmt.Errorf("查询事件日历事项失败,%s", e.Error())
+		return
+	}
+	// 循环查询matters
+	edbInfoIds := make([]int, 0)
+	refreshIds := make([]int, 0)
+	indexCodeList := make([]string, 0)
+
+	newMatterIds := make([]int, 0)
+	for _, matter := range matters {
+		newMatterIds = append(newMatterIds, matter.FeCalendarMatterId)
+		edbInfoIds = append(edbInfoIds, matter.EdbInfoId)
+	}
+
+	// 查询指标信息
+	edbInfoList, e := data_manage.GetEdbInfoByIdList(edbInfoIds)
+	if e != nil {
+		err = fmt.Errorf("查询指标信息失败,%s", e.Error())
+		return
+	}
+	// 只统计钢联化工和wind来源的指标
+	addEdbInfoIdMap := make(map[int]*data_manage.EdbInfo)
+	for _, edbInfo := range edbInfoList {
+		if edbInfo.Source != utils.DATA_SOURCE_WIND && edbInfo.Source != utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+			continue
+		}
+		refreshIds = append(refreshIds, edbInfo.EdbInfoId)
+		addEdbInfoIdMap[edbInfo.EdbInfoId] = edbInfo
+		if edbInfo.Source == utils.DATA_SOURCE_MYSTEEL_CHEMICAL {
+			indexCodeList = append(indexCodeList, edbInfo.EdbCode)
+		}
+	}
+	relationMap := make(map[int]struct{})
+	if len(newMatterIds) > 0 {
+		//查询已有的matters
+		relationList, e := data_manage.GetEdbInfoRelationByReferObjectIds(newMatterIds, utils.EDB_RELATION_CALENDAR)
+		if e != nil {
+			err = fmt.Errorf("查询事件日历指标引用失败,%s", e.Error())
+			return
+		}
+		for _, relation := range relationList {
+			relationMap[relation.ReferObjectId] = struct{}{}
+		}
+	}
+	addList := make([]*data_manage.EdbInfoRelation, 0)
+	nowTime := time.Now()
+	for _, matter := range matters {
+		_, ok1 := relationMap[matter.FeCalendarMatterId]
+		edbInfo, ok2 := addEdbInfoIdMap[matter.EdbInfoId]
+		if !ok1 && ok2 {
+			tmp := &data_manage.EdbInfoRelation{
+				ReferObjectId:      matter.FeCalendarMatterId,
+				ReferObjectType:    utils.EDB_RELATION_CALENDAR,
+				ReferObjectSubType: 0,
+				EdbInfoId:          edbInfo.EdbInfoId,
+				EdbName:            edbInfo.EdbName,
+				Source:             edbInfo.Source,
+				EdbCode:            edbInfo.EdbCode,
+				CreateTime:         nowTime,
+				ModifyTime:         nowTime,
+			}
+			addList = append(addList, tmp)
+		}
+	}
+
+	//更新指标刷新状态为启用
+	err = data_manage.AddOrUpdateEdbInfoRelation(addList, deleteRelationIds, refreshIds, indexCodeList)
+	if err != nil {
+		err = fmt.Errorf("删除不再需要的引用关系失败,%s", err.Error())
+		return
+	}
+	return
+}

+ 105 - 0
services/data/edb_refresh.go

@@ -0,0 +1,105 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/utils"
+	"fmt"
+	"sync"
+)
+
+var (
+	EdbRefreshLock     sync.Map                // 指标刷新锁, 避免同时间重复key的刷新
+	EdbRefreshHandling chan EdbQueueRefreshReq // 排队刷新的20+指标的图表/表格
+	EdbRefreshWorker   chan struct{}           // 同时允许N组刷新
+)
+
+func init() {
+	EdbRefreshHandling = make(chan EdbQueueRefreshReq, 50) // N为最大排队等候的goroutine数
+	EdbRefreshWorker = make(chan struct{}, 5)              // 控制刷新速率修改此N值
+}
+
+type EdbQueueRefreshReq struct {
+	RefreshKey            string   `description:"刷新请求的缓存key"`
+	ItemRefreshKeys       []string `description:"图表/表格刷新后要删除的缓存key"`
+	BaseEdbInfoArr        []*data_manage.EdbInfo
+	BasePredictEdbInfoArr []*data_manage.EdbInfo
+	CalculateMap          map[int]*data_manage.EdbInfo
+	PredictCalculateMap   map[int]*data_manage.EdbInfo
+	CalculateArr          []int
+	PredictCalculateArr   []int
+}
+
+// PushEdb2Refresh 写入指标刷新队列
+func PushEdb2Refresh(item EdbQueueRefreshReq) {
+	refreshKey := item.RefreshKey
+	if refreshKey == "" {
+		return
+	}
+
+	// 检查是否已在队列中
+	_, ok := EdbRefreshLock.Load(refreshKey)
+	if ok {
+		return
+	}
+
+	// 追加至刷新队列
+	EdbRefreshHandling <- item
+
+	EdbRefreshLock.Store(refreshKey, true)
+}
+
+// HandleEdbRefreshQueue 排队刷新指标
+func HandleEdbRefreshQueue() {
+	defer func() {
+		if err := recover(); err != nil {
+			tips := fmt.Sprintf("[HandleEdbRefreshQueue] panic: %v", err)
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+		}
+	}()
+	fmt.Println("HandleEdbRefreshQueue start")
+
+	for {
+		select {
+		case item, ok := <-EdbRefreshHandling:
+			if !ok {
+				return
+			}
+			go EdbRefreshTask(item)
+		}
+	}
+}
+
+// EdbRefreshTask 指标刷新任务
+func EdbRefreshTask(item EdbQueueRefreshReq) {
+	var err error
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("[EdbRefreshTask] ErrMsg: %s", err.Error())
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 3)
+		}
+		<-EdbRefreshWorker
+	}()
+	EdbRefreshWorker <- struct{}{}
+
+	fmt.Printf("EdbRefreshTask开始刷新: %s\n", item.RefreshKey)
+	// 刷新指标
+	e := edbInfoRefreshAll(false, item.BaseEdbInfoArr, item.BasePredictEdbInfoArr, item.CalculateMap, item.PredictCalculateMap, item.CalculateArr, item.PredictCalculateArr)
+	if e != nil {
+		err = fmt.Errorf("edbInfoRefreshAll err: %s", e.Error())
+	}
+
+	// 清除缓存
+	_ = utils.Rc.Delete(item.RefreshKey)
+	if len(item.ItemRefreshKeys) > 0 {
+		for _, v := range item.ItemRefreshKeys {
+			_ = utils.Rc.Delete(v)
+		}
+	}
+
+	// 解除锁
+	EdbRefreshLock.Delete(item.RefreshKey)
+	fmt.Printf("EdbRefreshTask结束刷新: %s\n", item.RefreshKey)
+}

+ 4 - 4
services/data/excel/balance_table.go

@@ -470,7 +470,6 @@ func TransferBalanceExcelContentToStatic(excelDetail *excelModel.ExcelInfo, lang
 		return
 	}
 	cellRelationConf = string(cellRelationConfByte)
-
 	newData, tmpErr, tmpErrMsg := GetMixedTableCellData(mixedTableReq, lang)
 	if tmpErr != nil {
 		err = errors.New(tmpErrMsg + "获取最新的数据失败 ,Err:" + tmpErr.Error())
@@ -534,11 +533,12 @@ func SyncBalanceEdbData(excelInfo *excelModel.ExcelInfo, balanceTableData [][]re
 
 	for _, mapping := range tmpMappingList {
 		excelEdbMap[mapping.ExcelChartEdbId] = mapping
-		err, _ = GetBalanceExcelEdbData(mapping, newExcelDataMap, excelDataMap, excelAllRows, excelAllCols)
-		if err != nil {
+		_, _ = GetBalanceExcelEdbData(mapping, newExcelDataMap, excelDataMap, excelAllRows, excelAllCols)
+		// 如果未正常获取到数据,则该条数据不展示
+		/*if err != nil {
 			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
 			return
-		}
+		}*/
 	}
 	// 批量更新图表数据
 	err = excelModel.BatchUpdateChartEdbData(excelInfo.ExcelInfoId, excelEdbMap, excelDataMap)

+ 2 - 2
services/data/excel/excel_info.go

@@ -520,10 +520,10 @@ func GetEdbIdsFromExcelCodes(excelCodes []string, sysUserId int, lang string) (e
 }
 
 // GetExcelEdbBatchRefreshKey 获取批量刷新表格指标缓存key
-func GetExcelEdbBatchRefreshKey(source string, reportId, chapterId int) string {
+func GetExcelEdbBatchRefreshKey(source string, primaryId, subId int) string {
 	if source == `` {
 		return ``
 	}
 
-	return fmt.Sprint("batch_refresh_excel_edb:", source, ":", reportId, ":", chapterId)
+	return fmt.Sprint("batch_refresh_excel_edb:", source, ":", primaryId, ":", subId)
 }

+ 5 - 0
services/data/line_equation/chart_info.go

@@ -547,6 +547,8 @@ func BatchAddChartInfo(batchAddChartReq []request.AddChart, lineChartInfoConfig
 
 	// 更改es
 	for _, v := range batchAddChartList {
+		// 添加指标引用记录
+		_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, v.ChartInfo)
 		//添加es数据
 		go data.EsAddOrEditChartInfo(v.ChartInfo.ChartInfoId)
 	}
@@ -787,6 +789,9 @@ func BatchSaveChartInfo(multipleGraphConfigId int, batchAddChartReq []request.Ad
 
 	// 更改es
 	for _, v := range batchAddChartList {
+		// 添加指标引用记录
+		_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, v.ChartInfo)
+
 		//添加es数据
 		go data.EsAddOrEditChartInfo(v.ChartInfo.ChartInfoId)
 	}

+ 5 - 1
services/data/line_feature/chart_info.go

@@ -527,7 +527,8 @@ func AddChartInfo(req data_manage.AddChartInfoReq, edbInfoMapping *data_manage.C
 		err = errors.New("新增相关性图表失败, Err: " + e.Error())
 		return
 	}
-
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartInfoId)
 
@@ -654,6 +655,9 @@ func EditChartInfo(req data_manage.EditChartInfoReq, edbInfoMapping *data_manage
 	resp.UniqueCode = chartItem.UniqueCode
 	resp.ChartType = req.ChartType
 
+	// 添加指标引用记录
+	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartItem)
+
 	//添加es数据
 	go data.EsAddOrEditChartInfo(chartItem.ChartInfoId)
 	//修改my eta es数据

+ 254 - 0
services/edb_info_replace.go

@@ -0,0 +1,254 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_api/models/data_manage"
+	excelModel "eta/eta_api/models/data_manage/excel"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/services/alarm_msg"
+	"eta/eta_api/services/sandbox"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+// 全局的指标替换
+func DealReplaceEdbCache() {
+	var err error
+	for {
+		utils.Rc.Brpop(utils.CACHE_KEY_REPLACE_EDB, func(b []byte) {
+			defer func() {
+				if err != nil {
+					utils.FileLog.Info("DealReplaceEdbCache err:" + err.Error())
+					go alarm_msg.SendAlarmMsg("替换表格中的指标失败提醒,errmsg:"+err.Error(), 3)
+				}
+			}()
+			record := new(data_manage.ReplaceEdbInfoItem)
+			if err = json.Unmarshal(b, &record); err != nil {
+				fmt.Println("json unmarshal wrong!")
+				return
+			}
+			oldEdbInfo := record.OldEdbInfo
+			newEdbInfo := record.NewEdbInfo
+			deleteCache := true
+			setNxKey := fmt.Sprintf("EDB_INFO_REPLACE:%d-%d", oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
+			defer func() {
+				if deleteCache {
+					utils.Rc.Delete(setNxKey)
+				}
+			}()
+			if !utils.Rc.SetNX(setNxKey, 1, 30*time.Minute) {
+				deleteCache = false
+				err = fmt.Errorf("替换表格中的指标失败旧指标:%d为新指标%d:正在处理中", oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
+				return
+			}
+
+			// 替换相关性图表配置
+			_, err = data_manage.ReplaceMultipleGraphConfigChartEdb(oldEdbInfo, newEdbInfo)
+			if err != nil {
+				err = fmt.Errorf("替换相关性图表配置失败,errmsg:%s", err.Error())
+				return
+			}
+			// 替换拟合方程指标
+			_, err = data_manage.ReplaceEdbInfoInLineEquationMultipleGraphConfig(oldEdbInfo, newEdbInfo)
+			if err != nil {
+				err = fmt.Errorf("替换拟合方程指标失败,errmsg:%s", err.Error())
+				return
+			}
+
+			// 替换表格中的指标
+			err = ReplaceEdbInExcel(oldEdbInfo, newEdbInfo)
+			if err != nil {
+				err = fmt.Errorf("替换表格中的指标失败,errmsg:%s", err.Error())
+				return
+			}
+
+			//替换逻辑图中的指标
+			err = sandbox.ReplaceEdbInSandbox(oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId)
+			if err != nil {
+				err = fmt.Errorf("替换逻辑图中的指标失败,errmsg:%s", err.Error())
+				return
+			}
+		})
+	}
+}
+
+// ReplaceEdbInExcel 替换表格中的指标
+func ReplaceEdbInExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo) (err error) {
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("替换表格中的指标失败提醒,errmsg:"+err.Error(), 3)
+		}
+	}()
+	//查询和指标相关的 表格
+	mappingList, err := excelModel.GetExcelEdbMappingByEdbInfoId(oldEdbInfo.EdbInfoId)
+	if err != nil {
+		err = fmt.Errorf("查询和指标相关的表格失败,错误:%s", err.Error())
+		return
+	}
+	updateList := make([]*excelModel.ExcelInfo, 0)
+	// 循环列表,根据表格类型单独处理
+	for _, excelMapping := range mappingList {
+		//查询和指标相关的混合表格
+		excelInfo, tmpErr := excelModel.GetExcelInfoById(excelMapping.ExcelInfoId)
+		if tmpErr != nil {
+			err = fmt.Errorf("查询和指标相关的混合表格失败,错误:%s", tmpErr.Error())
+			return
+		}
+		// 清除缓存
+		key := utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + excelInfo.UniqueCode
+		if utils.Re == nil {
+			_ = utils.Rc.Delete(key)
+		}
+		// 根据表格类型,调用不同的处理函数
+		switch excelMapping.Source {
+		case utils.TIME_TABLE: // 时间序列表格
+			// 替换余额表格中的指标
+			newExcelInfo, e := replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo, excelInfo)
+			if e != nil {
+				err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error())
+				return
+			}
+			updateList = append(updateList, newExcelInfo)
+		case utils.MIXED_TABLE, utils.BALANCE_TABLE:
+			// 替换余额表格中的指标
+			newExcelInfo, e := replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo, excelInfo)
+			if e != nil {
+				err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error())
+				return
+			}
+			updateList = append(updateList, newExcelInfo)
+		default:
+			// 其他表格类型的处理逻辑
+		}
+	}
+
+	err = excelModel.ReplaceEdbInExcel(oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, updateList)
+	if err != nil {
+		err = fmt.Errorf("替换表格中的指标失败,错误:%s", err.Error())
+		return
+	}
+
+	//todo 是否需要刷新表格中的指标数据
+	return
+}
+
+func replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excelModel.ExcelInfo) (newExcelInfo *excelModel.ExcelInfo, err error) {
+	newExcelInfo = excelInfo
+	var mixedTableReq request.MixedTableReq
+	err = json.Unmarshal([]byte(excelInfo.Content), &mixedTableReq)
+	if err != nil {
+		err = fmt.Errorf("表格json转结构体失败,Err:" + err.Error())
+		return
+	}
+	// 处理data
+	configList := mixedTableReq.Data
+	for ck, rowList := range configList {
+		for rk, cell := range rowList {
+			switch cell.DataType {
+			case request.EdbDT: // 指标信息
+				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
+					//更换成新指标ID
+					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
+				}
+			case request.InsertDataDT, request.PopInsertDataDT: // 插值、弹框插值
+				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
+					//更换成新指标ID
+					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
+				}
+			case request.InsertEdbCalculateDataDT: // 插入指标计算公式生成的值
+				var config request.CalculateConf
+				err = json.Unmarshal([]byte(cell.Value), &config)
+				if err != nil {
+					return
+				}
+				if cell.EdbInfoId == oldEdbInfo.EdbInfoId {
+					//更换成新指标ID
+					configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId
+				}
+				if config.EdbInfoId == oldEdbInfo.EdbInfoId {
+					config.EdbInfoId = newEdbInfo.EdbInfoId
+					var configStr []byte
+					configStr, err = json.Marshal(config)
+					if err != nil {
+						return
+					}
+					configList[ck][rk].Value = string(configStr)
+				}
+
+			case request.DateDT: // 日期类型
+				// 指标日期类型的单元格需要额外将指标id取出来
+				if cell.DataTimeType == request.EdbDateDT {
+					var config request.EdbDateConf
+					err = json.Unmarshal([]byte(cell.Value), &config)
+					if err != nil {
+						return
+					}
+					if config.EdbInfoId == oldEdbInfo.EdbInfoId {
+						config.EdbInfoId = newEdbInfo.EdbInfoId
+						var configStr []byte
+						configStr, err = json.Marshal(config)
+						if err != nil {
+							return
+						}
+						configList[ck][rk].Value = string(configStr)
+					}
+				}
+			}
+		}
+	}
+
+	mixedTableReq.Data = configList
+	var newContentByte []byte
+	newContentByte, err = json.Marshal(mixedTableReq)
+	if err != nil {
+		return
+	}
+	// 生成的新内容替换原先的旧内容
+	excelInfo.Content = string(newContentByte)
+	newExcelInfo = excelInfo
+	return
+}
+
+func replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excelModel.ExcelInfo) (newExcelInfo *excelModel.ExcelInfo, err error) {
+	newExcelInfo = excelInfo
+
+	var tableDataConfig request.TimeTableDataConfig
+	err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig)
+	if err != nil {
+		err = errors.New("表格json转结构体失败,Err:" + err.Error())
+		return
+	}
+	if len(tableDataConfig.EdbInfoIdList) <= 0 {
+		return
+	}
+	// 实际期数没有的情况下,直接返回吧
+	if tableDataConfig.Num <= 0 {
+		return
+	}
+
+	// 先处理edbInfoList
+	for k, id := range tableDataConfig.EdbInfoIdList {
+		if id == oldEdbInfo.EdbInfoId {
+			tableDataConfig.EdbInfoIdList[k] = newEdbInfo.EdbInfoId
+		}
+	}
+
+	// 先处理tableEdbInfoList
+	for k, tableEdbInfo := range tableDataConfig.TableEdbInfoList {
+		if tableEdbInfo.EdbInfoId == oldEdbInfo.EdbInfoId {
+			tableDataConfig.TableEdbInfoList[k].EdbInfoId = newEdbInfo.EdbInfoId
+		}
+	}
+
+	var newContentByte []byte
+	newContentByte, err = json.Marshal(tableDataConfig)
+	if err != nil {
+		return
+	}
+	// 生成的新内容替换原先的旧内容
+	excelInfo.Content = string(newContentByte)
+	newExcelInfo = excelInfo
+	return
+}

+ 1 - 0
services/elastic.go

@@ -109,6 +109,7 @@ func EsAddOrEditReport(indexName, docId string, item *models.ElasticReportDetail
 			"ClassifyNameSecond": item.ClassifyNameSecond,
 			"Categories":         item.Categories,
 			"StageStr":           item.StageStr,
+			"BodyMd5":            utils.MD5(item.BodyContent), // 对内容进行Md5加密,keywords类型,处理分组查询
 		}).Do(context.Background())
 		if err != nil {
 			return err

+ 31 - 35
services/excel/lucky_sheet.go

@@ -630,24 +630,22 @@ func handleTableDataList(tableDataList [][]LuckySheetDataValue, luckySheetDataCo
 		flag = false
 		//尾部
 		deleteBottomRowIndexList := make([]int, 0)
-		// 数据要大于1行才会处理
-		if len(tableDataList) > 1 {
-			for rowIndex := lenRow - 1; rowIndex >= 0; rowIndex-- {
-				isDelete := true
-				for _, v := range tableDataList[rowIndex] {
-					if v.Monitor != `` {
-						isDelete = false
-						flag = true
-						break
-					}
-				}
-				if flag {
+		// 数据第1行不处理
+		for rowIndex := lenRow - 1; rowIndex > removeTopRow; rowIndex-- {
+			isDelete := true
+			for _, v := range tableDataList[rowIndex] {
+				if v.Monitor != `` {
+					isDelete = false
+					flag = true
 					break
 				}
-				if isDelete {
-					deleteBottomRowIndexList = append(deleteBottomRowIndexList, rowIndex)
-					removeBottomRow++
-				}
+			}
+			if flag {
+				break
+			}
+			if isDelete {
+				deleteBottomRowIndexList = append(deleteBottomRowIndexList, rowIndex)
+				removeBottomRow++
 			}
 		}
 
@@ -699,28 +697,26 @@ func handleTableDataList(tableDataList [][]LuckySheetDataValue, luckySheetDataCo
 		flag = false
 		//右边
 		deleteTailColumnIndexList := make([]int, 0)
-		// 数据要大于1列才会处理
-		if lenColumn > 1 {
-			for columnIndex := lenColumn - 1; columnIndex >= 0; columnIndex-- {
-				isDelete := true
-				for _, v := range tableDataList {
-					//如果一列都没有,说明是上面几行是空行,没有数据
-					if len(v) <= 0 {
-						continue
-					}
-					if v[columnIndex].Monitor != `` || (v[columnIndex].MergeCell.Column != columnIndex && v[columnIndex].MergeCell.Column != 0) {
-						isDelete = false
-						flag = true
-						break
-					}
+		// 数据第1列不处理
+		for columnIndex := lenColumn - 1; columnIndex > removeLeftColumn; columnIndex-- {
+			isDelete := true
+			for _, v := range tableDataList {
+				//如果一列都没有,说明是上面几行是空行,没有数据
+				if len(v) <= 0 {
+					continue
 				}
-				if flag {
+				if v[columnIndex].Monitor != `` || (v[columnIndex].MergeCell.Column != columnIndex && v[columnIndex].MergeCell.Column != 0) {
+					isDelete = false
+					flag = true
 					break
 				}
-				if isDelete {
-					deleteTailColumnIndexList = append(deleteTailColumnIndexList, columnIndex)
-					removeRightColumn++
-				}
+			}
+			if flag {
+				break
+			}
+			if isDelete {
+				deleteTailColumnIndexList = append(deleteTailColumnIndexList, columnIndex)
+				removeRightColumn++
 			}
 		}
 

+ 52 - 10
services/ppt.go

@@ -41,7 +41,7 @@ type PPTContentElements struct {
 }
 
 // SavePPTReport 保存PPT报告
-func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
+func SavePPTReport(pptId, classifyId int, title string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
 	defer func() {
 		if err != nil {
 			utils.FileLog.Info("%s", err.Error())
@@ -68,7 +68,7 @@ func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.
 	}
 
 	// 2023-02-21 PPT可多次转为报告, 不做关联
-	if classifyIdSecond == 0 {
+	if classifyId == 0 {
 		errMsg = "请选择报告类型"
 		err = errors.New("请选择报告类型")
 		return
@@ -90,17 +90,48 @@ func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.
 		classifyMap[v.Id] = v
 	}
 	classifyIdFirst := 0
+	classifyIdSecond := 0
+	classifyIdThird := 0
 	classifyNameFirst := ""
 	classifyNameSecond := ""
-	secondClassify := classifyMap[classifyIdSecond]
-	if secondClassify != nil {
-		classifyNameSecond = secondClassify.ClassifyName
-		firstClassify := classifyMap[secondClassify.ParentId]
-		if firstClassify != nil {
-			classifyIdFirst = firstClassify.Id
-			classifyNameFirst = firstClassify.ClassifyName
-		}
+	classifyNameThird := ""
+
+	// 最小单元分类,第二级别的分类 ,最大的分类
+	var baseClassify, twoClassify, threeClassify *models.Classify
+
+	var hasTwo, hasThird bool
+	baseClassify, ok := classifyMap[classifyId]
+	if !ok {
+		errMsg = "分类异常"
+		err = errors.New("获取分类失败 ")
+		return
+	}
+	twoClassify, hasTwo = classifyMap[baseClassify.ParentId]
+	if ok {
+		threeClassify, hasThird = classifyMap[twoClassify.ParentId]
+	}
+
+	if hasThird { // 如果确实是有三级分类
+		classifyIdFirst = threeClassify.Id
+		classifyNameFirst = threeClassify.ClassifyName
+
+		classifyIdSecond = twoClassify.Id
+		classifyNameSecond = twoClassify.ClassifyName
+
+		classifyIdThird = baseClassify.Id
+		classifyNameThird = baseClassify.ClassifyName
+	} else if hasTwo {
+		classifyIdFirst = twoClassify.Id
+		classifyNameFirst = twoClassify.ClassifyName
+
+		classifyIdSecond = baseClassify.Id
+		classifyNameSecond = baseClassify.ClassifyName
+
+	} else {
+		classifyIdFirst = baseClassify.Id
+		classifyNameFirst = baseClassify.ClassifyName
 	}
+
 	// 新增报告
 	nowTime := time.Now().Local()
 	reportReq := &models.AddReq{
@@ -109,6 +140,8 @@ func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.
 		ClassifyNameFirst:  classifyNameFirst,
 		ClassifyIdSecond:   classifyIdSecond,
 		ClassifyNameSecond: classifyNameSecond,
+		ClassifyIdThird:    classifyIdThird,
+		ClassifyNameThird:  classifyNameThird,
 		Title:              title,
 		Abstract:           "",
 		Author:             "FICC团队",
@@ -117,7 +150,16 @@ func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.
 		Content:            htm,
 		CreateTime:         nowTime.Format(utils.FormatDateTime),
 		ReportVersion:      2,
+		CollaborateType:    1, // 协作方式,1:个人,2:多人协作。默认:1
+		ReportLayout:       1, // 报告布局,1:常规布局,2:智能布局。默认:1
+		IsPublicPublish:    2, // 是否公开发布,1:是,2:否
+	}
+
+	// 如果PPT是公开的,则报告也公开发布
+	if item.IsShare == 1 {
+		reportReq.IsPublicPublish = 1
 	}
+
 	newReportId, newCode, _, e := CreateNewReport(*reportReq, adminInfo)
 	if e != nil {
 		errMsg = "转换失败"

+ 47 - 196
services/report.go

@@ -11,7 +11,6 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/PuerkitoBio/goquery"
-	"github.com/rdlucklib/rdluck_tools/http"
 	"html"
 	"os"
 	"regexp"
@@ -45,143 +44,6 @@ func GetReportContentSub(content string) (contentSub string, err error) {
 	return
 }
 
-type ZgParam struct {
-}
-
-// 找钢网
-func ZhaoGangSend(report *models.ReportDetail) (err error) {
-	defer func() {
-		if err != nil {
-			go alarm_msg.SendAlarmMsg("发送报告至找刚网失败,Err"+err.Error(), 3)
-			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送报告至找刚网失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
-		}
-	}()
-	reportIdStr := strconv.Itoa(report.Id)
-	articleId := utils.MD5(reportIdStr)
-
-	var reportType int
-	if report.ClassifyNameSecond == "知白守黑日评" {
-		reportType = 1
-	} else {
-		reportType = 2
-	}
-	contentHtml := html.UnescapeString(report.Content)
-
-	doc, err := goquery.NewDocumentFromReader(strings.NewReader(contentHtml))
-	if err != nil {
-		fmt.Println("Create Doc Err:" + err.Error())
-		err = errors.New("Create Doc Err:" + err.Error())
-		return
-	}
-	doc.Find("p").Each(func(i int, p *goquery.Selection) {
-		phtml, err := p.Html()
-		if err != nil {
-			fmt.Println("Err:" + err.Error())
-			return
-		}
-		if phtml == "<br/>" {
-			if i == 0 {
-				p.Remove()
-			} else {
-				p.ReplaceWithHtml("<br/>")
-			}
-		} else {
-			p.SetAttr("style", "line-height:30px")
-		}
-	})
-	doc.Find("img").Each(func(i int, img *goquery.Selection) {
-		img.SetAttr("style", "width:100%;")
-	})
-	contentHtml, _ = doc.Find("body").Html()
-
-	createDate, _ := time.Parse(utils.FormatDateTime, report.CreateTime)
-	createDay := createDate.Format("0102")
-	title := "【第 " + strconv.Itoa(report.Stage) + "期|FICC" + "】 " + report.Title + "(" + createDay + ")"
-	contentSummary := report.Abstract
-
-	postUrl := `http://appserver.index.zhaogang.com/double.index.appserver.service/api/v1/wechat/article/hongze/push`
-	signStr := "zhaogang_data_vip" + "articleId" + articleId + "type" + strconv.Itoa(reportType) + "title" + title + "contentSummary" + contentSummary + "zhaogang_data_vip"
-	fmt.Println("signStr:", signStr)
-	sign := utils.MD5(signStr)
-	disclaimers := `<p>1、本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。</p >         <p>2、本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。</p >         <p>3、报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。</p >         <p>4、在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。</p >`
-	param := make(map[string]interface{})
-	dataMap := make(map[string]interface{})
-	contentMap := make(map[string]interface{})
-
-	dataMap["articleId"] = articleId
-	dataMap["type"] = reportType
-	dataMap["title"] = title
-	dataMap["contentSummary"] = contentSummary
-
-	contentMap["contentHtml"] = contentHtml
-	contentMap["articleAuthor"] = report.Author
-	//contentMap["publishedTime"] = report.PublishTime.Format(utils.FormatDateTime)
-	contentMap["publishedTime"] = report.PublishTime
-	contentMap["audioName"] = report.VideoName
-	contentMap["audioUrl"] = report.VideoUrl
-
-	videoPlaySeconds := report.VideoPlaySeconds
-	f, _ := strconv.ParseFloat(videoPlaySeconds, 64)
-	contentMap["audioLength"] = f * 1000
-	contentMap["disclaimers"] = disclaimers
-
-	param["cardData"] = dataMap
-	param["contentData"] = contentMap
-	param["sign"] = strings.ToUpper(sign)
-
-	paramJson, err := json.Marshal(param)
-	if err != nil {
-		fmt.Println("param json.Marshal Err:" + err.Error())
-		err = errors.New("param json.Marshal Err:" + err.Error())
-		return
-	}
-
-	utils.FileLog.Info("ZhaoGangSend parms:%s", string(paramJson))
-	result, err := http.Post(postUrl, string(paramJson), "application/json")
-	if err != nil {
-		fmt.Println("post err:" + err.Error())
-		err = errors.New("post Err:" + err.Error())
-		return
-	}
-	utils.FileLog.Info("ZhaoGangSend Result:%s", string(result))
-	//返回数据校验
-	mapResult := make(map[string]interface{})
-	err = json.Unmarshal(result, &mapResult)
-	if err != nil {
-		fmt.Println("找钢网返回数据转json失败: err:", err.Error(), ";返回数据:", string(result))
-		err = errors.New(fmt.Sprint("找钢网返回数据转json失败: err:", err.Error(), ";返回数据:", string(result)))
-		return
-	}
-	if resultCode, ok := mapResult["code"]; ok {
-		tmpResultCode := resultCode.(float64)
-		if tmpResultCode != 200 {
-			fmt.Println("找钢网返回数据异常,code返回参异常;返回数据:", string(result))
-			err = errors.New(fmt.Sprint("找钢网返回数据异常,code返回参异常;返回数据:", string(result)))
-			return
-		}
-	} else {
-		fmt.Println("找钢网返回数据异常,缺少code返回参;返回数据:", string(result))
-		err = errors.New(fmt.Sprint("找钢网返回数据异常,缺少code返回参;返回数据:", string(result)))
-		return
-	}
-
-	utils.FileLog.Info("%s", string(result))
-	return
-}
-
-/*func init() {
-	fmt.Println("start")
-	vint := 845
-	report, err := models.GetReportById(vint)
-	if err != nil {
-		fmt.Println("GetReportById Err", err.Error())
-		return
-	}
-	ZhaoGangSend(report)
-	fmt.Println("end")
-	return
-}*/
-
 // PublishDayWeekReport 发布晨周报
 func PublishDayWeekReport(reportId int) (tips string, err error) {
 	report, err := models.GetReportByReportId(reportId)
@@ -353,6 +215,21 @@ func PublishTodayDayReport() (err error) {
 	return
 }
 
+func initp2_838 (){
+	var condition string
+	var pars []interface{}
+	condition = " AND  state =  2 "
+	list ,err:= models.GetReportByCondition(condition,pars,[]string{},"",false,0,0)
+	if err != nil{
+		fmt.Println(err)
+	}
+	fmt.Println(len(list))
+	for  _,v:=  range  list{
+		fmt.Println(v.Id)
+		UpdateReportEs(v.Id,2)
+	}
+}
+
 // UpdateReportEs 更新报告/章节Es
 func UpdateReportEs(reportId int, publishState int) (err error) {
 	if reportId <= 0 {
@@ -372,7 +249,7 @@ func UpdateReportEs(reportId int, publishState int) (err error) {
 		if len(chapterList) > 0 {
 			for i := 0; i < len(chapterList); i++ {
 				// 章节对应的品种
-				permissionList, tmpErr := models.GetChapterTypePermissionByTypeIdAndResearchType(chapterList[i].TypeId, chapterList[i].ReportType)
+				permissionList, tmpErr := models.GetChapterTypePermissionByReportChapterTypeId(chapterList[i].TypeId)
 				if tmpErr != nil {
 					return
 				}
@@ -491,7 +368,7 @@ func UpdateReportChapterEs(reportChapterId int) (err error) {
 		return
 	}
 	// 章节对应的品种
-	permissionList, tmpErr := models.GetChapterTypePermissionByTypeIdAndResearchType(chapterInfo.TypeId, chapterInfo.ReportType)
+	permissionList, tmpErr := models.GetChapterTypePermissionByReportChapterTypeId(chapterInfo.TypeId)
 	if tmpErr != nil {
 		return
 	}
@@ -559,28 +436,6 @@ func DeleteReportAndChapter(reportId int) (err error) {
 	return
 }
 
-// UpdatePublishedReportToEs 更新已发布的报告ES
-func UpdatePublishedReportToEs() (err error) {
-	// 获取所有已发布的报告
-	var condition string
-	var pars []interface{}
-	condition = ` AND state IN (2, 6) `
-	reportList, err := models.GetReportList(condition, pars, "ficc", 1, 5000)
-	count := 0
-	failCount := 0
-	for i := 0; i < len(reportList); i++ {
-		if err = UpdateReportEs(reportList[i].Id, 2); err != nil {
-			fmt.Printf("更新失败, report_id: %d, Err: %s\n", reportList[i].Id, err.Error())
-			failCount += 1
-		} else {
-			count += 1
-		}
-	}
-	fmt.Printf("报告总数:%d, 更新成功数: %d, 更新失败数: %d", len(reportList), count, failCount)
-
-	return
-}
-
 // 替换报告内容中的base64图片
 func replaceReportBase64ToImg(content string) (newContent string, err error) {
 	if content == "" {
@@ -957,7 +812,7 @@ func CreateNewReport(req models.AddReq, adminInfo *system.Admin) (newReportId in
 		}
 		contentSub = sub
 	}
-	maxStage, e := models.GetReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond)
+	maxStage, e := models.GetReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird)
 	if e != nil {
 		errMsg = "期数获取失败!"
 		err = errors.New("期数获取失败,Err:" + e.Error())
@@ -983,36 +838,31 @@ func CreateNewReport(req models.AddReq, adminInfo *system.Admin) (newReportId in
 	item.ReportVersion = req.ReportVersion
 	item.AdminId = adminInfo.AdminId
 	item.AdminRealName = adminInfo.RealName
-	newReportId, e = models.AddReport(item)
-	if e != nil {
-		errMsg = "保存失败"
-		err = errors.New("保存失败,Err:" + e.Error())
-		return
-	}
 
-	// 处理权限
-	//if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
-	go func() {
-		permissionItems, e := models.GetPermission(req.ClassifyIdSecond)
-		if e != nil {
-			alarm_msg.SendAlarmMsg("获取权限失败,Err:"+err.Error(), 3)
-		}
-		for _, v := range permissionItems {
-			e = models.AddChartPermissionChapterMapping(v.ChartPermissionId, newReportId)
-			if e != nil {
-				alarm_msg.SendAlarmMsg("新增权限失败,Err:"+err.Error(), 3)
-			}
-		}
-		// 同步crm权限
-		_ = EditReportPermissionSync(newReportId, req.ClassifyIdSecond)
-	}()
-	//}
+	item.ClassifyIdThird = req.ClassifyIdThird
+	item.ClassifyNameThird = req.ClassifyNameThird
+	// 产品要求,如果是多人协作,那么就是章节类型的报告
+	if req.CollaborateType == 2 {
+		item.HasChapter = 1
+		item.ChapterType = ""
+	}
+	item.LastModifyAdminId = adminInfo.AdminId
+	item.LastModifyAdminName = adminInfo.RealName
+	item.ContentModifyTime = time.Now()
+	item.NeedSplice = 0
+	item.ContentStruct = html.EscapeString(req.ContentStruct)
+	item.HeadImg = req.HeadImg
+	item.EndImg = req.EndImg
+	item.CanvasColor = req.CanvasColor
+	item.HeadResourceId = req.HeadResourceId
+	item.EndResourceId = req.EndResourceId
+	item.CollaborateType = req.CollaborateType
+	item.ReportLayout = req.ReportLayout
+	item.IsPublicPublish = req.IsPublicPublish
+	item.ReportCreateTime = time.Now()
+
+	err, errMsg = AddReportAndChapter(item, 0, req.GrantAdminIdList)
 
-	reportCode = utils.MD5(strconv.Itoa(int(newReportId)))
-	//修改唯一编码
-	{
-		go models.ModifyReportCode(newReportId, reportCode)
-	}
 	return
 }
 
@@ -1197,9 +1047,13 @@ func GetReportContentSubWithoutIframe(content string) (contentSub string, err er
 
 // UpdateReportEditMark 更新研报当前更新状态
 // status 枚举值 1:编辑中,0:完成编辑, 2:只做查询
-func UpdateReportEditMark(reportId, nowUserId, status int, nowUserName, lang string) (ret models.MarkReportResp, err error) {
+func UpdateReportEditMark(reportId, reportChapterId, nowUserId, status int, nowUserName, lang string) (ret models.MarkReportResp, err error) {
 	//更新标记key
 	key := fmt.Sprint(`crm:report:edit:`, reportId)
+	//  章节id不为0则加上章节id
+	if reportChapterId > 0 {
+		key = fmt.Sprint(key, ":", reportChapterId)
+	}
 	ret.Status = 0
 	ret.Msg = "无人编辑"
 
@@ -1228,9 +1082,6 @@ func UpdateReportEditMark(reportId, nowUserId, status int, nowUserName, lang str
 		classifyNameFirst = reportInfo.ClassifyNameFirst
 	}
 
-	if classifyNameFirst == "晨报" || classifyNameFirst == "周报" {
-		return
-	}
 	if opUserId > 0 && opUserId != nowUserId {
 		editor := opUser.Editor
 		if editor == "" {
@@ -1292,7 +1143,7 @@ func SaveReportLogs(item *models.Report, chapters []*models.ReportChapter, admin
 	}()
 
 	if item != nil {
-		e := models.AddReportSaveLog(item.Id, item.AdminId, item.Content, item.ContentSub, item.AdminRealName)
+		e := models.AddReportSaveLog(item.Id, item.AdminId, item.Content, item.ContentSub, item.ContentStruct, item.CanvasColor, item.AdminRealName, item.HeadResourceId, item.EndResourceId)
 		if e != nil {
 			err = fmt.Errorf("AddReportSaveLog: %s", e.Error())
 			return

+ 37 - 9
services/report_approve.go

@@ -35,7 +35,7 @@ func CheckReportApproveFlowChange(reportType, classifyFirstId, classifySecondId
 	pars = append(pars, classifyFirstId, classifySecondId, models.ReportStateWaitApprove)
 	switch reportType {
 	case report_approve.FlowReportTypeChinese:
-		ct, e := models.GetReportListCount(cond, pars, "")
+		ct, e := models.GetReportListCount(cond, pars)
 		if e != nil {
 			err = fmt.Errorf("GetReportListCount err: %s", e.Error())
 			return
@@ -97,7 +97,7 @@ func CheckReportOpenApprove(reportType, firstId, secondId int) (opening bool, er
 }
 
 // CheckReportCurrState 校验报告当前应有的状态
-func CheckReportCurrState(reportType, firstId, secondId, operate int) (state int, err error) {
+func CheckReportCurrState(reportType, firstId, secondId, thirdId, operate int) (state int, err error) {
 	// 获取审批配置
 	confMap, e := models.GetBusinessConf()
 	if e != nil {
@@ -109,9 +109,9 @@ func CheckReportCurrState(reportType, firstId, secondId, operate int) (state int
 
 	// 查询对应分类是否有审批流
 	flowOb := new(report_approve.ReportApproveFlow)
-	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId, report_approve.ReportApproveFlowCols.ClassifyThirdId)
 	flowPars := make([]interface{}, 0)
-	flowPars = append(flowPars, reportType, firstId, secondId)
+	flowPars = append(flowPars, reportType, firstId, secondId, thirdId)
 	flowItem, e := flowOb.GetItemByCondition(flowCond, flowPars, "")
 	if e != nil && e.Error() != utils.ErrNoRow() {
 		err = fmt.Errorf("ApproveFlow GetItemByCondition err: %s", e.Error())
@@ -148,7 +148,7 @@ func CheckReportCurrState(reportType, firstId, secondId, operate int) (state int
 }
 
 // SubmitReportApprove 提交审批
-func SubmitReportApprove(reportType, reportId int, reportTitle string, firstId, secondId int, sysAdminId int, sysAdminName string) (approveId int, err error) {
+func SubmitReportApprove(reportType, reportId int, reportTitle string, firstId, secondId, thirdId int, sysAdminId int, sysAdminName string) (approveId int, err error) {
 	// 默认内部审批, 如果是走的第三方审批, 那么仅修改状态
 	confMap, e := models.GetBusinessConf()
 	if e != nil {
@@ -171,9 +171,9 @@ func SubmitReportApprove(reportType, reportId int, reportTitle string, firstId,
 
 	// 查询审批流
 	flowOb := new(report_approve.ReportApproveFlow)
-	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId)
+	flowCond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s = ? AND %s = ?`, report_approve.ReportApproveFlowCols.ReportType, report_approve.ReportApproveFlowCols.ClassifyFirstId, report_approve.ReportApproveFlowCols.ClassifySecondId, report_approve.ReportApproveFlowCols.ClassifyThirdId)
 	flowPars := make([]interface{}, 0)
-	flowPars = append(flowPars, reportType, firstId, secondId)
+	flowPars = append(flowPars, reportType, firstId, secondId, thirdId)
 	flowItem, e := flowOb.GetItemByCondition(flowCond, flowPars, "")
 	if e != nil {
 		err = fmt.Errorf("ApproveFlow GetItemByCondition err: %s", e.Error())
@@ -216,6 +216,7 @@ func SubmitReportApprove(reportType, reportId int, reportTitle string, firstId,
 	newApprove.ReportTitle = reportTitle
 	newApprove.ClassifyFirstId = firstId
 	newApprove.ClassifySecondId = secondId
+	newApprove.ClassifyThirdId = thirdId
 	newApprove.State = report_approve.ReportApproveStateApproving
 	newApprove.FlowId = flowItem.ReportApproveFlowId
 	newApprove.FlowVersion = flowItem.CurrVersion
@@ -457,7 +458,12 @@ func PassReportApprove(approveItem *report_approve.ReportApprove, recordItem *re
 	recordItem.State = report_approve.ReportApproveStatePass
 	recordItem.ApproveTime = now
 	recordItem.ModifyTime = now
-	recordCols := []string{"State", "ApproveTime", "ModifyTime"}
+	recordItem.NodeState = report_approve.ReportApproveStatePass
+	recordItem.NodeApproveUserId = recordItem.ApproveUserId
+	recordItem.NodeApproveUserName = recordItem.ApproveUserName
+	recordItem.NodeApproveTime = now
+
+	recordCols := []string{"State", "ApproveTime", "ModifyTime", "NodeState", "NodeApproveUserId", "NodeApproveUserName", "NodeApproveTime"}
 	lastApprove := false
 
 	// 依次审批
@@ -504,6 +510,7 @@ func PassReportApprove(approveItem *report_approve.ReportApprove, recordItem *re
 			newRecord.ApproveUserSort = nextUser.Sort
 			newRecord.CreateTime = now
 			newRecord.ModifyTime = now
+			newRecord.NodeState = report_approve.ReportApproveStateApproving
 			if e = newRecord.Create(); e != nil {
 				err = fmt.Errorf("生成审批记录失败, Err: %s", e.Error())
 				return
@@ -602,6 +609,13 @@ func PassReportApprove(approveItem *report_approve.ReportApprove, recordItem *re
 			err = fmt.Errorf("更新审批记录状态失败, Err: %s", e.Error())
 			return
 		}
+
+		// 将该审批的同一个节点的记录标记为已审批
+		if e = recordItem.UpdateNodeState(recordItem.ReportApproveId, recordItem.NodeId, recordItem.NodeState, recordItem.NodeApproveUserId, recordItem.NodeApproveUserName, recordItem.NodeApproveTime); e != nil {
+			err = fmt.Errorf("更新同一节点的其他审批记录状态失败, Err: %s", e.Error())
+			return
+		}
+
 		if currNode.NextNodeId == 0 {
 			lastApprove = true
 		}
@@ -684,12 +698,24 @@ func RefuseReportApprove(approveItem *report_approve.ReportApprove, recordItem *
 	recordItem.ApproveRemark = approveRemark
 	recordItem.ApproveTime = now
 	recordItem.ModifyTime = now
-	recordCols := []string{"State", "ApproveRemark", "ApproveTime", "ModifyTime"}
+
+	recordItem.NodeState = report_approve.ReportApproveStatePass
+	recordItem.NodeApproveUserId = recordItem.ApproveUserId
+	recordItem.NodeApproveUserName = recordItem.ApproveUserName
+	recordItem.NodeApproveTime = now
+
+	recordCols := []string{"State", "ApproveRemark", "ApproveTime", "ModifyTime", "NodeState", "NodeApproveUserId", "NodeApproveUserName", "NodeApproveTime"}
 	if e := recordItem.Update(recordCols); e != nil {
 		err = fmt.Errorf("更新审批记录状态失败, Err: %s", e.Error())
 		return
 	}
 
+	// 将该审批的同一个节点的记录标记为已审批
+	if e := recordItem.UpdateNodeState(recordItem.ReportApproveId, recordItem.NodeId, recordItem.NodeState, recordItem.NodeApproveUserId, recordItem.NodeApproveUserName, recordItem.NodeApproveTime); e != nil {
+		err = fmt.Errorf("更新同一节点的其他审批记录状态失败, Err: %s", e.Error())
+		return
+	}
+
 	// 驳回-更新审批, 报告状态, 推送消息
 	approveItem.State = report_approve.ReportApproveStateRefuse
 	approveItem.ApproveRemark = approveRemark
@@ -700,6 +726,7 @@ func RefuseReportApprove(approveItem *report_approve.ReportApprove, recordItem *
 		err = fmt.Errorf("更新审批状态失败, Err: %s", e.Error())
 		return
 	}
+
 	if e := updateReportApproveState(approveItem.ReportType, approveItem.ReportId, approveItem.ReportApproveId, models.ReportStateRefused); e != nil {
 		err = fmt.Errorf("更新报告状态失败, Err: %s", e.Error())
 		return
@@ -759,6 +786,7 @@ func BuildNextNodeRecordAndMsg(approveNodeItem *report_approve.ReportApproveNode
 		r.ApproveUserSort = u.Sort
 		r.CreateTime = now
 		r.ModifyTime = now
+		r.NodeState = report_approve.ReportApproveStateApproving // 当前节点审批状态
 		newRecords = append(newRecords, r)
 		// 依次审批仅生成一条记录
 		if approveNode.ApproveType == report_approve.NodeApproveTypeRoll {

+ 169 - 0
services/report_chapter.go

@@ -0,0 +1,169 @@
+package services
+
+import (
+	"eta/eta_api/models"
+	"eta/eta_api/utils"
+	"fmt"
+	"time"
+)
+
+// MoveReportChapter
+// @Description: 移动报告章节
+// @author: Roc
+// @datetime 2024-06-06 09:48:52
+// @param req *models.ReportChapterMoveReq
+// @return err error
+// @return errMsg string
+func MoveReportChapter(req *models.ReportChapterMoveReq) (err error, errMsg string) {
+	ob := new(models.ReportChapter)
+	reportChapterId := req.ReportChapterId
+	prevReportChapterId := req.PrevReportChapterId
+	nextReportChapterId := req.NextReportChapterId
+
+	//如果有传入 上一个兄弟节点分类id
+	var (
+		reportChapter     *models.ReportChapter
+		prevReportChapter *models.ReportChapter
+		nextReportChapter *models.ReportChapter
+
+		prevSort int
+		nextSort int
+	)
+
+	// 移动对象为分类, 判断权限
+	reportChapter, err = ob.GetReportChapterById(reportChapterId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "当前报告章节不存在"
+			err = fmt.Errorf("获取报告章节信息失败,Err:" + err.Error())
+			return
+		}
+		errMsg = "移动失败"
+		err = fmt.Errorf("获取章节信息失败,Err:" + err.Error())
+		return
+	} else if reportChapter.ReportChapterId == 0 {
+		errMsg = "当前报告章节不存在"
+		err = fmt.Errorf("获取报告章节信息失败,Err:" + err.Error())
+		return
+	}
+
+	if prevReportChapterId > 0 {
+		prevReportChapter, err = ob.GetReportChapterById(prevReportChapterId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取上一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		prevSort = prevReportChapter.Sort
+	}
+
+	if nextReportChapterId > 0 {
+		//下一个兄弟节点
+		nextReportChapter, err = ob.GetReportChapterById(nextReportChapterId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取下一个兄弟节点分类信息失败,Err:" + err.Error())
+			return
+		}
+		nextSort = nextReportChapter.Sort
+	}
+
+	err, errMsg = moveReportChapter(reportChapter, prevReportChapter, nextReportChapter, reportChapter.ReportId, prevSort, nextSort)
+	return
+}
+
+// moveReportChapter
+// @Description: 移动章节分类
+// @author: Roc
+// @datetime 2024-06-06 09:48:46
+// @param reportChapter *models.ReportChapter
+// @param prevReportChapter *models.ReportChapter
+// @param nextReportChapter *models.ReportChapter
+// @param reportId int
+// @param prevSort int
+// @param nextSort int
+// @return err error
+// @return errMsg string
+func moveReportChapter(reportChapter, prevReportChapter, nextReportChapter *models.ReportChapter, reportId int, prevSort, nextSort int) (err error, errMsg string) {
+	ob := new(models.ReportChapter)
+	updateCol := make([]string, 0)
+
+	if prevSort > 0 {
+		//如果是移动在两个兄弟节点之间
+		if nextSort > 0 {
+			//下一个兄弟节点
+			//如果上一个兄弟与下一个兄弟的排序权重是一致的,那么需要将下一个兄弟(以及下个兄弟的同样排序权重)的排序权重+2,自己变成上一个兄弟的排序权重+1
+			if prevSort == nextSort || prevSort == reportChapter.Sort {
+				//变更兄弟节点的排序
+				updateSortStr := `sort + 2`
+
+				//变更分类
+				if prevReportChapter != nil {
+					_ = ob.UpdateReportChapterSortByReportId(reportId, prevReportChapter.ReportChapterId, prevReportChapter.Sort, updateSortStr)
+				} else {
+					_ = ob.UpdateReportChapterSortByReportId(reportId, 0, prevSort, updateSortStr)
+				}
+
+			} else {
+				//如果下一个兄弟的排序权重正好是上个兄弟节点的下一层,那么需要再加一层了
+				if nextSort-prevSort == 1 {
+					//变更兄弟节点的排序
+					updateSortStr := `sort + 1`
+
+					//变更分类
+					if prevReportChapter != nil {
+						_ = ob.UpdateReportChapterSortByReportId(reportId, prevReportChapter.ReportChapterId, prevSort, updateSortStr)
+					} else {
+						_ = ob.UpdateReportChapterSortByReportId(reportId, 0, prevSort, updateSortStr)
+					}
+
+				}
+			}
+		}
+
+		reportChapter.Sort = prevSort + 1
+		reportChapter.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else if prevReportChapter == nil && nextReportChapter == nil {
+		//处理只拖动到目录里,默认放到目录底部的情况
+		var maxSort int
+		maxSort, err = ob.GetMaxSortByReportId(reportId)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("查询组内排序信息失败,Err:" + err.Error())
+			return
+		}
+		reportChapter.Sort = maxSort + 1 //那就是排在组内最后一位
+		reportChapter.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	} else {
+		// 拖动到父级分类的第一位
+		firstReportChapter, tmpErr := ob.GetFirstReportChapterByReportId(reportId)
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			errMsg = "移动失败"
+			err = fmt.Errorf("获取当前报告下,且排序数相同 的排序第一条的数据失败,Err:" + tmpErr.Error())
+			return
+		}
+
+		//如果该分类下存在其他分类,且第一个其他分类的排序等于0,那么需要调整排序
+		if firstReportChapter != nil && firstReportChapter.ReportChapterId != 0 && firstReportChapter.Sort == 0 {
+			updateSortStr := ` sort + 1 `
+			_ = ob.UpdateReportChapterSortByReportId(reportId, firstReportChapter.ReportChapterId-1, 0, updateSortStr)
+		}
+
+		reportChapter.Sort = 0 //那就是排在第一位
+		reportChapter.ModifyTime = time.Now()
+		updateCol = append(updateCol, "Sort", "ModifyTime")
+	}
+
+	//更新
+	if len(updateCol) > 0 {
+		err = reportChapter.Update(updateCol)
+		if err != nil {
+			errMsg = "移动失败"
+			err = fmt.Errorf("修改失败,Err:" + err.Error())
+			return
+		}
+	}
+	return
+}

+ 0 - 59
services/report_push.go

@@ -1,12 +1,9 @@
 package services
 
 import (
-	"fmt"
 	"eta/eta_api/models"
 	"eta/eta_api/services/alarm_msg"
-	"eta/eta_api/utils"
 	"strconv"
-	"time"
 )
 
 //func init() {
@@ -14,61 +11,6 @@ import (
 //	SendReportToThs(report)
 //}
 
-// SendReportToEmail 发送报告邮件
-func SendReportToEmail(report *models.ReportDetail) (err error) {
-	if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox && utils.BusinessCode != utils.BusinessCodeDebug {
-		// 客户不做报告邮件推送
-		return
-	}
-	fmt.Println("SendReportToEmail")
-	defer func() {
-		if err != nil {
-			//fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers)
-			go alarm_msg.SendAlarmMsg("发送报告至邮件失败,SendReportToEmail ErrMsg:"+err.Error(), 3)
-			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "SendReportToEmail ErrMsg:"+err.Error(), utils.EmailSendToUsers)
-		}
-	}()
-	toUser := ``
-	jumpUrl := ``
-	if utils.RunMode == "debug" {
-		//toUser = `glji@hzinsights.com`
-		toUser = `317699326@qq.com`
-		jumpUrl = "http://rddpweb.brilliantstart.cn/reportdtl?id=1578" + strconv.Itoa(report.Id)
-	} else {
-		toUser = "lijun011112@gtjas.com"
-		jumpUrl = "https://ficc.hzinsights.com/reportdtl?id=" + strconv.Itoa(report.Id)
-	}
-
-	createDate, err := time.Parse(utils.FormatDateTime, report.CreateTime)
-	createDateFrom := createDate.Format("060102")
-	emailBody :=
-		`<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>Email</title>
-</head>
-<body>
-    <div>
-        <h2 style="font-size: 16px;">弘则研报:<span>` + report.Title + "_" + createDateFrom + `</span><span></span></h2>
-        <div style="font-size: 14px;margin-left: 40px;">
-            <p>你好,</p>
-            <p>今日报告已推送。</p>
-            <p><span>报告类型:</span><span>` + report.ClassifyNameFirst + `</span></p>
-            <p><span>报告标题:</span><span>` + report.Title + `</span></p>
-            <p><span>报告链接:</span><a href="` + jumpUrl + `">弘则研究</a></p>
-        </div>
-    </div>
-</body>
-</html>`
-	fmt.Println("start SendReportToEmail")
-	result, err := utils.SendEmailByHz("弘则研报报告", emailBody, toUser)
-	fmt.Println("send result:", result, err)
-	return
-}
-
 // SendReportMiniToThs 发送报告-研报小程序到同花顺
 func SendReportMiniToThs(report *models.ReportDetail) (err error) {
 	defer func() {
@@ -78,7 +20,6 @@ func SendReportMiniToThs(report *models.ReportDetail) (err error) {
 		}
 	}()
 	if report.HasChapter == 0 {
-		go SendReportToEmail(report)
 	}
 	return
 }

+ 742 - 0
services/report_v2.go

@@ -0,0 +1,742 @@
+package services
+
+import (
+	"errors"
+	"eta/eta_api/models"
+	"eta/eta_api/models/report"
+	"eta/eta_api/models/system"
+	"eta/eta_api/utils"
+	"strconv"
+	"time"
+)
+
+// AddReportAndChapter
+// @Description: 新增报告(包含章节)
+// @author: Roc
+// @datetime 2024-06-04 11:23:20
+// @param reportInfo *models.Report
+// @param inheritReportId int
+// @return err error
+// @return errMsg string
+func AddReportAndChapter(reportInfo *models.Report, inheritReportId int, grantAdminIdList []int) (err error, errMsg string) {
+	// 获取最小分类id
+	minClassifyId := reportInfo.ClassifyIdThird
+	if minClassifyId <= 0 {
+		minClassifyId = reportInfo.ClassifyIdSecond
+	}
+	if minClassifyId <= 0 {
+		minClassifyId = reportInfo.ClassifyIdFirst
+	}
+	if minClassifyId <= 0 {
+		errMsg = "分类异常"
+		err = errors.New(errMsg)
+		return
+	}
+
+	errMsg = "生成报告失败"
+
+	// 报告继承
+	if inheritReportId > 0 {
+		inheritReport, tmpErr := models.GetReportByReportId(inheritReportId)
+		if tmpErr != nil && tmpErr.Error() != utils.ErrNoRow() {
+			errMsg = "获取待继承的报告失败"
+			err = tmpErr
+			return
+		}
+		if inheritReport != nil {
+			// 判断当前的报告分类与继承的报告分类是否一致
+			if inheritReport.ClassifyIdFirst != reportInfo.ClassifyIdFirst || inheritReport.ClassifyIdSecond != reportInfo.ClassifyIdSecond || inheritReport.ClassifyIdThird != reportInfo.ClassifyIdThird {
+				errMsg = "分类异常,与继承的报告分类不一致"
+				err = tmpErr
+				return
+			}
+
+			reportInfo.ChapterType = inheritReport.ChapterType
+			reportInfo.Content = inheritReport.Content
+			reportInfo.ContentSub = inheritReport.ContentSub
+			reportInfo.ContentStruct = inheritReport.ContentStruct
+			reportInfo.HeadImg = inheritReport.HeadImg
+			reportInfo.EndImg = inheritReport.EndImg
+			reportInfo.CanvasColor = inheritReport.CanvasColor
+			reportInfo.NeedSplice = inheritReport.NeedSplice
+			reportInfo.HeadResourceId = inheritReport.HeadResourceId
+			reportInfo.EndResourceId = inheritReport.EndResourceId
+			reportInfo.InheritReportId = inheritReport.Id
+		}
+	}
+
+	// 获取待生成的报告章节
+	addChapterList, allGrantUserList, err, errMsg := getAddChapter(reportInfo, minClassifyId, inheritReportId, grantAdminIdList)
+
+	// 新增报告及章节
+	var reportId int64
+	reportId, err = models.AddReportAndChapter(reportInfo, allGrantUserList, addChapterList)
+	if err != nil {
+		err = errors.New("新增报告及章节失败, Err: " + err.Error())
+		return
+	}
+	reportCode := utils.MD5(strconv.Itoa(reportInfo.Id))
+	reportInfo.ReportCode = reportCode
+
+	// 修改唯一编码
+	{
+		go models.ModifyReportCode(reportId, reportCode)
+	}
+
+	// TODO 报告权限处理
+	//处理权限
+	//go func() {
+	//	permissionItems, e := models.GetPermission(req.ClassifyIdSecond)
+	//	if e != nil {
+	//		alarm_msg.SendAlarmMsg("获取权限失败,Err:"+e.Error(), 3)
+	//		return
+	//	}
+	//	for _, v := range permissionItems {
+	//		e = models.AddChartPermissionChapterMapping(v.ChartPermissionId, int64(item.Id))
+	//		if e != nil {
+	//			alarm_msg.SendAlarmMsg("新增权限失败,Err:"+e.Error(), 3)
+	//			return
+	//		}
+	//	}
+	//	// 同步crm权限
+	//	_ = EditReportPermissionSync(int64(item.Id), req.ClassifyIdSecond)
+	//}()
+
+	return
+}
+
+// EditReport
+// @Description: 修改报告的基础信息、授权用户权限
+// @author: Roc
+// @datetime 2024-06-06 17:16:58
+// @param reportInfo *models.Report
+// @param req models.EditReq
+// @param sysUser *system.Admin
+// @return err error
+// @return errMsg string
+func EditReport(reportInfo *models.Report, req models.EditReq, sysUser *system.Admin) (err error, errMsg string) {
+	errMsg = `保存失败`
+	var stage int
+	if reportInfo.ClassifyNameFirst != req.ClassifyNameFirst || reportInfo.ClassifyNameSecond != req.ClassifyNameSecond {
+		// 报告期数
+		maxStage, _ := models.GetReportStageEdit(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird, int(req.ReportId))
+		maxStage = maxStage + 1
+		stage = maxStage
+	} else {
+		stage = reportInfo.Stage
+	}
+	//if req.State != reportInfo.State {
+	//	recordItem := &models.ReportStateRecord{
+	//		ReportId:   int(req.ReportId),
+	//		ReportType: 1,
+	//		State:      req.State,
+	//		AdminId:    this.SysUser.AdminId,
+	//		AdminName:  this.SysUser.AdminName,
+	//		CreateTime: time.Now(),
+	//	}
+	//	go func() {
+	//		_, _ = models.AddReportStateRecord(recordItem)
+	//	}()
+	//}
+
+	//item := new(models.Report)
+	reportInfo.ClassifyIdFirst = req.ClassifyIdFirst
+	reportInfo.ClassifyNameFirst = req.ClassifyNameFirst
+	reportInfo.ClassifyIdSecond = req.ClassifyIdSecond
+	reportInfo.ClassifyNameSecond = req.ClassifyNameSecond
+	reportInfo.ClassifyIdThird = req.ClassifyIdThird
+	reportInfo.ClassifyNameThird = req.ClassifyNameThird
+	reportInfo.Title = req.Title
+	reportInfo.Abstract = req.Abstract
+	reportInfo.Author = req.Author
+	reportInfo.Frequency = req.Frequency
+	//reportInfo.State = reportInfo.State // 编辑不变更状态
+	reportInfo.Stage = stage // 编辑不变更期数
+	//reportInfo.Content = html.EscapeString(req.Content)	// 编辑不变更具体内容
+	//reportInfo.ContentSub = html.EscapeString(contentSub)	// 编辑不变更具体内容
+	reportInfo.CreateTime = req.CreateTime
+	//reportInfo.CollaborateType = req.CollaborateType
+	//reportInfo.ReportLayout = req.ReportLayout
+	if req.IsPublicPublish <= 0 {
+		req.IsPublicPublish = 1
+	}
+	reportInfo.IsPublicPublish = req.IsPublicPublish
+	reportInfo.LastModifyAdminId = sysUser.AdminId
+	reportInfo.LastModifyAdminName = sysUser.RealName
+	reportInfo.ModifyTime = time.Now()
+
+	updateCols := []string{"ClassifyIdFirst", "ClassifyNameFirst", "ClassifyIdSecond", "ClassifyNameSecond", "ClassifyIdThird", "ClassifyNameThird", "Title", "Abstract", "Author", "Frequency", "Stage", "CreateTime", "IsPublicPublish", "LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}
+
+	// 需要添加的报告授权数据
+	addReportAdminList := make([]*report.ReportGrant, 0)
+	// 待移除的报告授权数据id
+	delReportGrantIdList := make([]int, 0)
+
+	// 处理当前报告需要新增/移除的授权信息
+	{
+		reportGrantObj := report.ReportGrant{}
+		// 获取当前报告已经授权的用户信息
+		reportGrantList, tmpErr := reportGrantObj.GetGrantListById(reportInfo.Id)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		// 当前报告已经授权的用户信息
+		currReportAdminMap := make(map[int]*report.ReportGrant)
+		// 需要删除的报告授权数据
+		delReportAdminMap := make(map[int]*report.ReportGrant)
+		for _, v := range reportGrantList {
+			currReportAdminMap[v.AdminId] = v
+			delReportAdminMap[v.AdminId] = v
+		}
+
+		// 先看需要新增哪些用户
+		for _, tmpAdminId := range req.GrantAdminIdList {
+			_, ok := currReportAdminMap[tmpAdminId]
+			// 如果章节中需要新增的用户 已经在 报告授权用户里面,那么就忽略,可以不用新增了
+			if ok {
+				delete(delReportAdminMap, tmpAdminId)
+				continue
+			}
+
+			// 如果不存在,那么就新增授权
+			addReportAdminList = append(addReportAdminList, &report.ReportGrant{
+				//GrantId:         0,
+				ReportId:   reportInfo.Id,
+				AdminId:    tmpAdminId,
+				CreateTime: time.Now(),
+			})
+		}
+
+		// 查出需要移除的授权id
+		for _, v := range delReportAdminMap {
+			delReportGrantIdList = append(delReportGrantIdList, v.GrantId)
+		}
+	}
+
+	// 修改报告的基本信息,以及报告的授权用户
+	err = models.EditReportAndPermission(reportInfo, updateCols, addReportAdminList, delReportGrantIdList)
+	if err != nil {
+		return
+	}
+	// TODO 权限处理
+	//处理权限
+	//go func() {
+	//	e := models.RemoveChartPermissionChapterMapping(req.ReportId)
+	//	if e != nil {
+	//		alarm_msg.SendAlarmMsg("修改删除报告权限失败,Err:"+e.Error(), 3)
+	//		return
+	//	}
+	//	permissionItems, e := models.GetPermission(req.ClassifyIdSecond)
+	//	if e != nil {
+	//		alarm_msg.SendAlarmMsg("获取权限失败,Err:"+e.Error(), 3)
+	//		return
+	//	}
+	//	for _, v := range permissionItems {
+	//		e = models.AddChartPermissionChapterMapping(v.ChartPermissionId, req.ReportId)
+	//		if e != nil {
+	//			alarm_msg.SendAlarmMsg("新增权限失败,Err:"+e.Error(), 3)
+	//			return
+	//		}
+	//	}
+	//	// 同步crm权限
+	//	_ = services.EditReportPermissionSync(req.ReportId, req.ClassifyIdSecond)
+	//}()
+
+	return
+}
+
+// getAddChapter
+// @Description: 获取待新增的报告章节列表
+// @author: Roc
+// @datetime 2024-06-04 13:10:58
+// @param reportInfo *models.Report
+// @param minClassifyId int
+// @param inheritReportId int
+// @param grantAdminIdList []int
+// @return chapterList []*models.ReportChapter
+// @return err error
+// @return errMsg string
+func getAddChapter(reportInfo *models.Report, minClassifyId, inheritReportId int, grantAdminIdList []int) (chapterList []models.AddReportChapter, allGrantUserList []*report.ReportGrant, err error, errMsg string) {
+	// 待生成的报告章节内容
+	chapterList = make([]models.AddReportChapter, 0)
+
+	// 所有的授权用户
+	allGrantUserList = make([]*report.ReportGrant, 0)
+	// 报告授权的用户ID
+	needAdminIdMap := make(map[int]bool)
+	for _, adminId := range grantAdminIdList {
+		needAdminIdMap[adminId] = true
+		allGrantUserList = append(allGrantUserList, &report.ReportGrant{
+			//GrantId:      0,
+			//ReportId:     0,
+			AdminId:    adminId,
+			CreateTime: time.Now(),
+		})
+	}
+	if reportInfo.HasChapter != 1 {
+		return
+	}
+
+	// TODO 弘则得单独处理启用禁用的情况
+	//if utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeSandbox && utils.BusinessCode != utils.BusinessCodeDebug {
+	//	br.Ret = 200
+	//	br.Success = true
+	//	br.Msg = "操作成功"
+	//	return
+	//}
+
+	errMsg = "生成报告章节失败"
+	// 章节类型列表
+	typeList, err := models.GetReportChapterTypeListByClassifyId(minClassifyId)
+	if err != nil {
+		err = errors.New(errMsg)
+		return
+	}
+
+	// 分类章节的授权用户
+	typeGrantListMap := make(map[int][]*report.ReportChapterGrant)
+	// 自定义章节列表
+	customAddChapterList := make([]models.AddReportChapter, 0)
+	// 报告继承
+	inheritChapterMap := make(map[int]*models.ReportChapter)
+	if inheritReportId > 0 {
+		// 继承待继承的报告章节内容
+		inheritReportChapters, tmpErr := models.GetChapterListByReportId(inheritReportId)
+		if tmpErr != nil {
+			errMsg = "获取待继承的报告章节失败"
+			err = tmpErr
+			return
+		}
+		reportChaptersIdList := make([]int, 0)
+		for _, v := range inheritReportChapters {
+			reportChaptersIdList = append(reportChaptersIdList, v.ReportChapterId)
+		}
+
+		// 继承的报告章节用户map
+		grantListMap := make(map[int][]*report.ReportChapterGrant)
+		// 授权数据列表
+		if len(reportChaptersIdList) > 0 {
+			obj := report.ReportChapterGrant{}
+			grantList, tmpErr := obj.GetGrantListByIdList(reportChaptersIdList)
+			if tmpErr != nil {
+				errMsg = "获取待继承的报告章节的授权用户列表失败"
+				err = tmpErr
+				return
+			}
+
+			for _, v := range grantList {
+				// 如果不在报告授权的用户ID里面,那么该章节就不继承该授权用户
+				if _, ok := needAdminIdMap[v.AdminId]; !ok {
+					continue
+				}
+
+				currReportChapterId := v.ReportChapterId
+				tmpGrantList, ok := grantListMap[currReportChapterId]
+				if !ok {
+					tmpGrantList = make([]*report.ReportChapterGrant, 0)
+				}
+				v.ReportChapterId = 0
+				v.GrantId = 0
+				tmpGrantList = append(tmpGrantList, v)
+				grantListMap[currReportChapterId] = tmpGrantList
+			}
+		}
+
+		// 继承的报告章节内容
+		for i := 0; i < len(inheritReportChapters); i++ {
+			customChapter := inheritReportChapters[i]
+
+			// 授权用户列表
+			tmpGrantList, ok := grantListMap[customChapter.ReportChapterId]
+			if !ok {
+				tmpGrantList = make([]*report.ReportChapterGrant, 0)
+			}
+			typeGrantListMap[customChapter.TypeId] = tmpGrantList
+
+			// 判断该章节是否是系统章节,如果是的话,那就是需要额外创建的
+			if customChapter.TypeId > 0 {
+				inheritChapterMap[customChapter.TypeId] = customChapter
+				continue
+			}
+
+			// 自定义的报告内容
+			customChapter.ReportId = reportInfo.Id
+			customChapter.ReportChapterId = 0
+			customChapter.ClassifyIdFirst = reportInfo.ClassifyIdFirst
+			customChapter.ClassifyNameFirst = reportInfo.ClassifyNameFirst
+			customChapter.ClassifyIdSecond = reportInfo.ClassifyIdSecond
+			customChapter.ClassifyNameSecond = reportInfo.ClassifyNameSecond
+			customChapter.ClassifyIdThird = reportInfo.ClassifyIdThird
+			customChapter.ClassifyNameThird = reportInfo.ClassifyNameThird
+			customChapter.Stage = reportInfo.Stage
+			customChapter.PublishState = 1
+			customChapter.CreateTime = reportInfo.CreateTime
+			customChapter.ModifyTime = time.Now()
+			customChapter.LastModifyAdminId = reportInfo.LastModifyAdminId
+			customChapter.LastModifyAdminName = reportInfo.LastModifyAdminName
+			customChapter.ContentModifyTime = time.Now()
+
+			customAddChapter := models.AddReportChapter{
+				ReportChapter: customChapter,
+				GrantList:     tmpGrantList,
+			}
+			customAddChapterList = append(customAddChapterList, customAddChapter)
+		}
+	}
+
+	// 最大排序
+	var maxSort int
+	for _, typeItem := range typeList {
+		v := inheritChapterMap[typeItem.ReportChapterTypeId]
+		chapterItem := new(models.ReportChapter)
+		if v != nil {
+			chapterItem.AddType = 2
+			chapterItem.Title = v.Title
+			chapterItem.ReportType = v.ReportType
+			chapterItem.ClassifyIdFirst = reportInfo.ClassifyIdFirst
+			chapterItem.ClassifyNameFirst = reportInfo.ClassifyNameFirst
+			chapterItem.ClassifyIdSecond = reportInfo.ClassifyIdSecond
+			chapterItem.ClassifyNameSecond = reportInfo.ClassifyNameSecond
+			chapterItem.ClassifyIdThird = reportInfo.ClassifyIdThird
+			chapterItem.ClassifyNameThird = reportInfo.ClassifyNameThird
+			chapterItem.TypeId = typeItem.ReportChapterTypeId
+			chapterItem.TypeName = typeItem.ReportChapterTypeName
+			chapterItem.Content = v.Content
+			chapterItem.ContentSub = v.ContentSub
+			chapterItem.Stage = reportInfo.Stage
+			chapterItem.PublishState = 1
+			chapterItem.Sort = typeItem.Sort
+			chapterItem.CreateTime = reportInfo.CreateTime
+			chapterItem.ModifyTime = time.Now()
+
+			chapterItem.LastModifyAdminId = reportInfo.LastModifyAdminId
+			chapterItem.LastModifyAdminName = reportInfo.LastModifyAdminName
+			chapterItem.ContentModifyTime = time.Now()
+			chapterItem.ContentStruct = v.ContentStruct
+			chapterItem.CanvasColor = v.CanvasColor
+			chapterItem.HeadResourceId = v.HeadResourceId
+			chapterItem.EndResourceId = v.EndResourceId
+			chapterItem.CollaborateType = v.CollaborateType
+			chapterItem.ReportLayout = v.ReportLayout
+			chapterItem.ReportCreateTime = time.Now()
+		} else {
+			chapterItem.AddType = 1
+			//chapterItem.ReportType = reportType
+			chapterItem.ClassifyIdFirst = reportInfo.ClassifyIdFirst
+			chapterItem.ClassifyNameFirst = reportInfo.ClassifyNameFirst
+			chapterItem.ClassifyIdSecond = reportInfo.ClassifyIdSecond
+			chapterItem.ClassifyNameSecond = reportInfo.ClassifyNameSecond
+			chapterItem.ClassifyIdThird = reportInfo.ClassifyIdThird
+			chapterItem.ClassifyNameThird = reportInfo.ClassifyNameThird
+			chapterItem.TypeId = typeItem.ReportChapterTypeId
+			chapterItem.TypeName = typeItem.ReportChapterTypeName
+			chapterItem.Stage = reportInfo.Stage
+			chapterItem.PublishState = 1
+			chapterItem.Sort = typeItem.Sort
+			chapterItem.CreateTime = reportInfo.CreateTime
+			chapterItem.ModifyTime = time.Now()
+
+			chapterItem.LastModifyAdminId = reportInfo.LastModifyAdminId
+			chapterItem.LastModifyAdminName = reportInfo.LastModifyAdminName
+			chapterItem.ContentModifyTime = time.Now()
+			//chapterItem.ContentStruct = v.ContentStruct
+			//chapterItem.HeadImg = v.HeadImg
+			//chapterItem.EndImg = v.EndImg
+			//chapterItem.CanvasColor = v.CanvasColor
+			//chapterItem.HeadResourceId = v.HeadResourceId
+			//chapterItem.EndResourceId = v.EndResourceId
+			chapterItem.CollaborateType = reportInfo.CollaborateType
+			chapterItem.ReportLayout = reportInfo.ReportLayout
+			chapterItem.ReportCreateTime = time.Now()
+		}
+
+		if typeItem.Sort > maxSort {
+			maxSort = typeItem.Sort
+		}
+
+		// 授权用户列表
+		tmpGrantList, ok := typeGrantListMap[chapterItem.TypeId]
+		if !ok {
+			tmpGrantList = make([]*report.ReportChapterGrant, 0)
+		}
+		addChapter := models.AddReportChapter{
+			ReportChapter: chapterItem,
+			GrantList:     tmpGrantList,
+		}
+
+		chapterList = append(chapterList, addChapter)
+	}
+
+	// 将自定义的章节内容添加到待生成的章节内容中
+	for _, addChapterItem := range customAddChapterList {
+		maxSort++
+		addChapterItem.ReportChapter.Sort = maxSort
+		chapterList = append(chapterList, addChapterItem)
+	}
+
+	hasGrantUserMap := make(map[int]bool)
+	for _, grantList := range typeGrantListMap {
+		for _, grant := range grantList {
+			if _, ok := hasGrantUserMap[grant.AdminId]; !ok {
+				allGrantUserList = append(allGrantUserList, &report.ReportGrant{
+					//GrantId:      0,
+					//ReportId:     0,
+					AdminId:    grant.AdminId,
+					CreateTime: time.Now(),
+				})
+			}
+		}
+	}
+
+	return
+}
+
+// AddChapterBaseInfoAndPermission
+// @Description:  添加章节基本信息及权限
+// @author: Roc
+// @datetime 2024-06-11 15:35:23
+// @param reportInfo *models.Report
+// @param reportChapterInfo *models.ReportChapter
+// @param permissionIdList []int
+// @param adminIdList []int
+// @return err error
+// @return errMsg string
+func AddChapterBaseInfoAndPermission(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, permissionIdList []int, adminIdList []int) (err error, errMsg string) {
+	errMsg = "新增失败"
+
+	if reportInfo.State == 2 {
+		errMsg = "该报告已发布,不允许编辑"
+		err = errors.New(errMsg)
+		return
+	}
+
+	// 需要添加的报告章节授权数据
+	addChapterAdminList := make([]*report.ReportChapterGrant, 0)
+	for _, adminId := range adminIdList {
+		//新增授权
+		addChapterAdminList = append(addChapterAdminList, &report.ReportChapterGrant{
+			//GrantId:         0,
+			//ReportChapterId: reportChapterInfo.ReportChapterId,
+			AdminId:    adminId,
+			CreateTime: time.Now(),
+		})
+	}
+
+	// 需要添加的报告章节品种权限数据
+	addChapterPermissionList := make([]*report.ReportChapterPermissionMapping, 0)
+	// 品种权限
+	for _, permissionId := range permissionIdList {
+		// 如果不存在,那么就新增品种权限配置
+		addChapterPermissionList = append(addChapterPermissionList, &report.ReportChapterPermissionMapping{
+			//ReportChapterPermissionMappingId:         0,
+			//ReportChapterId:   reportChapterInfo.ReportChapterId,
+			ChartPermissionId: permissionId,
+			CreateTime:        time.Now(),
+		})
+	}
+
+	err = models.AddChapterBaseInfoAndPermission(reportChapterInfo, addChapterAdminList, addChapterPermissionList)
+
+	return
+}
+
+// EditChapterBaseInfoAndPermission
+// @Description: 修改报告章节的基础信息、授权用户权限、品种权限
+// @author: Roc
+// @datetime 2024-06-05 11:49:11
+// @param reportInfo *models.Report
+// @param reportChapterInfo *models.ReportChapter
+// @param title string
+// @param permissionIdList []int
+// @param adminIdList []int
+// @return err error
+// @return errMsg string
+func EditChapterBaseInfoAndPermission(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, title string, permissionIdList []int, adminIdList []int) (err error, errMsg string) {
+	errMsg = "修改失败"
+
+	if reportInfo.State == 2 {
+		errMsg = "该报告已发布,不允许编辑"
+		err = errors.New(errMsg)
+		return
+	}
+
+	updateCols := make([]string, 0)
+	// 如果标题内容,那么就修改
+	if title != `` {
+		reportChapterInfo.Title = title
+		reportChapterInfo.ModifyTime = time.Now()
+		updateCols = append(updateCols, "Title", "ModifyTime")
+		reportChapterInfo.UpdateChapter(updateCols)
+	}
+
+	reportGrantObj := report.ReportGrant{}
+	chapterGrantObj := report.ReportChapterGrant{}
+	chapterPermissionObj := report.ReportChapterPermissionMapping{}
+
+	// 报告授权的用户map
+	reportGrantAdminIdMap := make(map[int]bool)
+	// 获取报告授权的用户信息
+	{
+		// 获取当前报告已经授权的用户信息
+		reportGrantList, tmpErr := reportGrantObj.GetGrantListById(reportInfo.Id)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		for _, v := range reportGrantList {
+			reportGrantAdminIdMap[v.AdminId] = true
+		}
+	}
+
+	// 需要添加的报告章节授权数据
+	addChapterAdminList := make([]*report.ReportChapterGrant, 0)
+	// 待移除的报告章节授权数据id
+	delReportChapterGrantIdList := make([]int, 0)
+
+	// 处理当前报告章节需要新增/移除的授权信息
+	{
+		// 获取当前章节已经授权的用户信息
+		chapterGrantList, tmpErr := chapterGrantObj.GetGrantListById(reportChapterInfo.ReportChapterId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		// 当前章节已经授权的用户信息
+		currChapterAdminMap := make(map[int]*report.ReportChapterGrant)
+		// 需要删除的报告章节授权数据
+		delChapterAdminMap := make(map[int]*report.ReportChapterGrant)
+		for _, v := range chapterGrantList {
+			currChapterAdminMap[v.AdminId] = v
+			delChapterAdminMap[v.AdminId] = v
+		}
+
+		for _, adminId := range adminIdList {
+			// 如果该用户 不在 报告授权的用户map 里面,说明这个用户是要移除的
+			if _, ok := reportGrantAdminIdMap[adminId]; !ok {
+				continue
+			}
+			_, ok := currChapterAdminMap[adminId]
+			// 如果存在,那么从 “需要删除的报告章节授权数据” 的map中移除
+			if ok {
+				delete(delChapterAdminMap, adminId)
+				continue
+			}
+			// 如果不存在,那么就新增授权
+			addChapterAdminList = append(addChapterAdminList, &report.ReportChapterGrant{
+				//GrantId:         0,
+				ReportChapterId: reportChapterInfo.ReportChapterId,
+				AdminId:         adminId,
+				CreateTime:      time.Now(),
+			})
+		}
+
+		// 查出需要移除的授权id
+		for _, v := range delChapterAdminMap {
+			delReportChapterGrantIdList = append(delReportChapterGrantIdList, v.GrantId)
+		}
+	}
+
+	// 其他章节授权的用户
+	otherChapterAdminMap := make(map[int]bool)
+	{
+		// 获取报告所有的章节id
+		reportChapterIdList, tmpErr := models.GetReportChapterIdList(reportInfo.Id)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		if len(reportChapterIdList) > 0 {
+			list, tmpErr := chapterGrantObj.GetGrantListByIdList(reportChapterIdList)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range list {
+				// 如果是当前章节,因为涉及到重新授权,所以得过滤
+				if v.ReportChapterId == reportChapterInfo.ReportChapterId {
+					continue
+				}
+				otherChapterAdminMap[v.AdminId] = true
+			}
+		}
+	}
+
+	// 需要添加的报告章节品种权限数据
+	addChapterPermissionList := make([]*report.ReportChapterPermissionMapping, 0)
+	// 待移除的报告章节品种权限数据id
+	delChapterPermissionMappingIdList := make([]int, 0)
+
+	// 处理当前报告章节需要新增/移除的品种权限信息
+	{
+		// 获取当前章节已经配置的品种权限信息
+		chapterPermissionList, tmpErr := chapterPermissionObj.GetPermissionListById(reportChapterInfo.ReportChapterId)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		// 当前章节已经配置的品种权限信息
+		currChapterPermissionMap := make(map[int]*report.ReportChapterPermissionMapping)
+		// 需要删除的报告章节品种权限配置
+		delChapterPermissionMap := make(map[int]*report.ReportChapterPermissionMapping)
+		for _, v := range chapterPermissionList {
+			currChapterPermissionMap[v.ChartPermissionId] = v
+			delChapterPermissionMap[v.ChartPermissionId] = v
+		}
+
+		for _, permissionId := range permissionIdList {
+			_, ok := currChapterPermissionMap[permissionId]
+			// 如果存在,那么从 “需要删除的报告章节品种权限配置” 的map中移除
+			if ok {
+				delete(delChapterPermissionMap, permissionId)
+				continue
+			}
+			// 如果不存在,那么就新增品种权限配置
+			addChapterPermissionList = append(addChapterPermissionList, &report.ReportChapterPermissionMapping{
+				//ReportChapterPermissionMappingId:         0,
+				ReportChapterId:   reportChapterInfo.ReportChapterId,
+				ChartPermissionId: permissionId,
+				CreateTime:        time.Now(),
+			})
+		}
+
+		// 查出需要移除的品种权限配置
+		for _, v := range delChapterPermissionMap {
+			delChapterPermissionMappingIdList = append(delChapterPermissionMappingIdList, v.ReportChapterPermissionMappingId)
+		}
+	}
+
+	err = models.EditChapterBaseInfoAndPermission(reportChapterInfo, updateCols, addChapterAdminList, addChapterPermissionList, delReportChapterGrantIdList, delChapterPermissionMappingIdList)
+
+	return
+}
+
+// DelChapter
+// @Description: 删除报告章节、授权用户权限、品种权限
+// @author: Roc
+// @datetime 2024-06-06 17:28:37
+// @param reportInfo *models.Report
+// @param reportChapterInfo *models.ReportChapter
+// @param sysUser *system.Admin
+// @return err error
+// @return errMsg string
+func DelChapter(reportInfo *models.Report, reportChapterInfo *models.ReportChapter, sysUser *system.Admin) (err error, errMsg string) {
+	errMsg = "删除失败"
+	if reportInfo.State == 2 {
+		errMsg = "该报告已发布,不允许删除"
+		err = errors.New(errMsg)
+		return
+	}
+
+	reportInfo.LastModifyAdminId = sysUser.AdminId
+	reportInfo.LastModifyAdminName = sysUser.RealName
+	reportInfo.ModifyTime = time.Now()
+	updateReportCols := []string{"LastModifyAdminId", "LastModifyAdminName", "ModifyTime"}
+	err = models.DelChapterAndPermission(reportInfo, updateReportCols, reportChapterInfo)
+
+	return
+}

+ 106 - 0
services/sandbox/sandbox.go

@@ -7,9 +7,11 @@ import (
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/sandbox/request"
 	"eta/eta_api/models/system"
+	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
 	"fmt"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -599,6 +601,27 @@ type ContentStruct struct {
 	} `json:"cells"`
 }
 
+type SendBoxNodeData struct {
+	linkData []SandBoxLinkData `json:"linkData"`
+	linkFold bool              `json:"linkFold"`
+}
+
+type SandBoxLinkData struct {
+	RId          string              `json:"RId"`
+	Id           int                 `json:"Id"`
+	Name         string              `json:"Name"`
+	Type         int                 `json:"Type"`
+	Editing      bool                `json:"editing"`
+	DatabaseType int                 `json:"databaseType"`
+	DetailParams SandBoxDetailParams `json:"detailParams"`
+}
+
+type SandBoxDetailParams struct {
+	Code       string `json:"code"`
+	Id         int    `json:"id"`
+	ClassifyId int    `json:"classifyId"`
+}
+
 // checkoutContent 校验内容是否变更
 func checkoutContent(oldContent, reqContent string) (isUpdate bool) {
 	defer func() {
@@ -852,3 +875,86 @@ func sandboxClassifyHaveChildV2(allNode []*sandbox.SandboxClassifyItems, node *s
 	}
 	return
 }
+
+func ReplaceEdbInSandbox(oldEdbInfoId, newEdbInfoId int) (err error) {
+	updateTotal := 0
+	logMsg := ""
+	//分页处理沙盘表
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg("替换沙盘中的指标记录失败提醒,errmsg:"+err.Error(), 3)
+		}
+		if logMsg != "" {
+			utils.FileLog.Info(fmt.Sprintf("替换ETA逻辑的指标记录,替换总数:%d,旧的指标id:%d,新的指标id:%d;%s", updateTotal, oldEdbInfoId, newEdbInfoId, logMsg))
+		}
+	}()
+	//查询沙盘总数
+	total, err := sandbox.GetSandboxListCountByCondition("", []interface{}{})
+	if err != nil {
+		err = fmt.Errorf("查询沙盘总数失败 Err:%s", err)
+		return
+	}
+
+	// 根据沙盘列表总数,分页查询
+	// 计算总页数
+	totalPage := (total + 99) / 100 // 使用整数除法,并添加一页以防有余数
+	updateSandBox := make([]sandbox.Sandbox, 0)
+
+	//查询沙盘列表
+	for i := 0; i < totalPage; i += 1 {
+		startSize := i * 100
+		list, e := sandbox.GetSandboxListByCondition("", []interface{}{}, startSize, 100)
+		if e != nil {
+			err = fmt.Errorf("查询沙盘列表失败 Err:%s", e)
+			return
+		}
+		for _, v := range list {
+			sandOldEdbId := fmt.Sprintf(`"RId":"1-%d","Id":%d,`, oldEdbInfoId, oldEdbInfoId)
+			if strings.Contains(v.Content, sandOldEdbId) {
+				sandNewEdbId := fmt.Sprintf(`"RId":"1-%d","Id":%d,`, newEdbInfoId, newEdbInfoId)
+				v.Sandbox.Content = strings.ReplaceAll(v.Content, sandOldEdbId, sandNewEdbId)
+				updateSandBox = append(updateSandBox, v.Sandbox)
+				logMsg += `涉及到的逻辑id:` + strconv.Itoa(v.Sandbox.SandboxId) + ";"
+				if len(updateSandBox) > 100 {
+					err = sandbox.UpdateSandboxContent(updateSandBox)
+					if err != nil {
+						err = fmt.Errorf("更新沙盘表失败 Err:%s", err)
+						return
+					}
+					updateTotal += len(updateSandBox)
+					updateSandBox = make([]sandbox.Sandbox, 0)
+				}
+			}
+		}
+	}
+	if len(updateSandBox) > 0 {
+		err = sandbox.UpdateSandboxContent(updateSandBox)
+		if err != nil {
+			err = fmt.Errorf("更新沙盘表失败 Err:%s", err)
+			return
+		}
+		updateTotal += len(updateSandBox)
+	}
+	return
+}
+
+func GetSandBoxEdbIdsByContent(content string) (edbInfoIds []int, err error) {
+	var contentInfo sandbox.ContentDataStruct
+	err = json.Unmarshal([]byte(content), &contentInfo)
+	if err != nil {
+		err = fmt.Errorf("json.Unmarshal err:%s", err.Error())
+		return
+	}
+	// 遍历所有节点
+	for _, node := range contentInfo.Cells {
+		if node.Data == nil {
+			continue
+		}
+		for _, v := range node.Data.LinkData {
+			if v.Type == 1 {
+				edbInfoIds = append(edbInfoIds, v.Id)
+			}
+		}
+	}
+	return
+}

+ 2 - 0
services/smart_report.go

@@ -158,6 +158,8 @@ def main():
         'waitUntil': 'networkidle0',
         'timeout': 1000000  # 设置超时时间为 100 秒
     })
+	# 等待3秒
+    yield from asyncio.sleep(3)
     yield from page.pdf({
         'path': "%s",
         'printBackground': True,

+ 5 - 2
services/task.go

@@ -40,8 +40,11 @@ func Task() {
 
 	go AutoInsertAdminOperateRecordToDB()
 
-	// 测试用-生成bloomberg数据
-	//go InsertBloombergIndex()
+	// 指标刷新
+	go data.HandleEdbRefreshQueue()
+
+	// 进行指标替换操作
+	go DealReplaceEdbCache()
 
 	// TODO:修复权限
 	//FixEnCompanyPermission()

+ 19 - 18
services/user_login.go

@@ -252,24 +252,24 @@ func LdapUserCheck(userName, password string) (pass bool, err error) {
 // @return err error
 // @return errMsg string
 func ThirdLogin(req map[string]interface{}) (data GetCrmTokenData, err error, errMsg string) {
-	if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox {
-		authCode, ok := req["code"]
-		if !ok {
-			errMsg = "参数有误"
-			err = errors.New("参数缺失, code")
-			return
-		}
-		authCodeStr := fmt.Sprint(authCode)
-		if authCodeStr == "" {
-			errMsg = "参数有误"
-			err = errors.New("参数缺失, AuthCode")
-			return
-		}
-
-		data, err = CodeLoginFromMiddleServer(authCodeStr)
-
-		return
-	}
+	//if utils.BusinessCode == utils.BusinessCodeRelease || utils.BusinessCode == utils.BusinessCodeSandbox || utils.BusinessCode == utils.BusinessCodeDebug {
+	//	authCode, ok := req["code"]
+	//	if !ok {
+	//		errMsg = "参数有误"
+	//		err = errors.New("参数缺失, code")
+	//		return
+	//	}
+	//	authCodeStr := fmt.Sprint(authCode)
+	//	if authCodeStr == "" {
+	//		errMsg = "参数有误"
+	//		err = errors.New("参数缺失, AuthCode")
+	//		return
+	//	}
+	//
+	//	data, err = CodeLoginFromMiddleServer(authCodeStr)
+	//
+	//	return
+	//}
 
 	data, err, errMsg = ThirdCodeLoginFromMiddleServer(req)
 
@@ -287,6 +287,7 @@ func ThirdLogin(req map[string]interface{}) (data GetCrmTokenData, err error, er
 // @return err error
 func ThirdCodeLoginFromMiddleServer(param map[string]interface{}) (tokenResp GetCrmTokenData, err error, errMsg string) {
 	if utils.EtaBridgeUrl == `` || utils.EtaBridgeLoginUrl == "" {
+
 		errMsg = `未配置第三方登录的桥接服务地址`
 		err = errors.New(errMsg)
 		return

+ 3 - 1
services/video.go

@@ -310,6 +310,8 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 		time.Sleep(5 * time.Second)
 	}
 
+	fmt.Println("savePath:" + savePath)
+
 	//上传到阿里云 和 minio
 	//if utils.ObjectStorageClient == "minio" {
 	//	uploadUrl, err = UploadAudioToMinIo(saveName, savePath)
@@ -351,7 +353,7 @@ func CreateReportVideo(reportTitle, reportContent, reportTime string) (uploadUrl
 
 	if playSeconds > 0 {
 		if utils.FileIsExist(savePath) {
-			os.Remove(savePath)
+			//os.Remove(savePath)
 		}
 	}
 

+ 8 - 1
static/ErrMsgConfig.json

@@ -50,5 +50,12 @@
   "系统处理中,请稍后重试!": "The system is processing, please try again later!",
   "固定日期不可为空": "The fixed date cannot be empty",
   "日期数量已达上限!": "The number of dates has reached the limit!",
-  "该品种已在指标库生成指标,不可删除": "This variety has already generated indicators in the index library and cannot be deleted"
+  "该品种已在指标库生成指标,不可删除": "This variety has already generated indicators in the index library and cannot be deleted",
+  "当前指标已用作画图,不可删除": "The current metric is in use for charting and cannot be deleted",
+  "当前指标已被表格引用,不可删除":"The current metric is referenced by a table and cannot be deleted",
+  "当前指标已用作指标运算,不可删除": "The current metric is used in metric calculations and cannot be deleted.",
+  "当前指标已用作预测指标,不可删除": "The current metric is used as a forecasting indicator and cannot be deleted.",
+  "当前指标已添加到跨品种分析,不可删除": "The current metric has been added to cross-commodity analysis and cannot be deleted.",
+  "指标已删除,请刷新页面": "Metric deleted, please refresh the page.",
+  "删除失败": "Deletion failed."
 }

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini