Browse Source

Merge branch 'debug' into bzq1/admin_conflict

zqbao 10 months ago
parent
commit
cce5b28aa9
84 changed files with 6119 additions and 856 deletions
  1. 1 2
      .gitignore
  2. 10 1
      controllers/ai/ai_file.go
  3. 60 0
      controllers/data_manage/chart_common.go
  4. 18 2
      controllers/data_manage/chart_info.go
  5. 6 2
      controllers/data_manage/chart_theme.go
  6. 7 7
      controllers/data_manage/data_manage_permission/data_manage_permission.go
  7. 4 4
      controllers/data_manage/data_manage_permission/data_move.go
  8. 19 0
      controllers/data_manage/edb_info.go
  9. 8 2
      controllers/data_manage/edb_info_calculate.go
  10. 1277 0
      controllers/data_manage/excel/balance_table.go
  11. 5 0
      controllers/data_manage/excel/excel_classify.go
  12. 198 66
      controllers/data_manage/excel/excel_info.go
  13. 13 2
      controllers/data_manage/predict_edb_info.go
  14. 6 2
      controllers/data_source/icpi.go
  15. 0 1
      controllers/english_report/report.go
  16. 116 11
      controllers/ppt_english.go
  17. 11 1
      controllers/ppt_english_group.go
  18. 111 4
      controllers/ppt_v2.go
  19. 11 1
      controllers/ppt_v2_group.go
  20. 3 3
      controllers/sys_team.go
  21. 41 6
      controllers/target.go
  22. 1 1
      go.mod
  23. 2 3
      go.sum
  24. 1 2
      models/business_conf.go
  25. 8 0
      models/chart_permission.go
  26. 3 2
      models/data_manage/base_from_trade_index.go
  27. 164 75
      models/data_manage/chart_info.go
  28. 15 0
      models/data_manage/chart_theme/chart_theme_type.go
  29. 15 5
      models/data_manage/edb_data_base.go
  30. 24 4
      models/data_manage/edb_info.go
  31. 2 0
      models/data_manage/edb_info_calculate.go
  32. 28 0
      models/data_manage/edb_info_record.go
  33. 44 0
      models/data_manage/excel/excel_chart_data.go
  34. 333 0
      models/data_manage/excel/excel_chart_edb.go
  35. 119 44
      models/data_manage/excel/excel_info.go
  36. 74 0
      models/data_manage/excel/excel_worker.go
  37. 76 0
      models/data_manage/excel/request/balance_table.go
  38. 23 1
      models/data_manage/excel/request/excel_info.go
  39. 44 30
      models/data_manage/excel/response/excel_info.go
  40. 17 17
      models/data_manage/excel/response/sheet.go
  41. 15 4
      models/data_manage/my_chart.go
  42. 11 5
      models/db.go
  43. 4 1
      models/ppt_english/ppt_english.go
  44. 3 1
      models/ppt_english/ppt_english_grant.go
  45. 3 1
      models/ppt_english/ppt_english_group.go
  46. 19 1
      models/ppt_english/ppt_english_group_mapping.go
  47. 4 1
      models/ppt_v2.go
  48. 3 1
      models/ppt_v2_grant.go
  49. 3 1
      models/ppt_v2_group.go
  50. 13 3
      models/ppt_v2_group_mapping.go
  51. 1 0
      models/report.go
  52. 114 6
      routers/commentsRouter.go
  53. 20 12
      routers/router.go
  54. 135 9
      services/data/chart_info.go
  55. 1533 0
      services/data/chart_info_excel_balance.go
  56. 30 0
      services/data/chart_info_interface.go
  57. 4 0
      services/data/data_manage_permission/data_move.go
  58. 7 1
      services/data/data_manage_permission/edb_permission.go
  59. 27 0
      services/data/data_manage_permission/excel.go
  60. 30 18
      services/data/edb_info.go
  61. 0 287
      services/data/edb_info_calculate.go
  62. 30 0
      services/data/edb_info_record.go
  63. 105 0
      services/data/edb_refresh.go
  64. 452 0
      services/data/excel/balance_table.go
  65. 80 22
      services/data/excel/excel_info.go
  66. 49 2
      services/data/excel/excel_op.go
  67. 58 14
      services/data/future_good/chart_info.go
  68. 4 2
      services/data/future_good/profit_chart_info.go
  69. 1 0
      services/elastic.go
  70. 182 48
      services/elastic/elastic.go
  71. 23 0
      services/eta_forum/eta_forum_hub.go
  72. 10 0
      services/eta_forum/eta_forum_hub_lib.go
  73. 31 35
      services/excel/lucky_sheet.go
  74. 49 1
      services/ppt/ppt_english_group.go
  75. 47 0
      services/ppt/ppt_group.go
  76. 15 0
      services/report.go
  77. 2 0
      services/smart_report.go
  78. 2 2
      services/task.go
  79. 19 18
      services/user_login.go
  80. 3 1
      services/video.go
  81. 44 44
      utils/common.go
  82. 13 13
      utils/config.go
  83. 2 0
      utils/constants.go
  84. 1 1
      utils/logs.go

+ 1 - 2
.gitignore

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

+ 10 - 1
controllers/ai/ai_file.go

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

+ 60 - 0
controllers/data_manage/chart_common.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"encoding/json"
 	"eta/eta_api/controllers/data_manage/correlation"
 	"eta/eta_api/controllers/data_manage/cross_variety"
 	"eta/eta_api/controllers/data_manage/future_good"
@@ -8,7 +9,12 @@ import (
 	"eta/eta_api/controllers/data_manage/line_feature"
 	"eta/eta_api/models"
 	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	"eta/eta_api/services/data/excel"
 	"eta/eta_api/utils"
+	"fmt"
+	"time"
 )
 
 // CommonChartInfoDetailFromUniqueCode
@@ -150,9 +156,63 @@ func (this *ChartInfoController) CommonChartInfoDetailFromUniqueCode() {
 		br.Success = true
 		br.Msg = "获取成功"
 		br.Data = resp
+	case utils.CHART_SOURCE_BALANCE_EXCEL:
+		resp, isOk, msg, errMsg := getBalanceChartInfoDetailFromUniqueCode(chartInfo, isCache, sysUser)
+		if !isOk {
+			br.Msg = msg
+			br.ErrMsg = errMsg
+			return
+		}
+		br.Ret = 200
+		br.Success = true
+		br.Msg = "获取成功"
+		br.Data = resp
 	default:
 		br.Msg = "错误的图表"
 		br.ErrMsg = "错误的图表"
 		return
 	}
 }
+
+func getBalanceChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	resp = new(data_manage.ChartInfoDetailFromUniqueCodeResp)
+	resp, isOk, msg, errMsg = data.CheckBalanceChartCacheAndPermission(chartInfo, isCache, sysUser)
+	if isOk {
+		return
+	}
+	msg = `获取失败`
+	// 相关联指标
+	mappingListTmp, dataListMap, err, errMsg := excel.GetBalanceExcelChartSingle(chartInfo, "")
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	var chartInfoResp *data_manage.ChartInfoDetailResp
+	chartInfoResp, err, errMsg = data.GetBalanceExcelChartDetail(chartInfo, mappingListTmp, sysUser, dataListMap)
+	if err != nil {
+		msg = "查询图表详情失败"
+		errMsg = "查询图表详情失败,Err:" + err.Error()
+		return
+	}
+	resp = &data_manage.ChartInfoDetailFromUniqueCodeResp{
+		ChartInfo:            chartInfoResp.ChartInfo,
+		Status:               true,
+		EdbInfoList:          chartInfoResp.EdbInfoList,
+		XEdbIdValue:          chartInfoResp.XEdbIdValue,
+		YDataList:            chartInfoResp.YDataList,
+		XDataList:            chartInfoResp.XDataList,
+		BarChartInfo:         chartInfoResp.BarChartInfo,
+		CorrelationChartInfo: chartInfoResp.CorrelationChartInfo,
+		DataResp:             chartInfoResp.DataResp,
+	}
+	// 将数据加入缓存
+	if utils.Re == nil {
+		cacheData, _ := json.Marshal(resp)
+		key := data.GetChartInfoDataKey(chartInfo.ChartInfoId)
+		utils.Rc.Put(key, cacheData, 2*time.Hour)
+	}
+	isOk = true
+
+	return
+}

+ 18 - 2
controllers/data_manage/chart_info.go

@@ -2919,6 +2919,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)
@@ -2929,7 +2937,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)
@@ -3441,9 +3449,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,

+ 6 - 2
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 = "获取成功"
@@ -475,7 +479,7 @@ func (c *ChartThemeController) Delete() {
 		br.ErrMsg = "删除失败,Err:" + err.Error()
 		return
 	}
-
+	go eta_forum.ChartThemeSave(chartTheme)
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "删除成功"
@@ -564,7 +568,7 @@ func (c *ChartThemeController) SetDefaultTheme() {
 		br.ErrMsg = "配置失败,Err:" + err.Error()
 		return
 	}
-
+	go eta_forum.ChartThemeTypeSave(chartThemeType)
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "配置成功"

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

@@ -51,7 +51,7 @@ func (c *DataMangePermissionController) SetEdbChartPermission() {
 	}
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
-	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -114,7 +114,7 @@ func (c *DataMangePermissionController) SetPermissionEdbChartClassifyIsPermissio
 	}
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
-	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -172,7 +172,7 @@ func (c *DataMangePermissionController) SetEdbChartClassifyPermission() {
 	}
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
-	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -231,7 +231,7 @@ func (c *DataMangePermissionController) GetEdbChartPermission() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -290,7 +290,7 @@ func (c *DataMangePermissionController) GetEdbChartClassifyPermission() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -306,7 +306,7 @@ func (c *DataMangePermissionController) GetEdbChartClassifyPermission() {
 	}
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -364,7 +364,7 @@ func (c *DataMangePermissionController) GetEdbChartNoPermission() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return

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

@@ -40,7 +40,7 @@ func (c *DataMangePermissionController) EdbChartClassifyList() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -90,7 +90,7 @@ func (c *DataMangePermissionController) SecretEdbChartClassifyList() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -163,7 +163,7 @@ func (c *DataMangePermissionController) MoveEdbChartList() {
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
 	subSource, _ := c.GetInt("SubSource")
-	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if source == 6 && (subSource <= utils.EXCEL_DEFAULT || subSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return
@@ -254,7 +254,7 @@ func (c *DataMangePermissionController) MoveEdbChartUser() {
 	}
 
 	// 子来源(目前作用于ETA表格,2024-3-26 14:12:09)
-	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.CUSTOM_ANALYSIS_TABLE) {
+	if req.Source == 6 && (req.SubSource <= utils.EXCEL_DEFAULT || req.SubSource > utils.BALANCE_TABLE) {
 		br.Msg = "错误的子来源"
 		br.IsSendEmail = false
 		return

+ 19 - 0
controllers/data_manage/edb_info.go

@@ -2384,6 +2384,11 @@ func (this *EdbInfoController) EdbInfoEdit() {
 		return
 	}
 
+	// 记录旧的指标基本信息
+	oldEdbName := edbInfo.EdbName
+	oldFrequency := edbInfo.Frequency
+	oldUnit := edbInfo.Unit
+
 	var haveOperaAuth bool
 	// 权限校验
 	{
@@ -2477,6 +2482,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)

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

+ 1277 - 0
controllers/data_manage/excel/balance_table.go

@@ -0,0 +1,1277 @@
+package excel
+
+import (
+	"encoding/json"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/excel"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/models/data_manage/excel/response"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	"eta/eta_api/services/data/data_manage_permission"
+	excelService "eta/eta_api/services/data/excel"
+	etaTrialService "eta/eta_api/services/eta_trial"
+	"eta/eta_api/utils"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// GetChildTable
+// @Title 获取子表
+// @Description 获取子表
+// @Param	request	body request.MixedTableCellDataReq true "type json string"
+// @router /excel_info/child_table [get]
+func (c *ExcelInfoController) GetChildTable() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	parentId, _ := c.GetInt("ParentId")
+	if parentId <= 0 {
+		br.Msg = "请选择父表"
+		return
+	}
+	list := make([]*excel.ExcelInfo, 0)
+	// 查询所有子表
+	childList, err := excel.GetChildExcelInfoByParentId(parentId)
+	if err != nil {
+		br.Msg = "查询子表失败"
+		return
+	}
+	if len(childList) > 0 {
+		list = childList
+	}
+
+	resp := &response.BalanceChildTableResp{List: list}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = resp
+}
+
+// Rename
+// @Title 表格重命名接口
+// @Description 表格重命名接口
+// @Param	request	body request.EditExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/rename [post]
+func (c *ExcelInfoController) Rename() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.RenameExcelInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ExcelInfoId <= 0 {
+		br.Msg = "请传入ETA表格标识!"
+		return
+	}
+
+	req.ExcelName = strings.Trim(req.ExcelName, " ")
+	if req.ExcelName == "" {
+		br.Msg = "请填写表格名称!"
+		br.IsSendEmail = false
+		return
+	}
+
+	excelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
+		return
+	}
+	//判断表格是否存在
+	var condition string
+	var pars []interface{}
+	condition += " AND excel_info_id != ? AND excel_classify_id=? AND excel_name=?  AND parent_id=?"
+	pars = append(pars, req.ExcelInfoId, excelInfo.ExcelClassifyId, req.ExcelName, excelInfo.ParentId)
+
+	// 获取分类下是否存在该表格名称
+	count, err := excel.GetExcelInfoCountByCondition(condition, pars)
+	if err != nil {
+		br.Msg = "ETA判断表格名称是否存在失败"
+		br.ErrMsg = "判断ETA表格名称是否存在失败,Err:" + err.Error()
+		return
+	}
+	if count > 0 {
+		br.Msg = "ETA表格名称已存在,请重新填写"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		if excelInfo.Source == utils.BALANCE_TABLE {
+			checkExcelInfoId := excelInfo.ExcelInfoId
+			if excelInfo.BalanceType == 1 {
+				checkExcelInfoId = excelInfo.RelExcelInfoId
+			} else {
+				if excelInfo.ParentId > 0 {
+					checkExcelInfoId = excelInfo.ParentId
+				}
+			}
+			if checkExcelInfoId != excelInfo.ExcelInfoId {
+				checkExcelInfo, err = excel.GetExcelInfoById(checkExcelInfoId)
+				if err != nil {
+					br.Msg = "获取平衡表格信息失败"
+					br.ErrMsg = "获取平衡表格信息失败,Err:" + err.Error()
+					return
+				}
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if e != nil {
+			br.Msg = "获取ETA表格权限失败"
+			br.ErrMsg = "获取表格权限信息失败,Err" + e.Error()
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	excelInfo.ModifyTime = time.Now()
+	excelInfo.ExcelName = req.ExcelName
+	excelInfo.UpdateUserId = sysUser.AdminId
+	excelInfo.UpdateUserRealName = sysUser.RealName
+	// 自动保存时不会传缩略图,也就不更新这个字段
+	updateExcelInfoParams := []string{"ModifyTime", "ExcelName", "UpdateUserId", "UpdateUserRealName"}
+
+	err = excelInfo.Update(updateExcelInfoParams)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	resp := response.AddExcelInfoResp{
+		ExcelInfoId: excelInfo.ExcelInfoId,
+		UniqueCode:  excelInfo.UniqueCode,
+	}
+
+	//删除公共图库那边的缓存
+	_ = utils.Rc.Delete(utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + excelInfo.UniqueCode)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "修改成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// SaveExcelWorker
+// @Title 新增编辑表格协作人接口
+// @Description 新增编辑表格协作人接口
+// @Param	request	body request.EditExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/worker/save [post]
+func (c *ExcelInfoController) SaveExcelWorker() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.SaveExcelInfoWorkerReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ExcelInfoId <= 0 {
+		br.Msg = "请传入ETA表格标识!"
+		return
+	}
+
+	excelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
+		return
+	}
+	if excelInfo.SysUserId != sysUser.AdminId {
+		br.Msg = "您没有权限操作!"
+		br.ErrMsg = "您没有权限操作!"
+		return
+	}
+	// 操作权限校验, 增加协作人判断
+	{
+		// 数据权限
+		haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(excelInfo.ExcelInfoId, excelInfo.ExcelClassifyId, excelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if err != nil {
+			br.Msg = "获取ETA表格失败"
+			br.ErrMsg = "获取ETA表格权限失败,Err:" + err.Error()
+			return
+		}
+		button := excelService.GetExcelInfoOpButton(sysUser, excelInfo.SysUserId, excelInfo.Source, haveOperaAuth)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	obj := new(excel.ExcelWorker)
+	notDeleteWorkerIds := make([]string, 0)
+	workerMap := make(map[int]struct{})
+	if req.SysUserIds != "" {
+		notDeleteWorkerIds = strings.Split(req.SysUserIds, ",")
+	}
+	existList, err := obj.GetByExcelInfoId(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取表格协作人失败!"
+		br.ErrMsg = "获取表格协作人失败,Err:" + err.Error()
+		return
+	}
+	for _, v := range existList {
+		workerMap[v.SysUserId] = struct{}{}
+	}
+	addIds := make([]int, 0)
+	for _, v := range notDeleteWorkerIds {
+		id, _ := strconv.Atoi(v)
+		if _, ok := workerMap[id]; !ok {
+			addIds = append(addIds, id)
+		}
+	}
+	// 查询协作人姓名
+	adminList, err := system.GetAdminListByIdListWithoutEnable(addIds)
+	addList := make([]*excel.ExcelWorker, 0)
+	for _, v := range adminList {
+		addList = append(addList, &excel.ExcelWorker{
+			ExcelInfoId:     req.ExcelInfoId,
+			SysUserId:       v.AdminId,
+			SysUserRealName: v.RealName,
+			CreateTime:      time.Now(),
+			ModifyTime:      time.Now(),
+		})
+	}
+	// 保存协作人
+	err = obj.AddWorker(req.ExcelInfoId, addList, notDeleteWorkerIds)
+	if err != nil {
+		br.Msg = "保存失败"
+		br.ErrMsg = "保存失败,Err:" + err.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// GetWorker
+// @Title 查询协作人接口
+// @Description 新增编辑表格协作人接口
+// @Param	request	body request.EditExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/worker [get]
+func (c *ExcelInfoController) GetWorker() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	excelInfoId, _ := c.GetInt("ExcelInfoId")
+	if excelInfoId <= 0 {
+		br.Msg = "请选择表格"
+		br.ErrMsg = "ExcelInfoId未传"
+		br.IsSendEmail = false
+		return
+	}
+
+	obj := new(excel.ExcelWorker)
+
+	list, err := obj.GetByExcelInfoId(excelInfoId)
+	if err != nil {
+		br.Msg = "获取表格协作人失败!"
+		br.ErrMsg = "获取表格协作人失败,Err:" + err.Error()
+		return
+	}
+	ret := &response.BalanceTableWorkerResp{List: list}
+	br.Data = ret
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// BalanceChartInfoAdd
+// @Title 新增图表接口
+// @Description 新增图表接口
+// @Param	request	body data_manage.AddChartInfoReq true "type json string"
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /excel_info/balance/chart_add [post]
+func (c *ExcelInfoController) BalanceChartInfoAdd() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	deleteCache := true
+	cacheKey := "CACHE_EXCEL_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		return
+	}
+	var req request.AddBalanceTableChartReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	req.ChartName = strings.Trim(req.ChartName, " ")
+	if req.ChartName == "" {
+		br.Msg = "请填写图表名称!"
+		return
+	}
+	// 获取表格信息
+	excelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		return
+	}
+
+	if excelInfo.Source != utils.BALANCE_TABLE {
+		br.Msg = "EXCEL类型错误!"
+		return
+	}
+	// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		if excelInfo.Source == utils.BALANCE_TABLE {
+			checkExcelInfoId := excelInfo.ExcelInfoId
+			if excelInfo.BalanceType == 1 {
+				checkExcelInfoId = excelInfo.RelExcelInfoId
+			} else {
+				if excelInfo.ParentId > 0 {
+					checkExcelInfoId = excelInfo.ParentId
+				}
+			}
+			if checkExcelInfoId != excelInfo.ExcelInfoId {
+				checkExcelInfo, err = excel.GetExcelInfoById(checkExcelInfoId)
+				if err != nil {
+					br.Msg = "获取平衡表格信息失败"
+					br.ErrMsg = "获取平衡表格信息失败,Err:" + err.Error()
+					return
+				}
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if e != nil {
+			br.Msg = "获取ETA表格权限失败"
+			br.ErrMsg = "获取表格权限信息失败,Err" + e.Error()
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	chartInfo, err, errMsg, isSendEmail := data.AddBalanceExcelChart(excelInfo, req, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartInfo.ChartInfoId
+	resp.UniqueCode = chartInfo.UniqueCode
+	resp.ChartType = req.ChartType
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartInfoId = chartInfo.ChartInfoId
+		chartLog.ChartName = req.ChartName
+		chartLog.ChartClassifyId = 0
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartInfo.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "新增图表"
+		chartLog.Method = c.Ctx.Input.URI()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	// 试用平台更新用户累计新增图表数
+	adminItem, e := system.GetSysAdminById(sysUser.AdminId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取系统用户数据失败,Err:" + err.Error()
+		return
+	}
+	if utils.BusinessCode == utils.BusinessCodeSandbox && adminItem.DepartmentName == "ETA试用客户" {
+		go func() {
+			var r etaTrialService.EtaTrialUserReq
+			r.Mobile = adminItem.Mobile
+			_, _ = etaTrialService.UpdateUserChartNum(r)
+		}()
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// BalanceChartInfoEdit
+// @Title 编辑图表接口
+// @Description 新增图表接口
+// @Param	request	body data_manage.AddChartInfoReq true "type json string"
+// @Success 200 {object} data_manage.AddChartInfoResp
+// @router /excel_info/balance/chart_edit [post]
+func (c *ExcelInfoController) BalanceChartInfoEdit() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	deleteCache := true
+	cacheKey := "CACHE_EXCEL_CHART_INFO_ADD_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(c.Ctx.Input.RequestBody)
+		return
+	}
+	var req request.AddBalanceTableChartReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	req.ChartName = strings.Trim(req.ChartName, " ")
+	if req.ChartName == "" {
+		br.Msg = "请填写图表名称!"
+		return
+	}
+	if req.ChartInfoId <= 0 {
+		br.Msg = "请选择图表"
+		return
+	}
+	// 获取表格信息
+	excelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		return
+	}
+
+	if excelInfo.Source != utils.BALANCE_TABLE {
+		br.Msg = "EXCEL类型错误!"
+		return
+	}
+	// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		if excelInfo.Source == utils.BALANCE_TABLE {
+			checkExcelInfoId := excelInfo.ExcelInfoId
+			if excelInfo.BalanceType == 1 {
+				checkExcelInfoId = excelInfo.RelExcelInfoId
+			} else {
+				if excelInfo.ParentId > 0 {
+					checkExcelInfoId = excelInfo.ParentId
+				}
+			}
+			if checkExcelInfoId != excelInfo.ExcelInfoId {
+				checkExcelInfo, err = excel.GetExcelInfoById(checkExcelInfoId)
+				if err != nil {
+					br.Msg = "获取平衡表格信息失败"
+					br.ErrMsg = "获取平衡表格信息失败,Err:" + err.Error()
+					return
+				}
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if e != nil {
+			br.Msg = "获取ETA表格权限失败"
+			br.ErrMsg = "获取表格权限信息失败,Err" + e.Error()
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	chartItem, err, errMsg, isSendEmail := data.EditBalanceExcelChart(excelInfo, req, sysUser)
+	if err != nil {
+		br.Msg = "保存失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	resp := new(data_manage.AddChartInfoResp)
+	resp.ChartInfoId = chartItem.ChartInfoId
+	resp.UniqueCode = chartItem.UniqueCode
+	resp.ChartType = req.ChartType
+
+	//新增操作日志
+	{
+		chartLog := new(data_manage.ChartInfoLog)
+		chartLog.ChartName = chartItem.ChartName
+		chartLog.ChartInfoId = req.ChartInfoId
+		chartLog.ChartClassifyId = chartItem.ChartClassifyId
+		chartLog.SysUserId = sysUser.AdminId
+		chartLog.SysUserRealName = sysUser.RealName
+		chartLog.UniqueCode = chartItem.UniqueCode
+		chartLog.CreateTime = time.Now()
+		chartLog.Content = string(c.Ctx.Input.RequestBody)
+		chartLog.Status = "编辑图表"
+		chartLog.Method = c.Ctx.Input.URL()
+		go data_manage.AddChartInfoLog(chartLog)
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// GetBalanceChartList
+// @Title 获取平衡表表关联的图表
+// @Description 获取平衡表表关联的图表
+// @Param	request	body request.MixedTableCellDataReq true "type json string"
+// @router /excel_info/balance/chart_list [get]
+func (c *ExcelInfoController) GetBalanceChartList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	excelInfoId, _ := c.GetInt("ExcelInfoId")
+	if excelInfoId <= 0 {
+		br.Msg = "请选择平衡表"
+		return
+	}
+	// 查询所有子表
+	excelInfo, err := excel.GetExcelInfoById(excelInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "表格不存在"
+			return
+		}
+		br.Msg = "查询子表失败"
+		br.ErrMsg = "查询子表失败,Err:" + err.Error()
+		return
+	}
+	list := make([]*data_manage.BalanceChartInfoDetailResp, 0)
+	chartInfoList, mappingListMap, dataListMap, err, errMsg := excelService.GetBalanceExcelChartList(excelInfo, "")
+	if err != nil {
+		if errMsg != "" {
+			br.Msg = errMsg
+			br.ErrMsg = err.Error()
+			return
+		} else {
+			br.Msg = "查询图表失败"
+			br.ErrMsg = "查询图表失败,Err:" + err.Error()
+		}
+		return
+	}
+	for _, chartInfo := range chartInfoList {
+		mappingList, ok := mappingListMap[chartInfo.ChartInfoId]
+		if !ok {
+			br.Msg = "未找到图表关联的指标信息"
+			return
+		}
+		var chartInfoResp *data_manage.ChartInfoDetailResp
+		chartInfoResp, err, errMsg = data.GetBalanceExcelChartDetail(chartInfo, mappingList, sysUser, dataListMap)
+		if err != nil {
+			br.Msg = "查询图表详情失败"
+			br.ErrMsg = "查询图表详情失败,Err:" + err.Error()
+			return
+		}
+		chartEdbList := make([]*data_manage.ExcelChartEdbView, 0)
+		for _, v := range mappingList {
+			tmp := &data_manage.ExcelChartEdbView{
+				ExcelChartEdbId: v.ExcelChartEdbId,
+				DateSequenceStr: v.DateSequence,
+				DataSequenceStr: v.DataSequence,
+				FromTag:         v.FromTag,
+			}
+			chartEdbList = append(chartEdbList, tmp)
+		}
+
+		balanceChartInfoResp := &data_manage.BalanceChartInfoDetailResp{
+			ChartInfoDetailResp: chartInfoResp,
+			ExcelEdbList:        chartEdbList,
+		}
+		list = append(list, balanceChartInfoResp)
+	}
+
+	ret := &data_manage.BalanceTableChartListResp{List: list}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "查询成功"
+	br.Data = ret
+}
+
+// DeleteBalanceChart
+// @Title 删除平衡表图表
+// @Description 删除平衡表图表
+// @Param	request	body data_manage.DeleteChartClassifyReq true "type json string"
+// @Success 200 Ret=200 删除成功
+// @router /excel_info/balance/chart_del [post]
+func (c *ExcelInfoController) DeleteBalanceChart() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req data_manage.DeleteChartClassifyReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ChartInfoId <= 0 {
+		br.Msg = "参数错误"
+		br.IsSendEmail = false
+		return
+	}
+	//删除图表
+	if req.ChartInfoId > 0 {
+		chartInfo, err := data_manage.GetChartInfoById(req.ChartInfoId)
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "图表已删除,请刷新页面"
+				br.ErrMsg = "指标不存在,Err:" + err.Error()
+				return
+			} else {
+				br.Msg = "删除失败"
+				br.ErrMsg = "删除失败,获取指标信息失败,Err:" + err.Error()
+				return
+			}
+		}
+		if chartInfo == nil {
+			br.Msg = "图表已删除,请刷新页面"
+			return
+		}
+
+		// 操作权限校验, 增加协作人判断
+		{
+			// 获取表格信息
+			excelInfo, e := excel.GetExcelInfoByChartInfoId(req.ChartInfoId)
+			if e != nil {
+				br.Msg = "获取ETA表格失败"
+				return
+			}
+			checkExcelInfo := excelInfo
+			if excelInfo.Source == utils.BALANCE_TABLE {
+				checkExcelInfoId := excelInfo.ExcelInfoId
+				if excelInfo.BalanceType == 1 {
+					checkExcelInfoId = excelInfo.RelExcelInfoId
+				} else {
+					if excelInfo.ParentId > 0 {
+						checkExcelInfoId = excelInfo.ParentId
+					}
+				}
+				if checkExcelInfoId != excelInfo.ExcelInfoId {
+					checkExcelInfo, e = excel.GetExcelInfoById(checkExcelInfoId)
+					if e != nil {
+						br.Msg = "获取平衡表格信息失败"
+						br.ErrMsg = "获取平衡表格信息失败,Err:" + e.Error()
+						return
+					}
+				}
+			}
+			// 数据权限
+			haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+			if e != nil {
+				br.Msg = "获取ETA表格权限失败"
+				br.ErrMsg = "获取表格权限信息失败,Err" + e.Error()
+				return
+			}
+
+			button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+			if !button.OpButton {
+				br.Msg = "无操作权限"
+				br.IsSendEmail = false
+				return
+			}
+		}
+
+		// 获取引用该图表的MyCharts, 用于ES删除
+		var myCond string
+		var myPars []interface{}
+		myCond += ` AND a.chart_info_id = ? `
+		myPars = append(myPars, req.ChartInfoId)
+		myCharts, e := data_manage.GetMyChartListGroupByCharyInfoIdAndAdminIdByCondition(myCond, myPars)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取引用图表的MyChats失败, Err: " + e.Error()
+			return
+		}
+		myIds := make([]int, 0)
+		for _, m := range myCharts {
+			myIds = append(myIds, m.MyChartId)
+		}
+
+		// 查询图表相关联的数据
+		edbIds := make([]int, 0)
+		// 查询图表相关联的指标
+		edbList, e := excel.GetExcelChartEdbMappingByChartInfoId(req.ChartInfoId)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "获取图表相关联的指标失败, Err: " + e.Error()
+			return
+		}
+		for _, v := range edbList {
+			edbIds = append(edbIds, v.ExcelChartEdbId)
+		}
+		//删除图表及关联指标
+		e = data_manage.DeleteBalanceExcelChartInfoAndData(req.ChartInfoId, edbIds)
+		if e != nil {
+			br.Msg = "删除失败"
+			br.ErrMsg = "删除失败,Err:" + e.Error()
+			return
+		}
+		//删除ES
+		{
+			go data.EsDeleteChartInfo(req.ChartInfoId)
+			// 删除MY ETA 图表 es数据
+			//go data.EsDeleteMyChartInfoByChartInfoId(req.ChartInfoId)
+			go data.EsDeleteMyChartInfoByMyChartIds(myIds)
+		}
+
+		//新增操作日志
+		{
+			chartLog := new(data_manage.ChartInfoLog)
+			chartLog.ChartName = chartInfo.ChartName
+			chartLog.ChartInfoId = req.ChartInfoId
+			chartLog.ChartClassifyId = chartInfo.ChartClassifyId
+			chartLog.SysUserId = sysUser.AdminId
+			chartLog.SysUserRealName = sysUser.RealName
+			chartLog.UniqueCode = chartInfo.UniqueCode
+			chartLog.CreateTime = time.Now()
+			chartLog.Content = string(c.Ctx.Input.RequestBody)
+			chartLog.Status = "删除图表"
+			chartLog.Method = c.Ctx.Input.URI()
+			go data_manage.AddChartInfoLog(chartLog)
+		}
+	}
+	br.Ret = 200
+	br.Msg = "删除成功"
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// BalanceSeasonChartLegendPreview
+// @Title 季节性图例预览接口
+// @Description 季节性图例预览接口
+// @Param	request	body request.BalanceSeasonChartLegendPreviewReq true "type json string"
+// @Success 200 {object} data_manage.BalanceSeasonChartLegendPreviewResp
+// @router /excel_info/balance/chartLegend/preview [post]
+func (c *ExcelInfoController) BalanceSeasonChartLegendPreview() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.BalanceSeasonChartLegendPreviewReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if len(req.DateArr) == 0 || len(req.DateArr) == 0 || len(req.DateArr) != len(req.DataArr) {
+		br.Msg = "请输入正确的日期和数据"
+		return
+	}
+	newDataMap := make(map[int]float64)
+	for i, v := range req.DataArr {
+		fv, e := strconv.ParseFloat(v, 64)
+		if e != nil {
+			br.Msg = "数据格式错误"
+			return
+		}
+		newDataMap[i] = fv
+	}
+	//组装成excelEdbData
+	dataList := make([]*data_manage.EdbDataList, 0)
+
+	for i, v := range req.DateArr {
+		dataTime, e := time.ParseInLocation(utils.FormatDate, v, time.Local)
+		if e != nil {
+			br.Msg = "日期格式错误"
+			br.ErrMsg = v + "日期格式错误,Err:" + e.Error()
+			return
+		}
+		timestamp := dataTime.UnixNano() / 1e6
+		tmp := &data_manage.EdbDataList{
+			EdbDataId:     i,
+			DataTime:      v,
+			DataTimestamp: timestamp,
+			Value:         newDataMap[i],
+		}
+		dataList = append(dataList, tmp)
+	}
+
+	list, err, errMsg := data.GetBalanceExcelSeasonChartLegendPreview(dataList, req.Calendar, req.SeasonExtraConfig)
+	if err != nil {
+		if errMsg != "" {
+			br.Msg = errMsg
+		} else {
+			br.Msg = "预览失败"
+		}
+		br.ErrMsg = err.Error()
+		return
+	}
+
+	ret := &data_manage.BalanceSeasonChartLegendPreviewResp{List: list}
+	br.Data = ret
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// AddStaticExcel
+// @Title 新增静态表
+// @Description 新增静态表
+// @Param	request	body request.EditExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/balance/static/add [post]
+func (c *ExcelInfoController) AddStaticExcel() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.AddBalanceStaticExcelInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ExcelInfoId <= 0 {
+		br.Msg = "请传入ETA表格标识!"
+		return
+	}
+
+	cacheKey := "CACHE_TABLE_INFO_BALANCE_STATIC_ADD_" + strconv.Itoa(req.ExcelInfoId)
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!"
+		return
+	}
+	defer func() {
+		_ = utils.Rc.Delete(cacheKey)
+	}()
+
+	req.VersionName = strings.Trim(req.VersionName, " ")
+	if req.VersionName == "" {
+		br.Msg = "请填写版本名称!"
+		br.IsSendEmail = false
+		return
+	}
+
+	// 获取原ETA表格信息
+	oldExcelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		return
+	}
+	// 操作权限校验, 增加协作人判断
+	{
+		// 数据权限
+		haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(oldExcelInfo.ExcelInfoId, oldExcelInfo.ExcelClassifyId, oldExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if err != nil {
+			br.Msg = "获取ETA表格失败"
+			br.ErrMsg = "获取ETA表格权限失败,Err:" + err.Error()
+			return
+		}
+		button := excelService.GetExcelInfoOpButton(sysUser, oldExcelInfo.SysUserId, oldExcelInfo.Source, haveOperaAuth)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	// 查询出每个子表的内容,并将内容转为静态版本
+	//查询动态表所有的子表,并复制为静态表
+	condition := " AND parent_id = ? AND balance_type = 0 "
+	var pars []interface{}
+	pars = append(pars, req.ExcelInfoId)
+	childExcelList, err := excel.GetExcelInfoListByCondition(condition, pars)
+	if err != nil {
+		br.Msg = "获取子表失败"
+		br.ErrMsg = fmt.Sprintf("获取子表失败 %s", err.Error())
+		return
+	}
+	for k, childExcelInfo := range childExcelList {
+		content, e := excelService.TransferBalanceExcelContentToStatic(childExcelInfo, "")
+		if e != nil {
+			br.Msg = "动态内容转成静态失败"
+			br.ErrMsg = fmt.Sprintf("动态内容转成静态失败 %s", e.Error())
+			return
+		}
+		childExcelList[k].Content = content
+	}
+
+	excelInfo, err, errMsg, isSendEmail := data.AddBalanceStaticExcel(oldExcelInfo, req.VersionName, sysUser, 0, req.ExcelInfoId, 1, childExcelList)
+	if err != nil {
+		br.Msg = "复制失败"
+		if errMsg != `` {
+			br.Msg = errMsg
+		}
+		br.ErrMsg = "复制失败,Err:" + err.Error()
+		br.IsSendEmail = isSendEmail
+		return
+	}
+
+	resp := new(response.AddExcelInfoResp)
+	resp.ExcelInfoId = excelInfo.ExcelInfoId
+	resp.UniqueCode = excelInfo.UniqueCode
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "保存成功"
+	br.Data = resp
+	br.IsAddLog = true
+}
+
+// BalanceVersionList
+// @Title 查询平衡表版本号列表
+// @Description 查询平衡表版本号列表
+// @Param	request	body request.EditExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/balance/version [get]
+func (c *ExcelInfoController) BalanceVersionList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	excelInfoId, _ := c.GetInt("ExcelInfoId")
+	if excelInfoId <= 0 {
+		br.Msg = "请选择表格"
+		br.ErrMsg = "ExcelInfoId未传"
+		br.IsSendEmail = false
+		return
+	}
+	excelInfo, err := excel.GetExcelInfoById(excelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
+		return
+	}
+	if excelInfo.Source != utils.BALANCE_TABLE {
+		br.Msg = "请选择平衡表"
+		return
+	}
+	if excelInfo.BalanceType != 0 && excelInfo.ParentId != 0 {
+		br.Msg = "请选择动态平衡表"
+		return
+	}
+	list := make([]*response.BalanceTableVersionListItem, 0)
+	list = append(list, &response.BalanceTableVersionListItem{
+		ExcelInfoId:    excelInfo.ExcelInfoId,
+		UniqueCode:     excelInfo.UniqueCode,
+		BalanceType:    excelInfo.BalanceType,
+		RelExcelInfoId: excelInfo.RelExcelInfoId,
+		VersionName:    "动态表", //todo 有个默认的版本名称
+	})
+	//查询动态表所有的子表,并复制为静态表
+	condition := " AND rel_excel_info_id=? AND parent_id = 0 AND balance_type = 1 "
+	var pars []interface{}
+	pars = append(pars, excelInfoId)
+
+	staticList, err := excel.GetNoContentExcelInfoListByConditionNoPage(condition, pars)
+	if err != nil {
+		br.Msg = "获取子表失败"
+		br.ErrMsg = fmt.Sprintf("获取子表失败 %s", err.Error())
+		return
+	}
+
+	for _, staticInfo := range staticList {
+		tmp := &response.BalanceTableVersionListItem{
+			ExcelInfoId:    staticInfo.ExcelInfoId,
+			UniqueCode:     staticInfo.UniqueCode,
+			BalanceType:    staticInfo.BalanceType,
+			RelExcelInfoId: staticInfo.RelExcelInfoId,
+			VersionName:    staticInfo.VersionName,
+		}
+		list = append(list, tmp)
+	}
+	ret := &response.BalanceTableVersionListResp{List: list}
+	br.Data = ret
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// ModifyBalanceExcelVersion
+// @Title 版本号重命名
+// @Description 版本号重命名
+// @Param	request	body request.AddBalanceStaticExcelInfoReq true "type json string"
+// @Success 200 {object} response.AddExcelInfoResp
+// @router /excel_info/balance/version/modify [post]
+func (c *ExcelInfoController) ModifyBalanceExcelVersion() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		c.Data["json"] = br
+		c.ServeJSON()
+	}()
+	sysUser := c.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	var req request.AddBalanceStaticExcelInfoReq
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ExcelInfoId <= 0 {
+		br.Msg = "请传入ETA表格标识!"
+		return
+	}
+
+	req.VersionName = strings.Trim(req.VersionName, " ")
+	if req.VersionName == "" {
+		br.Msg = "请填写版本名称!"
+		br.IsSendEmail = false
+		return
+	}
+	excelInfo, err := excel.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
+		return
+	}
+	if excelInfo.Source != utils.BALANCE_TABLE {
+		br.Msg = "请选择平衡表"
+		return
+	}
+	if excelInfo.BalanceType != 1 && excelInfo.ParentId != 0 {
+		br.Msg = "请选择静态表"
+		return
+	}
+
+	// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		if excelInfo.Source == utils.BALANCE_TABLE {
+			checkExcelInfoId := excelInfo.ExcelInfoId
+			if excelInfo.BalanceType == 1 {
+				checkExcelInfoId = excelInfo.RelExcelInfoId
+			} else {
+				if excelInfo.ParentId > 0 {
+					checkExcelInfoId = excelInfo.ParentId
+				}
+			}
+			if checkExcelInfoId != excelInfo.ExcelInfoId {
+				checkExcelInfo, err = excel.GetExcelInfoById(checkExcelInfoId)
+				if err != nil {
+					br.Msg = "获取平衡表格信息失败"
+					br.ErrMsg = "获取平衡表格信息失败,Err:" + err.Error()
+					return
+				}
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
+		if e != nil {
+			br.Msg = "获取ETA表格权限失败"
+			br.ErrMsg = "获取表格权限信息失败,Err" + e.Error()
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			br.Msg = "无操作权限"
+			br.IsSendEmail = false
+			return
+		}
+	}
+	// 检验分类下是否存在该版本号
+	{
+		var condition string
+		var pars []interface{}
+		condition += " AND rel_excel_info_id=? "
+		pars = append(pars, req.ExcelInfoId)
+
+		condition += " AND version_name=? "
+		pars = append(pars, req.VersionName)
+
+		count, tmpErr := excel.GetExcelInfoCountByCondition(condition, pars)
+		if tmpErr != nil {
+			br.Msg = "查询版本号失败"
+			br.ErrMsg = tmpErr.Error()
+			return
+		}
+		if count > 0 {
+			br.Msg = "表格版本号已存在,请重新填写表格名称"
+			br.IsSendEmail = false
+			return
+		}
+	}
+
+	excelInfo.ModifyTime = time.Now()
+	excelInfo.VersionName = req.VersionName
+	updateExcelInfoParams := []string{"ModifyTime", "VersionName"}
+	// todo 同步修改静态表中的图表和指标名称
+	// ETA表格信息变更
+	err = excelInfo.Update(updateExcelInfoParams)
+	if err != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "操作失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+	br.IsAddLog = true
+}

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

@@ -755,8 +755,13 @@ func (this *ExcelClassifyController) DeleteExcelClassify() {
 			condition += " AND excel_classify_id=? "
 			pars = append(pars, excelInfo.ExcelClassifyId)
 
+			if excelInfo.Source == utils.BALANCE_TABLE {
+				condition += " AND parent_id=0 AND balance_type=0 "
+			}
+
 			condition += " AND (sort>? OR (sort=? AND excel_info_id<?) ) "
 			pars = append(pars, excelInfo.Sort, excelInfo.Sort, excelInfo.ExcelInfoId)
+
 			nextItem, err = excel.GetNextExcelInfoByCondition(condition, pars)
 			if err != nil && err.Error() != utils.ErrNoRow() {
 				br.Msg = "删除失败"

+ 198 - 66
controllers/data_manage/excel/excel_info.go

@@ -79,35 +79,51 @@ func (c *ExcelInfoController) Add() {
 		return
 	}
 
-	if req.ExcelClassifyId <= 0 {
+	if req.ExcelClassifyId <= 0 && req.ParentId == 0 {
 		br.Msg = "分类参数错误!"
 		br.IsSendEmail = false
 		return
 	}
 
-	excelClassify, err := excel3.GetExcelClassifyById(req.ExcelClassifyId)
-	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
+	if req.ExcelClassifyId > 0 {
+		excelClassify, e := excel3.GetExcelClassifyById(req.ExcelClassifyId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "分类不存在"
+				br.ErrMsg = "分类不存在"
+				br.IsSendEmail = false
+				return
+			}
+			br.Msg = "获取分类信息失败"
+			br.ErrMsg = "获取分类信息失败,Err:" + e.Error()
+			return
+		}
+		if excelClassify == nil {
 			br.Msg = "分类不存在"
 			br.ErrMsg = "分类不存在"
 			br.IsSendEmail = false
 			return
 		}
-		br.Msg = "获取分类信息失败"
-		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
-		return
 	}
-	if excelClassify == nil {
-		br.Msg = "分类不存在"
-		br.ErrMsg = "分类不存在"
-		br.IsSendEmail = false
-		return
+
+	if req.ParentId > 0 {
+		parentExcelInfo, e := excel3.GetExcelInfoById(req.ParentId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "父级ETA表格被删除,请刷新页面"
+				return
+			}
+			br.Msg = "获取父级ETA表格信息失败"
+			br.ErrMsg = "获取父级ETA表格信息失败,Err:" + e.Error()
+			return
+		}
+		req.ExcelClassifyId = parentExcelInfo.ExcelClassifyId
 	}
 
 	var condition string
 	var pars []interface{}
-	condition += " AND excel_classify_id=? "
-	pars = append(pars, req.ExcelClassifyId)
+	condition += " AND excel_classify_id=? AND parent_id=?"
+	pars = append(pars, req.ExcelClassifyId, req.ParentId)
 
 	condition += " AND excel_name=? "
 	pars = append(pars, req.ExcelName)
@@ -167,7 +183,7 @@ func (c *ExcelInfoController) Add() {
 	}
 
 	// 混合表格
-	if req.Source == 3 {
+	if req.Source == 3 || req.Source == 5 {
 		contentByte, err := json.Marshal(req.TableData)
 		if err != nil {
 			br.Msg = "自定义表格数据获取失败"
@@ -216,19 +232,22 @@ func (c *ExcelInfoController) Add() {
 	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
 	excelInfo := &excel3.ExcelInfo{
 		//ExcelInfoId:     0,
-		ExcelName:       req.ExcelName,
-		Source:          req.Source,
-		ExcelType:       req.ExcelType,
-		UniqueCode:      utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
-		ExcelClassifyId: req.ExcelClassifyId,
-		SysUserId:       sysUser.AdminId,
-		SysUserRealName: sysUser.RealName,
-		Content:         content,
-		ExcelImage:      req.ExcelImage,
-		Sort:            maxSort + 1,
-		IsDelete:        0,
-		ModifyTime:      time.Now(),
-		CreateTime:      time.Now(),
+		ExcelName:          req.ExcelName,
+		Source:             req.Source,
+		ExcelType:          req.ExcelType,
+		UniqueCode:         utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
+		ExcelClassifyId:    req.ExcelClassifyId,
+		SysUserId:          sysUser.AdminId,
+		SysUserRealName:    sysUser.RealName,
+		Content:            content,
+		ExcelImage:         req.ExcelImage,
+		Sort:               maxSort + 1,
+		IsDelete:           0,
+		ModifyTime:         time.Now(),
+		CreateTime:         time.Now(),
+		ParentId:           req.ParentId,
+		UpdateUserId:       sysUser.AdminId,
+		UpdateUserRealName: sysUser.RealName,
 	}
 
 	excelEdbMappingList := make([]*excel3.ExcelEdbMapping, 0)
@@ -244,7 +263,30 @@ func (c *ExcelInfoController) Add() {
 			})
 		}
 	}
-	err = excel3.AddExcelInfo(excelInfo, excelEdbMappingList)
+	var childExcel *excel3.ExcelInfo
+	if excelInfo.Source == utils.BALANCE_TABLE && req.ParentId == 0 && excelInfo.BalanceType == 0 { //首次创建平衡表时需要添加一个默认的子表
+		timestamp = strconv.FormatInt(time.Now().UnixNano(), 10) + "_" + utils.GetRandString(10)
+		childExcel = &excel3.ExcelInfo{
+			//ExcelInfoId:     0,
+			ExcelName:       "平衡表",
+			Source:          excelInfo.Source,
+			ExcelType:       excelInfo.ExcelType,
+			UniqueCode:      utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
+			ExcelClassifyId: req.ExcelClassifyId,
+			SysUserId:       sysUser.AdminId,
+			SysUserRealName: sysUser.RealName,
+			Content:         excelInfo.Content,
+			//ExcelImage:         req.ExcelImage,
+			Sort:       excelInfo.Sort + 1,
+			IsDelete:   0,
+			ModifyTime: time.Now(),
+			CreateTime: time.Now(),
+			//ParentId:           req.ParentId,
+			UpdateUserId:       sysUser.AdminId,
+			UpdateUserRealName: sysUser.RealName,
+		}
+	}
+	err = excel3.AddExcelInfo(excelInfo, excelEdbMappingList, childExcel)
 	if err != nil {
 		br.Msg = "保存失败"
 		br.ErrMsg = "保存失败,Err:" + err.Error()
@@ -346,6 +388,9 @@ func (c *ExcelInfoController) List() {
 	} else {
 		condition += " AND source = ? "
 		pars = append(pars, source)
+		if source == utils.BALANCE_TABLE { //平衡表的列表只显示动态表的一级表(不显示子表和静态表)
+			condition += " AND parent_id = 0 AND balance_type=0 "
+		}
 	}
 
 	// 筛选分类
@@ -407,6 +452,7 @@ func (c *ExcelInfoController) List() {
 		classifyIdList := make([]int, 0)
 		for _, v := range list {
 			classifyIdList = append(classifyIdList, v.ExcelClassifyId)
+
 		}
 		classifyMap := make(map[int]*excel3.ExcelClassify)
 
@@ -430,11 +476,28 @@ func (c *ExcelInfoController) List() {
 			return
 		}
 
-		for _, v := range list {
+		for k, v := range list {
 			// 数据权限
 			if classifyInfo, ok := classifyMap[v.ExcelClassifyId]; ok {
 				v.HaveOperaAuth = data_manage_permission.CheckExcelPermissionByPermissionIdList(v.IsJoinPermission, classifyInfo.IsJoinPermission, v.ExcelInfoId, v.ExcelClassifyId, permissionEdbIdList, permissionClassifyIdList)
 			}
+			if v.Source == utils.BALANCE_TABLE {
+				//处理按钮权限和编辑状态
+				markStatus, err := services.UpdateExcelEditMark(v.ExcelInfoId, sysUser.AdminId, 2, sysUser.RealName)
+				if err != nil {
+					br.Msg = "查询标记状态失败"
+					br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
+					return
+				}
+				if markStatus.Status == 0 {
+					list[k].CanEdit = true
+				} else {
+					list[k].Editor = markStatus.Editor
+				}
+
+				// excel表格按钮权限
+				list[k].Button = excel2.GetBalanceExcelInfoOpButton(sysUser.AdminId, v.SysUserId, v.HaveOperaAuth, v.ExcelInfoId)
+			}
 		}
 
 	}
@@ -493,9 +556,18 @@ func (c *ExcelInfoController) Detail() {
 		br.ErrMsg = err.Error()
 		return
 	}
-
+	checkExcelInfoId := excelInfoId
+	if excelDetail.Source == utils.BALANCE_TABLE {
+		if excelDetail.BalanceType == 1 { // 平衡表静态表编辑状态以动态表的编辑状态为准
+			checkExcelInfoId = excelDetail.RelExcelInfoId
+		} else {
+			if excelDetail.ParentId > 0 { //  子表编辑状态以父表的编辑状态为准
+				checkExcelInfoId = excelDetail.ParentId
+			}
+		}
+	}
 	// 编辑状态
-	markStatus, err := services.UpdateExcelEditMark(excelInfoId, sysUser.AdminId, 2, sysUser.RealName)
+	markStatus, err := services.UpdateExcelEditMark(checkExcelInfoId, sysUser.AdminId, 2, sysUser.RealName)
 	if err != nil {
 		br.Msg = "查询标记状态失败"
 		br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
@@ -508,7 +580,9 @@ func (c *ExcelInfoController) Detail() {
 	}
 
 	// excel表格按钮权限
-	excelDetail.Button = excel2.GetExcelInfoOpButton(sysUser, excelDetail.SysUserId, excelDetail.Source, excelDetail.HaveOperaAuth)
+	if excelDetail.Source != utils.BALANCE_TABLE {
+		excelDetail.Button = excel2.GetExcelInfoOpButton(sysUser, excelDetail.SysUserId, excelDetail.Source, excelDetail.HaveOperaAuth)
+	}
 
 	br.Ret = 200
 	br.Success = true
@@ -568,14 +642,42 @@ func (c *ExcelInfoController) Edit() {
 		return
 	}
 
-	if req.ExcelClassifyId <= 0 {
+	excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
+	if err != nil {
+		br.Msg = "获取ETA表格失败"
+		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
+		return
+	}
+
+	if req.ExcelClassifyId <= 0 && excelInfo.ParentId == 0 {
 		br.Msg = "分类参数错误!"
 		br.IsSendEmail = false
 		return
 	}
 
+	checkExcelInfoId := excelInfo.ExcelInfoId
+	checkExcelInfo := excelInfo
+	if excelInfo.Source == utils.BALANCE_TABLE {
+		checkExcelInfoId = excelInfo.ExcelInfoId
+		if excelInfo.BalanceType == 1 {
+			checkExcelInfoId = excelInfo.RelExcelInfoId
+		} else {
+			if excelInfo.ParentId > 0 {
+				checkExcelInfoId = excelInfo.ParentId
+			}
+		}
+		if checkExcelInfoId != excelInfo.ExcelInfoId {
+			checkExcelInfo, err = excel3.GetExcelInfoById(checkExcelInfoId)
+			if err != nil {
+				br.Msg = "获取平衡表格信息失败"
+				br.ErrMsg = "获取平衡表格信息失败,Err:" + err.Error()
+				return
+			}
+		}
+	}
+
 	// 标记编辑状态
-	markRet, err := services.UpdateExcelEditMark(req.ExcelInfoId, sysUser.AdminId, 1, sysUser.RealName)
+	markRet, err := services.UpdateExcelEditMark(checkExcelInfoId, sysUser.AdminId, 1, sysUser.RealName)
 	if err != nil {
 		br.Msg = "查询标记状态失败"
 		br.ErrMsg = "查询标记状态失败,Err:" + err.Error()
@@ -587,33 +689,47 @@ func (c *ExcelInfoController) Edit() {
 		br.Data = markRet
 		return
 	}
-	excelClassify, err := excel3.GetExcelClassifyById(req.ExcelClassifyId)
-	if err != nil {
-		if err.Error() == utils.ErrNoRow() {
+	if req.ExcelClassifyId > 0 {
+		excelClassify, e := excel3.GetExcelClassifyById(req.ExcelClassifyId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "分类不存在"
+				br.ErrMsg = "分类不存在"
+				br.IsSendEmail = false
+				return
+			}
+			br.Msg = "获取分类信息失败"
+			br.ErrMsg = "获取分类信息失败,Err:" + e.Error()
+			return
+		}
+		if excelClassify == nil {
 			br.Msg = "分类不存在"
 			br.ErrMsg = "分类不存在"
 			br.IsSendEmail = false
 			return
 		}
-		br.Msg = "获取分类信息失败"
-		br.ErrMsg = "获取分类信息失败,Err:" + err.Error()
-		return
 	}
-	if excelClassify == nil {
-		br.Msg = "分类不存在"
-		br.ErrMsg = "分类不存在"
-		br.IsSendEmail = false
-		return
+	if excelInfo.ParentId > 0 {
+		parentExcelInfo, e := excel3.GetExcelInfoById(excelInfo.ParentId)
+		if e != nil {
+			if e.Error() == utils.ErrNoRow() {
+				br.Msg = "父级ETA表格被删除,请刷新页面"
+				return
+			}
+			br.Msg = "获取父级ETA表格信息失败"
+			br.ErrMsg = "获取父级ETA表格信息失败,Err:" + e.Error()
+			return
+		}
+		req.ExcelClassifyId = parentExcelInfo.ExcelClassifyId
 	}
-
 	//判断表格是否存在
 	var condition string
 	var pars []interface{}
 	condition += " AND excel_info_id != ? "
 	pars = append(pars, req.ExcelInfoId)
 
-	condition += " AND excel_classify_id=? "
-	pars = append(pars, req.ExcelClassifyId)
+	condition += " AND excel_classify_id=? AND parent_id=?"
+	pars = append(pars, req.ExcelClassifyId, excelInfo.ParentId)
 
 	condition += " AND excel_name=? "
 	pars = append(pars, req.ExcelName)
@@ -631,25 +747,22 @@ func (c *ExcelInfoController) Edit() {
 		return
 	}
 
-	excelInfo, err := excel3.GetExcelInfoById(req.ExcelInfoId)
-	if err != nil {
-		br.Msg = "获取ETA表格失败"
-		br.ErrMsg = "获取ETA表格失败,Err:" + err.Error()
-		return
-	}
-
 	// 操作权限校验
 	{
 		// 数据权限
-		haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(excelInfo.ExcelInfoId, excelInfo.ExcelClassifyId, excelInfo.IsJoinPermission, c.SysUser.AdminId)
+		haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, c.SysUser.AdminId)
 		if err != nil {
 			br.Msg = "获取ETA表格失败"
 			br.ErrMsg = "获取ETA表格权限失败,Err:" + err.Error()
 			return
 		}
-		button := excel2.GetExcelInfoOpButton(sysUser, excelInfo.SysUserId, excelInfo.Source, haveOperaAuth)
+		var button excel3.ExcelInfoDetailButton
+		if checkExcelInfo.Source == utils.BALANCE_TABLE {
+			button = excel2.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		} else {
+			button = excel2.GetExcelInfoOpButton(sysUser, excelInfo.SysUserId, excelInfo.Source, haveOperaAuth)
+		}
 		if !button.OpButton {
-			br.Msg = "无操作权限"
 			br.Msg = "无操作权限"
 			br.IsSendEmail = false
 			return
@@ -688,7 +801,7 @@ func (c *ExcelInfoController) Edit() {
 			return
 		}
 		content = string(contentByte)
-	case utils.MIXED_TABLE: // 混合表格
+	case utils.MIXED_TABLE, utils.BALANCE_TABLE: // 混合表格, 平衡表
 		contentByte, err := json.Marshal(req.TableData)
 		if err != nil {
 			br.Msg = "混合表格数据获取失败"
@@ -732,7 +845,6 @@ func (c *ExcelInfoController) Edit() {
 	excelInfo.ExcelClassifyId = req.ExcelClassifyId
 	excelInfo.ExcelImage = req.ExcelImage
 	excelInfo.Content = content
-
 	// 自动保存时不会传缩略图,也就不更新这个字段
 	var updateExcelInfoParams []string
 	if req.ExcelImage != "" {
@@ -1048,7 +1160,7 @@ func (c *ExcelInfoController) Delete() {
 		var nextItem *excel3.ExcelInfo
 		var condition string
 		var pars []interface{}
-		condition += " AND excel_classify_id=? "
+		condition += " AND excel_classify_id=? AND parent_id=0"
 		pars = append(pars, excelInfo.ExcelClassifyId)
 
 		condition += " AND sort>=? "
@@ -1932,7 +2044,10 @@ func (c *ExcelInfoController) Refresh() {
 
 	// 操作权限校验
 	{
-		button := excel2.GetExcelInfoOpButton(sysUser, excelDetail.SysUserId, excelDetail.Source, excelDetail.HaveOperaAuth)
+		button := excelDetail.Button
+		if excelDetail.Source != utils.BALANCE_TABLE {
+			button = excel2.GetExcelInfoOpButton(sysUser, excelDetail.SysUserId, excelDetail.Source, excelDetail.HaveOperaAuth)
+		}
 		if !button.RefreshButton {
 			br.Msg = "无操作权限"
 			br.IsSendEmail = false
@@ -1967,7 +2082,8 @@ func (c *ExcelInfoController) Refresh() {
 	}
 
 	// 数据刷新-混合表格
-	if excelDetail.Source == utils.MIXED_TABLE {
+	if excelDetail.Source == utils.MIXED_TABLE || excelDetail.Source == utils.BALANCE_TABLE {
+		// todo 刷新动态表的所有子表中关联的指标数据
 		jsonByte, e := json.Marshal(excelDetail.TableData)
 		if e != nil {
 			br.Msg = "刷新失败"
@@ -2424,6 +2540,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)
@@ -2433,7 +2557,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))
@@ -2481,10 +2605,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)

+ 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

+ 0 - 1
controllers/english_report/report.go

@@ -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 = "获取失败"

+ 116 - 11
controllers/ppt_english.go

@@ -8,7 +8,6 @@ import (
 	"eta/eta_api/services"
 	"eta/eta_api/services/ppt"
 	"eta/eta_api/utils"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	_ "image/gif"
 	_ "image/jpeg"
 	_ "image/png"
@@ -17,6 +16,8 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // PptEnglishController 新版ppt模块
@@ -91,6 +92,16 @@ func (this *PptEnglishController) ListPpt() {
 		} else {
 			list[i].IsAuth = false
 		}
+		if list[i].PptPage == 0 {
+			var pptContent []services.PPTContent
+			er := json.Unmarshal([]byte(list[i].Content), &pptContent)
+			if er != nil {
+				br.Msg = "content参数解析失败"
+				br.ErrMsg = "content参数解析失败, Err:" + er.Error()
+				return
+			}
+			list[i].PptPage = len(pptContent)
+		}
 	}
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(ppt_english.PptEnglishListResp)
@@ -125,6 +136,13 @@ func (this *PptEnglishController) AddPpt() {
 		br.Msg = "标题不能为空"
 		return
 	}
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
 
 	var newId int64
 	var msg string
@@ -188,8 +206,9 @@ func (this *PptEnglishController) AddPpt() {
 		pptInfo.Content = req.Content
 		pptInfo.CoverContent = req.CoverContent
 		pptInfo.ModifyTime = time.Now()
+		pptInfo.PptPage = len(pptContent)
 
-		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent"})
+		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page"})
 
 		msg = "保存成功"
 	}
@@ -221,6 +240,15 @@ func (this *PptEnglishController) EditPpt() {
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
 		return
 	}
+
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	if req.FirstPage.Title == "" {
 		br.Msg = "标题不能为空"
 		return
@@ -268,13 +296,36 @@ func (this *PptEnglishController) EditPpt() {
 	pptInfo.Content = req.Content
 	pptInfo.CoverContent = req.CoverContent
 	pptInfo.ModifyTime = time.Now()
-	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent"})
+	pptInfo.PptPage = len(pptContent)
+	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page"})
 	if err != nil {
 		br.Msg = "编辑失败"
 		br.ErrMsg = "编辑失败,Err:" + err.Error()
 		return
 	}
 
+	pptMap, err := ppt_english.GetPptMappingByPptId(req.PptId)
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := ppt_english.GetPptMappingListByGroupIdDesc(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPptEnglish(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	// 日志记录
 	{
 		logInfo := &ppt_english.PptEnglishSaveLog{
@@ -468,6 +519,29 @@ func (this *PptEnglishController) Publish() {
 		br.ErrMsg = "发布失败,Err:" + err.Error()
 		return
 	}
+
+	pptMap, err := ppt_english.GetPptMappingByPptId(int64(req.PptId))
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := ppt_english.GetPptMappingListByGroupIdDesc(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPptEnglish(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	//添加发布记录
 	{
 		record := new(ppt_english.PptEnglishPublishRecord)
@@ -636,6 +710,13 @@ func (this *PptEnglishController) SaveLog() {
 		return
 	}
 
+	var pageContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pageContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
 	// 获取ppt
 	item, err := ppt_english.GetPptEnglishByTitleAndId(req.FirstPage.Title, this.SysUser.AdminId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
@@ -670,14 +751,38 @@ func (this *PptEnglishController) SaveLog() {
 			return
 		}
 	}
-	//pptInfo.TemplateType = req.FirstPage.TemplateType
-	//pptInfo.BackgroundImg = req.FirstPage.ImgUrl
-	//pptInfo.Title = req.FirstPage.Title
-	//pptInfo.ReportType = req.FirstPage.ReportType
-	//pptInfo.PptDate = req.FirstPage.PptDate
-	//pptInfo.Content = req.Content
-	//pptInfo.ModifyTime = time.Now()
-	//err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime"})
+
+	pptItem.TemplateType = req.FirstPage.TemplateType
+	pptItem.BackgroundImg = req.FirstPage.ImgUrl
+	pptItem.Title = req.FirstPage.Title
+	pptItem.ReportType = req.FirstPage.ReportType
+	pptItem.PptDate = req.FirstPage.PptDate
+	pptItem.Content = req.Content
+	pptItem.ModifyTime = time.Now()
+	pptItem.PptPage = len(pageContent)
+	err = pptItem.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "ppt_page"})
+
+	pptMap, err := ppt_english.GetPptMappingByPptId(req.PptId)
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := ppt_english.GetPptMappingListByGroupIdDesc(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPptEnglish(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	//日志记录
 	logInfo := &ppt_english.PptEnglishSaveLog{

+ 11 - 1
controllers/ppt_english_group.go

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

+ 111 - 4
controllers/ppt_v2.go

@@ -9,7 +9,6 @@ import (
 	"eta/eta_api/services/ppt"
 	"eta/eta_api/utils"
 	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	_ "image/gif"
 	_ "image/jpeg"
 	_ "image/png"
@@ -18,6 +17,8 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // PptV2Controller 新版ppt模块
@@ -91,6 +92,16 @@ func (this *PptV2Controller) ListPpt() {
 		} else {
 			list[i].IsAuth = false
 		}
+		if list[i].PptPage == 0 {
+			var pptContent []services.PPTContent
+			er := json.Unmarshal([]byte(list[i].Content), &pptContent)
+			if er != nil {
+				br.Msg = "content参数解析失败"
+				br.ErrMsg = "content参数解析失败, Err:" + er.Error()
+				return
+			}
+			list[i].PptPage = len(pptContent)
+		}
 	}
 	page := paging.GetPaging(currentIndex, pageSize, total)
 	resp := new(models.PptV2ListResp)
@@ -126,6 +137,14 @@ func (this *PptV2Controller) AddPpt() {
 		return
 	}
 
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	var newId int64
 	var msg string
 	if req.PptId <= 0 {
@@ -158,6 +177,7 @@ func (this *PptV2Controller) AddPpt() {
 			AdminId:       this.SysUser.AdminId,
 			AdminRealName: this.SysUser.RealName,
 			PptVersion:    2,
+			PptPage:       len(pptContent),
 		}
 		newId, err = models.AddPptV2(pptInfo)
 		if err != nil {
@@ -189,8 +209,9 @@ func (this *PptV2Controller) AddPpt() {
 		pptInfo.Content = req.Content
 		pptInfo.CoverContent = req.CoverContent
 		pptInfo.ModifyTime = time.Now()
+		pptInfo.PptPage = len(pptContent)
 
-		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent"})
+		err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page"})
 
 		msg = "保存成功"
 	}
@@ -226,6 +247,15 @@ func (this *PptV2Controller) EditPpt() {
 		br.Msg = "标题不能为空"
 		return
 	}
+
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
 	item, err := models.GetPptV2ByTitleAndId(req.FirstPage.Title, this.SysUser.AdminId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
 		br.Msg = "获取数据异常!"
@@ -269,13 +299,36 @@ func (this *PptV2Controller) EditPpt() {
 	pptInfo.Content = req.Content
 	pptInfo.CoverContent = req.CoverContent
 	pptInfo.ModifyTime = time.Now()
-	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent"})
+	pptInfo.PptPage = len(pptContent)
+	err = pptInfo.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "CoverContent", "ppt_page"})
 	if err != nil {
 		br.Msg = "编辑失败"
 		br.ErrMsg = "编辑失败,Err:" + err.Error()
 		return
 	}
 
+	pptMap, err := models.GetPptMappingByPptId(req.PptId)
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := models.GetPptMappingListByGroupId(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPpt(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	// 日志记录
 	{
 		logInfo := &models.PptV2SaveLog{
@@ -469,6 +522,29 @@ func (this *PptV2Controller) Publish() {
 		br.ErrMsg = "发布失败,Err:" + err.Error()
 		return
 	}
+
+	pptMap, err := models.GetPptMappingByPptId(int64(req.PptId))
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := models.GetPptMappingListByGroupId(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPpt(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
+
 	//添加发布记录
 	{
 		record := new(models.PptV2PublishRecord)
@@ -606,6 +682,13 @@ func (this *PptV2Controller) SaveLog() {
 		br.Msg = "标题不能为空"
 		return
 	}
+	var pptContent []services.PPTContent
+	err = json.Unmarshal([]byte(req.Content), &pptContent)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
 
 	// 获取ppt
 	item, err := models.GetPptV2ByTitleAndId(req.FirstPage.Title, this.SysUser.AdminId)
@@ -648,7 +731,31 @@ func (this *PptV2Controller) SaveLog() {
 	pptItem.PptDate = req.FirstPage.PptDate
 	pptItem.Content = req.Content
 	pptItem.ModifyTime = time.Now()
-	err = pptItem.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime"})
+	pptItem.PptPage = len(pptContent)
+	err = pptItem.Update([]string{"TemplateType", "BackgroundImg", "Title", "ReportType", "PptDate", "Content", "ModifyTime", "ppt_page"})
+
+	// 将更新后的PPT, 置顶
+	pptMap, err := models.GetPptMappingByPptId(int64(req.PptId))
+	if err != nil {
+		br.Msg = `该PPT信息不存在, 保存失败`
+		br.ErrMsg = `该PPT信息不存在, 保存失败, Err` + err.Error()
+		br.IsSendEmail = false
+		return
+	}
+	pptMapList, err := models.GetPptMappingListByGroupId(pptMap.GroupId)
+	if err != nil {
+		br.ErrMsg = "PPT目录信息异常"
+		return
+	}
+	if !pptMap.IsMoved && len(pptMapList) > 1 {
+		// 如果没有人为移动位置, 默认将当前ppt置顶
+		err = ppt.MoveGroupPpt(pptMap.GroupId, pptMap.GroupPptId, pptMapList[0].GroupPptId, 0, this.SysUser.AdminId)
+		if err != nil {
+			br.Msg = err.Error()
+			br.ErrMsg = "移动失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	//日志记录
 	logInfo := &models.PptV2SaveLog{

+ 11 - 1
controllers/ppt_v2_group.go

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

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

+ 8 - 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")

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

+ 164 - 75
models/data_manage/chart_info.go

@@ -221,6 +221,45 @@ func DeleteChartInfoAndData(chartInfoId int) (err error) {
 	return
 }
 
+// 删除平衡表中的指标和数据
+func DeleteBalanceExcelChartInfoAndData(chartInfoId int, edbIds []int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	to, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = to.Rollback()
+		} else {
+			_ = to.Commit()
+		}
+	}()
+
+	sql := ` DELETE FROM chart_info WHERE chart_info_id=? `
+	_, err = to.Raw(sql, chartInfoId).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除平衡表图表失败 %s", err.Error())
+		return
+	}
+	sql = ` DELETE FROM  excel_chart_edb WHERE chart_info_id=? `
+	_, err = to.Raw(sql, chartInfoId).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除平衡表图表指标失败 %s", err.Error())
+		return
+	}
+	// 删除表格里的数据
+	if len(edbIds) > 0 {
+		sql = ` DELETE FROM  excel_chart_data WHERE excel_chart_edb_id in (` + utils.GetOrmInReplace(len(edbIds)) + `)`
+		_, err = to.Raw(sql, edbIds).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除平衡表图表指标数据失败 %s", err.Error())
+			return
+		}
+	}
+	return
+}
+
 func GetChartInfoCountByCondition(condition string, pars []interface{}) (count int, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT COUNT(1) AS count FROM chart_info WHERE 1=1 `
@@ -720,6 +759,21 @@ type ChartInfoDetailResp struct {
 	CorrelationChartInfo *CorrelationInfo `description:"相关性图表信息"`
 	DataResp             interface{}      `description:"图表数据,根据图的类型而定的,没有确定的数据格式"`
 }
+type BalanceTableChartListResp struct {
+	List []*BalanceChartInfoDetailResp
+}
+
+type BalanceChartInfoDetailResp struct {
+	*ChartInfoDetailResp
+	ExcelEdbList []*ExcelChartEdbView
+}
+
+type ExcelChartEdbView struct {
+	ExcelChartEdbId int
+	DateSequenceStr string `description:"日期序列选区"`
+	DataSequenceStr string `description:"数据序列选区"`
+	FromTag         string `description:"标签"`
+}
 
 // XData 商品价格曲线的的x轴数据
 type XData struct {
@@ -995,85 +1049,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
 }
 
@@ -1453,6 +1537,11 @@ func (m QuarterDataList) Swap(i, j int) {
 	m[i], m[j] = m[j], m[i]
 }
 
+// BalanceSeasonChartLegendPreviewResp 表格中季节性图表预览接口
+type BalanceSeasonChartLegendPreviewResp struct {
+	List QuarterDataList
+}
+
 // 判断图表指标是否已经存在
 func ChartInfoExist(condition, edbInfoIdStr string) (count int, err error) {
 	sql := `SELECT COUNT(1) AS count FROM (
@@ -1761,10 +1850,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 根据图表编码获取图表列表数据

+ 15 - 0
models/data_manage/chart_theme/chart_theme_type.go

@@ -88,3 +88,18 @@ func GetChartThemeTypeByChartTypeAndSource(chartType, source int) (item *ChartTh
 
 	return
 }
+
+// GetChartThemeTypeByChartType
+// @Description: 通过图表类型获取类型
+// @author: Roc
+// @datetime 2023-12-14 09:53:58
+// @param chartThemeTypeId int
+// @return item *ChartThemeType
+// @return err error
+func GetChartThemeTypeByChartType(chartType int) (item *ChartThemeType, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT * FROM chart_theme_type where chart_type = ?`
+	err = o.Raw(sql, chartType).QueryRow(&item)
+
+	return
+}

+ 15 - 5
models/data_manage/edb_data_base.go

@@ -329,13 +329,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)
@@ -378,6 +380,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)

+ 24 - 4
models/data_manage/edb_info.go

@@ -32,6 +32,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 +49,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 +57,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"`
 }
@@ -982,11 +983,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:"数据的最新值(预测日期的最新值)"`
 }
 
 // 获取指标的所有计算指标,以及计算指标所依赖计算指标
@@ -1305,7 +1306,7 @@ type SetEdbDataInsertConfigReq struct {
 // GetEdbInfoByClassifyId 用于分类展示
 func GetEdbInfoByClassifyId(classifyId, edbInfoType, adminId int) (items []*EdbClassifyItems, err error) {
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT edb_info_id,classify_id,edb_name_source AS classify_name,edb_name_en AS classify_name_en,unique_code,source_name,source,sys_user_id,sys_user_real_name,start_date,edb_code,edb_type, sort,is_join_permission FROM edb_info WHERE classify_id = ? AND edb_info_type = ?`
+	sql := ` SELECT edb_info_id,classify_id,edb_name AS classify_name,edb_name_en AS classify_name_en,unique_code,source_name,source,sys_user_id,sys_user_real_name,start_date,edb_code,edb_type, sort,is_join_permission FROM edb_info WHERE classify_id = ? AND edb_info_type = ?`
 
 	pars := []interface{}{classifyId, edbInfoType}
 	// 如果筛选了用户id
@@ -1545,6 +1546,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")

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

+ 44 - 0
models/data_manage/excel/excel_chart_data.go

@@ -0,0 +1,44 @@
+package excel
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ExcelChartData struct {
+	ExcelChartDataId int `orm:"column(excel_chart_data_id);pk"`
+	ExcelInfoId      int `description:"表格id"`
+	ExcelChartEdbId  int `description:"指标ID"`
+	DataTime         string
+	Value            float64
+	ModifyTime       time.Time `description:"修改时间"`
+	CreateTime       time.Time `description:"创建时间"`
+	DataTimestamp    int64
+}
+
+func (e *ExcelChartData) TableName() string {
+	return "excel_chart_data"
+}
+
+// 新增
+func (e *ExcelChartData) Add() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Insert(e)
+	return
+}
+
+// 修改
+func (e *ExcelChartData) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
+// 删除
+func (e *ExcelChartData) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(e)
+	return
+}
+
+// 查询

+ 333 - 0
models/data_manage/excel/excel_chart_edb.go

@@ -0,0 +1,333 @@
+package excel
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type ExcelChartEdb struct {
+	ExcelChartEdbId int       `orm:"column(excel_chart_edb_id);pk"`
+	ExcelInfoId     int       `description:"表格id"`
+	ChartInfoId     int       `description:"图表id"`
+	EdbCode         string    `description:"指标编码"`
+	EdbName         string    `description:"指标名称"`
+	DateSequence    string    `description:"日期序列选区"`
+	DataSequence    string    `description:"数据序列选区"`
+	SysUserId       int       `description:"创建人"`
+	SysUserRealName string    `description:"创建人姓名"`
+	MaxData         float64   `description:"上限"`
+	MinData         float64   `description:"下限"`
+	IsOrder         bool      `description:"true:正序,false:逆序"`
+	IsAxis          int       `description:"true:左轴,false:右轴"`
+	EdbInfoType     int       `description:"true:标准指标,false:领先指标"`
+	LeadValue       int       `description:"领先值"`
+	LeadUnit        string    `description:"领先单位"`
+	FromTag         string    `description:"标签"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+	ChartWidth      float64   `description:"线条大小"`
+}
+
+type ExcelChartEdbView struct {
+	ExcelChartEdbId int
+	ExcelInfoId     int    `description:"表格id"`
+	ChartInfoId     int    `description:"图表id"`
+	EdbCode         string `description:"指标编码"`
+	EdbName         string `description:"指标名称"`
+	DateSequenceStr string `description:"日期序列选区"`
+	DataSequenceStr string `description:"数据序列选区"`
+	/*MaxData         float64 `description:"上限"`
+	MinData         float64 `description:"下限"`
+	IsOrder         bool    `description:"true:正序,false:逆序"`
+	IsAxis          int     `description:"true:左轴,false:右轴"`
+	EdbInfoType     int     `description:"true:标准指标,false:领先指标"`
+	LeadValue       int     `description:"领先值"`
+	LeadUnit        string  `description:"领先单位"`*/
+	FromTag string `description:"标签"`
+}
+
+type BalanceTableChart struct {
+	ChartInfoId       int    `description:"图表id,新增时传0"`
+	ChartName         string `description:"图表名称"`
+	ChartType         int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图"`
+	Calendar          string `description:"公历/农历"`
+	LeftMin           string `description:"图表左侧最小值"`
+	LeftMax           string `description:"图表左侧最大值"`
+	RightMin          string `description:"图表右侧最小值"`
+	RightMax          string `description:"图表右侧最大值"`
+	Right2Min         string `description:"图表右侧2最小值"`
+	Right2Max         string `description:"图表右侧2最大值"`
+	MinMaxSave        int    `description:"是否手动保存过上下限:0-否;1-是"`
+	ExtraConfig       string `description:"图表额外配置信息,json字符串"`
+	ChartImage        string `description:"封面图" json:"-"`
+	SeasonExtraConfig string `description:"季节性图表中的配置,json数据"`
+	SourcesFrom       string `description:"图表来源"`
+	//	ChartEdbInfoList  []ExcelChartEdbView
+}
+
+func (e *ExcelChartEdb) TableName() string {
+	return "excel_chart_edb"
+}
+
+// 新增
+func (e *ExcelChartEdb) Add() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Insert(e)
+	return
+}
+
+// 修改
+func (e *ExcelChartEdb) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
+// 删除
+func (e *ExcelChartEdb) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(e)
+	return
+}
+
+type AddChartEdbAndDataItem struct {
+	ChartEdb *ExcelChartEdb
+	DateList []string  `description:"日期列表"`
+	ValList  []float64 `description:"数据列表"`
+}
+
+// 同时添加指标和指标数据
+func (e *ExcelChartEdb) AddChartEdbAndData(list []*AddChartEdbAndDataItem, chartInfo *data_manage.ChartInfo, deleteEdbIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+
+	// 先删除原先的绑定的指标
+	if len(deleteEdbIds) > 0 && chartInfo.ChartInfoId > 0 {
+		sql := `DELETE FROM excel_chart_edb WHERE excel_chart_info_id = ? AND excel_chart_edb_id in (` + utils.GetOrmInReplace(len(deleteEdbIds)) + `)`
+		_, err = o.Raw(sql, chartInfo.ChartInfoId, deleteEdbIds).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除原先的指标失败:%v", err)
+			return
+		}
+	}
+	// 图表指标信息入库
+	updateIds := make([]int, 0)
+	var edbInfoIdArrStr []string
+	for _, item := range list {
+		err = addChartEdbAndData(o, item.ChartEdb, item.DateList, item.ValList)
+		if err != nil {
+			return
+		}
+		updateIds = append(updateIds, item.ChartEdb.ExcelChartEdbId)
+		edbInfoIdArrStr = append(edbInfoIdArrStr, strconv.Itoa(item.ChartEdb.ExcelChartEdbId))
+	}
+
+	//新增图表
+	chartInfoId := chartInfo.ChartInfoId
+	if chartInfo.ChartInfoId <= 0 {
+		lastId, e := o.Insert(chartInfo)
+		if e != nil {
+			err = fmt.Errorf("新增图表失败,AddChartEdbAndData: %v", e)
+			return
+		}
+		chartInfoId = int(lastId)
+	} else {
+		_, err = o.Update(chartInfo)
+		if err != nil {
+			err = fmt.Errorf("更新图表失败,AddChartEdbAndData: %v", e)
+			return
+		}
+	}
+
+	//更新图表id
+	sql := `update excel_chart_edb set chart_info_id = ? where excel_chart_edb_id in (` + utils.GetOrmInReplace(len(updateIds)) + `)`
+	_, err = o.Raw(sql, chartInfoId, updateIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("更新图表id失败,AddChartEdbAndData: %v", err)
+		return
+	}
+
+	if len(edbInfoIdArrStr) > 0 {
+		edbInfoIdStr := strings.Join(edbInfoIdArrStr, ",")
+		//更新图表关联的指标id
+		sql = `update chart_info set edb_info_ids = ? where chart_info_id = ?`
+		_, err = o.Raw(sql, edbInfoIdStr, chartInfoId).Exec()
+	}
+	return
+}
+
+func addChartEdbAndData(o orm.TxOrmer, chartEdb *ExcelChartEdb, dateList []string, valList []float64) (err error) {
+	// 图表指标信息入库
+	excelChartEdbId := chartEdb.ExcelChartEdbId
+	if chartEdb.ExcelChartEdbId <= 0 {
+		lastId, e := o.Insert(chartEdb)
+		if e != nil {
+			err = fmt.Errorf("新增指标失败,addChartEdbAndData: %v", e)
+			return
+		}
+		excelChartEdbId = int(lastId)
+	} else {
+		_, e := o.Update(chartEdb)
+		if e != nil {
+			err = fmt.Errorf("更新指标失败,addChartEdbAndData: %v", e)
+			return
+		}
+		//如果有数据则删除所有的数据
+		sql := `delete from excel_chart_data where excel_chart_edb_id = ?`
+		_, err = o.Raw(sql, excelChartEdbId).Exec()
+		if err != nil {
+			return
+		}
+	}
+
+	chartEdb.ExcelChartEdbId = excelChartEdbId
+
+	// 图表指标数据入库
+	addList := make([]*ExcelChartData, 0)
+	if len(dateList) > 0 && len(valList) > 0 {
+		for k, v := range dateList {
+			chartData := &ExcelChartData{
+				ExcelInfoId:     chartEdb.ExcelInfoId,
+				ExcelChartEdbId: chartEdb.ExcelChartEdbId,
+				DataTime:        v,
+				Value:           valList[k],
+				ModifyTime:      time.Now(),
+				CreateTime:      time.Now(),
+			}
+			//时间戳
+			currentDate, er := time.Parse(utils.FormatDate, v)
+			if er != nil {
+				err = fmt.Errorf("时间格式化失败 err:%v", er)
+				return
+			}
+			timestamp := currentDate.UnixNano() / 1e6
+			chartData.DataTimestamp = timestamp
+			addList = append(addList, chartData)
+			// data信息入库
+			if len(addList) > 1000 {
+				_, err = o.InsertMulti(len(addList), len(addList))
+				if err != nil {
+					return
+				}
+				addList = addList[:0]
+			}
+		}
+	}
+
+	// data信息入库
+	if len(addList) > 0 {
+		_, err = o.InsertMulti(len(addList), len(addList))
+		if err != nil {
+			return
+		}
+	}
+	return
+}
+
+func GetExcelChartEdbMappingByExcelInfoId(excelInfoId int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE excel_info_id=? 
+             ORDER BY excel_chart_edb_id ASC `
+	_, err = o.Raw(sql, excelInfoId).QueryRows(&list)
+	return
+}
+
+func GetExcelChartEdbMappingByExcelInfoIds(excelInfoIds []int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).QueryRows(&list)
+	return
+}
+
+func GetExcelChartEdbById(id int) (item *ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM excel_chart_edb WHERE excel_chart_edb_id=? `
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func GetExcelChartEdbMappingByChartInfoId(chartInfoId int) (list []*ExcelChartEdb, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT *
+             FROM excel_chart_edb 
+			 WHERE chart_info_id=? 
+             ORDER BY excel_chart_edb_id ASC `
+	_, err = o.Raw(sql, chartInfoId).QueryRows(&list)
+	return
+}
+
+func GetExcelInfoByChartInfoId(chartInfoId int) (item *ExcelInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT i.*
+             FROM excel_chart_edb e left join excel_info i on e.excel_info_id=i.excel_info_id
+			 WHERE e.chart_info_id=? limit 1`
+	err = o.Raw(sql, chartInfoId).QueryRow(&item)
+	return
+}
+
+// 同时删除指标和指标数据
+func DeleteExcelChartEdbAndData(excelInfoIds []int, chartInfoIds []int) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+	// 把对应的表格状态改成删除状态
+	//更新图表id
+	sql := `update excel_info set is_delete = 1, modify_time = ? where excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, time.Now(), excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("更新图表id失败,AddChartEdbAndData: %v", err)
+		return
+	}
+	// 把删除图表状态
+	if len(chartInfoIds) > 0 {
+		sql := `DELETE FROM chart_info WHERE  chart_info_id in (` + utils.GetOrmInReplace(len(chartInfoIds)) + `)`
+		_, err = o.Raw(sql, chartInfoIds).Exec()
+		if err != nil {
+			err = fmt.Errorf("删除原先的指标失败:%v", err)
+			return
+		}
+
+		// todo 如果加入到我的图库中,则删除我的图库中的数据
+	}
+	// 删除原先的绑定的指标
+	sql = `DELETE FROM excel_chart_edb WHERE  excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除原先的指标失败:%v", err)
+		return
+	}
+	// 删除指标数据
+	sql = `DELETE FROM excel_chart_data WHERE  excel_info_id in (` + utils.GetOrmInReplace(len(excelInfoIds)) + `)`
+	_, err = o.Raw(sql, excelInfoIds).Exec()
+	if err != nil {
+		err = fmt.Errorf("删除原先的指标失败:%v", err)
+		return
+	}
+	return
+}

+ 119 - 44
models/data_manage/excel/excel_info.go

@@ -9,22 +9,28 @@ import (
 
 // ExcelInfo excel表格详情表
 type ExcelInfo 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:"操作人真实姓名"`
-	Content          string    `description:"表格内容"`
-	ExcelImage       string    `description:"表格图片"`
-	FileUrl          string    `description:"表格下载地址"`
-	Sort             int       `description:"排序字段,数字越小越排前面"`
-	IsDelete         int       `description:"是否删除,0:未删除,1:已删除"`
-	ModifyTime       time.Time `description:"最近修改日期"`
-	CreateTime       time.Time `description:"创建日期"`
-	IsJoinPermission int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	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:"操作人真实姓名"`
+	Content            string    `description:"表格内容"`
+	ExcelImage         string    `description:"表格图片"`
+	FileUrl            string    `description:"表格下载地址"`
+	Sort               int       `description:"排序字段,数字越小越排前面"`
+	IsDelete           int       `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime         time.Time `description:"最近修改日期"`
+	CreateTime         time.Time `description:"创建日期"`
+	IsJoinPermission   int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	ParentId           int       `description:"表格的父级id"`
+	BalanceType        int       `description:"平衡表类型:0 动态表,1静态表"`
+	UpdateUserId       int       `description:"更新人id"`
+	UpdateUserRealName string    `description:"更新人真实姓名"`
+	RelExcelInfoId     int       `description:"平衡表里静态表关联的动态表excel id"`
+	VersionName        string    `description:"静态表版本名称"`
 }
 
 // Update 更新 excel表格基础信息
@@ -35,25 +41,30 @@ func (excelInfo *ExcelInfo) Update(cols []string) (err error) {
 }
 
 type MyExcelInfoList struct {
-	ExcelInfoId      int       `orm:"column(excel_info_id);pk"`
-	Source           int       `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
-	ExcelType        int       `description:"表格类型,1:指标列,2:日期列,默认:1"`
-	ExcelName        string    `description:"表格名称"`
-	UniqueCode       string    `description:"表格唯一编码"`
-	ExcelClassifyId  int       `description:"表格分类id"`
-	SysUserId        int       `description:"操作人id"`
-	SysUserRealName  string    `description:"操作人真实姓名"`
-	ExcelImage       string    `description:"表格图片"`
-	FileUrl          string    `description:"表格下载地址"`
-	Sort             int       `description:"排序字段,数字越小越排前面"`
-	ModifyTime       time.Time `description:"最近修改日期"`
-	CreateTime       time.Time `description:"创建日期"`
-	IsJoinPermission int       `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
-	HaveOperaAuth    bool      `description:"是否有数据权限"`
+	ExcelInfoId        int                   `orm:"column(excel_info_id);pk"`
+	Source             int                   `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType          int                   `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName          string                `description:"表格名称"`
+	UniqueCode         string                `description:"表格唯一编码"`
+	ExcelClassifyId    int                   `description:"表格分类id"`
+	SysUserId          int                   `description:"操作人id"`
+	SysUserRealName    string                `description:"操作人真实姓名"`
+	ExcelImage         string                `description:"表格图片"`
+	FileUrl            string                `description:"表格下载地址"`
+	Sort               int                   `description:"排序字段,数字越小越排前面"`
+	ModifyTime         time.Time             `description:"最近修改日期"`
+	CreateTime         time.Time             `description:"创建日期"`
+	IsJoinPermission   int                   `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	HaveOperaAuth      bool                  `description:"是否有数据权限"`
+	UpdateUserId       int                   `description:"更新人id"`
+	UpdateUserRealName string                `description:"更新人真实姓名"`
+	Button             ExcelInfoDetailButton `description:"操作权限"`
+	CanEdit            bool                  `description:"是否可编辑"`
+	Editor             string                `description:"编辑人"`
 }
 
 // AddExcelInfo 新增表格
-func AddExcelInfo(excelInfo *ExcelInfo, excelEdbMappingList []*ExcelEdbMapping) (err error) {
+func AddExcelInfo(excelInfo *ExcelInfo, excelEdbMappingList []*ExcelEdbMapping, childExcel *ExcelInfo) (err error) {
 	o, err := orm.NewOrmUsingDB("data").Begin()
 	if err != nil {
 		return
@@ -71,7 +82,16 @@ func AddExcelInfo(excelInfo *ExcelInfo, excelEdbMappingList []*ExcelEdbMapping)
 		return
 	}
 	excelInfo.ExcelInfoId = int(lastId)
-
+	// todo 判断如果是平衡表的父级,则新增一个名叫平衡表的子表, 内容为空
+	if childExcel != nil {
+		// 表格信息入库
+		childExcel.ParentId = excelInfo.ExcelInfoId
+		_, err = o.Insert(childExcel)
+		if err != nil {
+			err = fmt.Errorf("新增子表失败:%v", err)
+			return
+		}
+	}
 	// excel与指标的关联关系
 	dataNum := len(excelEdbMappingList)
 	if dataNum > 0 {
@@ -104,7 +124,12 @@ func EditExcelInfo(excelInfo *ExcelInfo, updateExcelInfoParams []string, excelEd
 	if err != nil {
 		return
 	}
-
+	//更新父级分类时,同时更新子集分类
+	if excelInfo.Source == utils.BALANCE_TABLE && excelInfo.ParentId == 0 {
+		// 同步更新子表分类
+		sql := `UPDATE FROM excel_info set excel_classify_id = ? WHERE parent_id=? `
+		_, err = o.Raw(sql, excelInfo.ExcelClassifyId, excelInfo.ExcelInfoId).Exec()
+	}
 	// 删除关系表
 	sql := `DELETE FROM excel_edb_mapping WHERE excel_info_id=? `
 	_, err = o.Raw(sql, excelInfo.ExcelInfoId).Exec()
@@ -145,6 +170,10 @@ func GetNoContentExcelInfoAll(source, userId int) (items []*ExcelClassifyItems,
 		sql += ` AND sys_user_id = ? `
 		pars = append(pars, userId)
 	}
+
+	if source == utils.BALANCE_TABLE { //平衡表的列表只显示动态表的一级表(不显示子表和静态表)
+		sql += " AND parent_id = 0 AND balance_type=0 "
+	}
 	sql += `  ORDER BY sort asc,excel_info_id desc `
 	_, err = o.Raw(sql, pars...).QueryRows(&items)
 	return
@@ -204,13 +233,27 @@ func GetNoContentExcelInfoListByCondition(condition string, pars []interface{},
 	return
 }
 
-func GetExcelInfoByCondition(condition string, pars []interface{}) (item *ExcelInfo, err error) {
+func GetNoContentExcelInfoListByConditionNoPage(condition string, pars []interface{}) (items []*ExcelInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `SELECT excel_info_id,excel_classify_id,excel_name,
+             unique_code,sys_user_id,sys_user_real_name,sort,is_join_permission, parent_id, balance_type, update_user_id,update_user_real_name,rel_excel_info_id,version_name FROM excel_info WHERE is_delete=0 `
+	if condition != "" {
+		sql += condition
+	}
+
+	sql += ` ORDER BY excel_info_id DESC `
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func GetExcelInfoListByCondition(condition string, pars []interface{}) (items []*ExcelInfo, err error) {
 	o := orm.NewOrmUsingDB("data")
 	sql := ` SELECT * FROM excel_info WHERE 1=1 AND is_delete=0 `
 	if condition != "" {
 		sql += condition
 	}
-	err = o.Raw(sql, pars).QueryRow(&item)
+	sql += ` ORDER BY sort asc, excel_info_id asc`
+	_, err = o.Raw(sql, pars).QueryRows(&items)
 	return
 }
 
@@ -325,7 +368,7 @@ func GetExcelInfoByClassifyIdAndName(classifyId int, excelName string) (item *Ex
 // GetNoContentExcelListByCondition 获取没有content的excel表格列表数据
 func GetNoContentExcelListByCondition(condition string, pars []interface{}, startSize, pageSize int) (item []*MyExcelInfoList, err error) {
 	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,excel_image,file_url,sort,create_time,modify_time,is_join_permission
+	sql := ` SELECT excel_info_id,source,excel_type,excel_name,unique_code,excel_classify_id,sys_user_id,sys_user_real_name,excel_image,file_url,sort,create_time,modify_time,is_join_permission,update_user_id,update_user_real_name
 FROM excel_info WHERE 1=1 AND is_delete=0 `
 	if condition != "" {
 		sql += condition
@@ -374,7 +417,7 @@ func UpdateExcelInfoClassifyId(classifyId, excelInfoId int) (err error) {
 // GetNoContentExcelInfoByName 根据名称 获取eta表格详情
 func GetNoContentExcelInfoByName(excelName string, source int) (item *MyExcelInfoList, err error) {
 	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,excel_image,file_url,sort,create_time,modify_time,is_join_permission 
+	sql := ` SELECT excel_info_id,source,excel_type,excel_name,unique_code,excel_classify_id,sys_user_id,sys_user_real_name,excel_image,file_url,sort,create_time,modify_time,is_join_permission,update_user_id,update_user_real_name 
  FROM excel_info WHERE excel_name = ? AND source = ? AND is_delete=0 `
 	err = o.Raw(sql, excelName, source).QueryRow(&item)
 
@@ -384,7 +427,7 @@ func GetNoContentExcelInfoByName(excelName string, source int) (item *MyExcelInf
 // GetNoContentExcelInfoByUniqueCode 根据unique_code来获取excel表格详情
 func GetNoContentExcelInfoByUniqueCode(uniqueCode string) (item *MyExcelInfoList, err error) {
 	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,excel_image,file_url,sort,create_time,modify_time,is_join_permission 
+	sql := ` SELECT excel_info_id,source,excel_type,excel_name,unique_code,excel_classify_id,sys_user_id,sys_user_real_name,excel_image,file_url,sort,create_time,modify_time,is_join_permission,update_user_id,update_user_real_name 
  FROM excel_info WHERE unique_code=? AND is_delete=0 `
 	err = o.Raw(sql, uniqueCode).QueryRow(&item)
 	return
@@ -393,7 +436,7 @@ func GetNoContentExcelInfoByUniqueCode(uniqueCode string) (item *MyExcelInfoList
 // GetNoContentExcelInfoByExcelId 根据表格id来获取excel表格详情
 func GetNoContentExcelInfoByExcelId(excelInfoId int) (item *MyExcelInfoList, err error) {
 	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,excel_image,file_url,sort,create_time,modify_time,is_join_permission 
+	sql := ` SELECT excel_info_id,source,excel_type,excel_name,unique_code,excel_classify_id,sys_user_id,sys_user_real_name,excel_image,file_url,sort,create_time,modify_time,is_join_permission,update_user_id,update_user_real_name 
  FROM excel_info WHERE excel_info_id=? AND is_delete=0 `
 	err = o.Raw(sql, excelInfoId).QueryRow(&item)
 	return
@@ -538,10 +581,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
@@ -569,6 +612,18 @@ func GetNoContentExcelListByExcelInfoIdList(excelInfoIdList []string) (items []*
 	return
 }
 
+func GetNoContentExcelListByExcelInfoIdAndParentId(excelInfoIdList []string) (items []*MyExcelInfoList, err error) {
+	num := len(excelInfoIdList)
+	if num <= 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM excel_info WHERE excel_info_id in (` + utils.GetOrmInReplace(num) + `) OR parent_id in (` + utils.GetOrmInReplace(num) + `)   order by excel_info_id DESC `
+	_, err = o.Raw(sql, excelInfoIdList, excelInfoIdList).QueryRows(&items)
+
+	return
+}
+
 // GetNoContentExcelListByUserId
 // @Description: 根据ETA表格ID列表获取列表信息
 // @param userIdList []int
@@ -623,3 +678,23 @@ func ModifyExcelInfoUserIdByOldUserId(oldUserIdList []int, userId int, userName
 	_, err = o.Raw(sql, userId, userName, oldUserIdList).Exec()
 	return
 }
+
+// GetChildExcelInfoByParentId 根据id 获取eta表格详情
+func GetChildExcelInfoByParentId(parentId int) (items []*ExcelInfo, err error) {
+	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,excel_image,file_url,sort,create_time,modify_time,is_join_permission, parent_id, balance_type, update_user_id,update_user_real_name FROM excel_info WHERE parent_id=? AND is_delete=0 order by sort asc, excel_info_id asc`
+	_, err = o.Raw(sql, parentId).QueryRows(&items)
+	return
+}
+
+// ExcelInfoDetailButton 操作按钮
+type ExcelInfoDetailButton struct {
+	RefreshButton    bool `description:"是否可刷新"`
+	CopyButton       bool `description:"是否可另存为"`
+	DownloadButton   bool `description:"是否可下载"`
+	OpButton         bool `description:"是否可编辑"`
+	DeleteButton     bool `description:"是否可删除"`
+	OpEdbButton      bool `description:"是否可生成指标"`
+	RefreshEdbButton bool `description:"是否可刷新指标"`
+	OpWorkerButton   bool `description:"是否修改协作人"`
+}

+ 74 - 0
models/data_manage/excel/excel_worker.go

@@ -0,0 +1,74 @@
+package excel
+
+import (
+	"eta/eta_api/utils"
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type ExcelWorker struct {
+	ExcelWorkerId   int       `orm:"column(excel_worker_id);pk"`
+	ExcelInfoId     int       `description:"表格id"`
+	SysUserId       int       `description:"创建人"`
+	SysUserRealName string    `description:"创建人姓名"`
+	ModifyTime      time.Time `description:"修改时间"`
+	CreateTime      time.Time `description:"创建时间"`
+}
+
+func (e *ExcelWorker) TableName() string {
+	return "excel_worker"
+}
+
+// 新增 协作人
+func (e *ExcelWorker) AddWorker(excelInfoId int, addWorkers []*ExcelWorker, notDeleteWorkers []string) (err error) {
+	o, err := orm.NewOrmUsingDB("data").Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = o.Rollback()
+		} else {
+			_ = o.Commit()
+		}
+	}()
+	if len(notDeleteWorkers) > 0 {
+		sql := `delete from excel_worker where excel_info_id = ? and sys_user_id not in (` + utils.GetOrmInReplace(len(notDeleteWorkers)) + `)`
+		_, err = o.Raw(sql, excelInfoId, notDeleteWorkers).Exec()
+		if err != nil {
+			return
+		}
+	} else if len(notDeleteWorkers) == 0 { // 清空协作人
+		sql := `delete from excel_worker where excel_info_id = ? `
+		_, err = o.Raw(sql, excelInfoId).Exec()
+		if err != nil {
+			return
+		}
+	}
+	if len(addWorkers) > 0 {
+		_, err = o.InsertMulti(len(addWorkers), addWorkers)
+	}
+	return
+}
+
+// 修改
+func (e *ExcelWorker) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(e, cols...)
+	return
+}
+
+// 删除
+func (e *ExcelWorker) Delete() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Delete(e)
+	return
+}
+
+// 查询
+func (e *ExcelWorker) GetByExcelInfoId(excelInfoId int) (items []*ExcelWorker, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `select * from excel_worker where excel_info_id = ? `
+	_, err = o.Raw(sql, excelInfoId).QueryRows(&items)
+	return
+}

+ 76 - 0
models/data_manage/excel/request/balance_table.go

@@ -0,0 +1,76 @@
+package request
+
+import "eta/eta_api/models/data_manage"
+
+type AddBalanceTableChartEdbItem struct {
+	DateSequenceStr string  `description:"日期序列"`
+	DataSequenceStr string  `description:"数据序列"`
+	EdbName         string  `description:"指标名称"`
+	MaxData         float64 `description:"上限"`
+	MinData         float64 `description:"下限"`
+	IsOrder         bool    `description:"true:正序,false:逆序"`
+	IsAxis          int     `description:"true:左轴,false:右轴"`
+	EdbInfoType     int     `description:"true:标准指标,false:领先指标"`
+	LeadValue       int     `description:"领先值"`
+	LeadUnit        string  `description:"领先单位"`
+	FromTag         string  `description:"标签"`
+	ExcelChartEdbId int
+
+	/*	ChartStyle        string  `description:"图表类型"`
+		ChartColor        string  `description:"颜色"`
+		PredictChartColor string  `description:"预测数据的颜色"`
+		ChartWidth        float64 `description:"线条大小"`
+		Source            int     `description:"1:ETA图库;2:商品价格曲线"`
+		EdbAliasName      string  `description:"中文别名"`
+		IsConvert         int     `description:"是否数据转换 0不转 1转"`
+		ConvertType       int     `description:"数据转换类型 1乘 2除 3对数"`
+		ConvertValue      float64 `description:"数据转换值"`
+		ConvertUnit       string  `description:"数据转换单位"`
+		ConvertEnUnit     string  `description:"数据转换单位"`*/
+}
+
+type AddBalanceTableChartReq struct {
+	ExcelInfoId int `description:"表格ID"`
+	ChartInfoId int `description:"图表id,新增时传0"`
+	//ChartClassifyId int    `description:"分类id"`
+	ChartName string `description:"图表名称"`
+	ChartType int    `description:"生成样式:1:曲线图,2:季节性图,3:面积图,4:柱状图,5:散点图,6:组合图,7:柱方图"`
+	//DateType        int    `description:"日期类型:1:00年至今,2:10年至今,3:15年至今,4:年初至今,5:自定义时间,6:起始日期至今"`
+	//StartDate       string `description:"自定义开始日期"`
+	//EndDate         string `description:"自定义结束日期"`
+	Calendar   string `description:"公历/农历"`
+	LeftMin    string `description:"图表左侧最小值"`
+	LeftMax    string `description:"图表左侧最大值"`
+	RightMin   string `description:"图表右侧最小值"`
+	RightMax   string `description:"图表右侧最大值"`
+	Right2Min  string `description:"图表右侧2最小值"`
+	Right2Max  string `description:"图表右侧2最大值"`
+	MinMaxSave int    `description:"是否手动保存过上下限:0-否;1-是"`
+	//BarChartInfo         BarChartInfoReq         `description:"柱方图的配置"`
+	//CorrelationChartInfo CorrelationChartInfoReq `description:"相关性图表配置"`
+	ExtraConfig       string                      `description:"图表额外配置信息,json字符串"`
+	ChartImage        string                      `description:"封面图" json:"-"`
+	SeasonExtraConfig data_manage.SeasonExtraItem `description:"季节性图表中的配置,json数据"`
+	//StartYear         int                         `description:"当选择的日期类型为最近N年类型时,即date_type=20, 用start_year表示N"`
+	//ChartThemeId int    `description:"图表应用主题ID"`
+	SourcesFrom string `description:"图表来源"`
+	//Instructions      string          `description:"图表说明"`
+	//MarkersLines      string          `description:"标识线"`
+	//MarkersAreas      string          `description:"标识区"`
+	//Unit              string          `description:"中文单位名称"`
+	//UnitEn            string          `description:"英文单位名称"`
+	ChartEdbInfoList []AddBalanceTableChartEdbItem
+}
+
+type BalanceSeasonChartLegendPreviewReq struct {
+	Calendar          string                      `description:"公历/农历"`
+	SeasonExtraConfig data_manage.SeasonExtraItem `description:"季节性图表中的配置,json数据"`
+	DataArr           []string
+	DateArr           []string
+}
+
+// AddBalanceStaticExcelInfoReq 添加平衡表静态表
+type AddBalanceStaticExcelInfoReq struct {
+	ExcelInfoId int    `description:"ETA表格ID"`
+	VersionName string `description:"静态表版本名称"`
+}

+ 23 - 1
models/data_manage/excel/request/excel_info.go

@@ -17,12 +17,13 @@ type DeleteExcelInfoReq struct {
 type AddExcelInfoReq struct {
 	ExcelInfoId     int         `description:"表格ID"`
 	ExcelName       string      `description:"表格名称"`
-	Source          int         `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	Source          int         `description:"表格来源,1:excel插件的表格,2:自定义表格,5平衡表,默认:1"`
 	ExcelType       int         `description:"表格类型,1:指标列,2:日期列,默认:1"`
 	ExcelImage      string      `description:"表格截图"`
 	ExcelClassifyId int         `description:"分类id"`
 	Content         string      `description:"Excel表格内容"`
 	TableData       interface{} `description:"自定义表格的数据内容"`
+	ParentId        int         `description:"表格的父级id"`
 }
 
 // EditExcelInfoReq 编辑表格请求
@@ -134,8 +135,29 @@ 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"`
 	Status      int `description:"标记状态,1:编辑中,2:编辑完成"`
 }
+
+// RenameExcelInfoReq 表格重命名请求
+type RenameExcelInfoReq struct {
+	ExcelInfoId int    `description:"ETA表格ID"`
+	ExcelName   string `description:"表格名称"`
+}
+
+type SaveExcelInfoWorkerReq struct {
+	ExcelInfoId int    `description:"ETA表格ID"`
+	SysUserIds  string `description:"协作人ID 用英文逗号拼接"`
+}

+ 44 - 30
models/data_manage/excel/response/excel_info.go

@@ -56,36 +56,50 @@ type TableDetailResp struct {
 
 // ExcelInfoDetail excel表格详情(前端使用)
 type ExcelInfoDetail struct {
-	ExcelInfoId      int                   `orm:"column(excel_info_id);pk"`
-	Source           int                   `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
-	ExcelType        int                   `description:"表格类型,1:指标列,2:日期列,默认:1"`
-	ExcelName        string                `description:"表格名称"`
-	UniqueCode       string                `description:"表格唯一编码"`
-	ExcelClassifyId  int                   `description:"表格分类id"`
-	SysUserId        int                   `description:"操作人id"`
-	SysUserRealName  string                `description:"操作人真实姓名"`
-	Content          string                `description:"表格内容"`
-	ExcelImage       string                `description:"表格图片"`
-	FileUrl          string                `description:"表格下载地址"`
-	Sort             int                   `description:"排序字段,数字越小越排前面"`
-	IsDelete         int                   `description:"是否删除,0:未删除,1:已删除"`
-	ModifyTime       time.Time             `description:"最近修改日期"`
-	CreateTime       time.Time             `description:"创建日期"`
-	TableData        interface{}           `description:"表格内容"`
-	Button           ExcelInfoDetailButton `description:"操作权限"`
-	CanEdit          bool                  `description:"是否可编辑"`
-	Editor           string                `description:"编辑人"`
-	IsJoinPermission int                   `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
-	HaveOperaAuth    bool                  `description:"是否有数据权限"`
+	ExcelInfoId        int                          `orm:"column(excel_info_id);pk"`
+	Source             int                          `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType          int                          `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName          string                       `description:"表格名称"`
+	UniqueCode         string                       `description:"表格唯一编码"`
+	ExcelClassifyId    int                          `description:"表格分类id"`
+	SysUserId          int                          `description:"操作人id"`
+	SysUserRealName    string                       `description:"操作人真实姓名"`
+	Content            string                       `description:"表格内容"`
+	ExcelImage         string                       `description:"表格图片"`
+	FileUrl            string                       `description:"表格下载地址"`
+	Sort               int                          `description:"排序字段,数字越小越排前面"`
+	IsDelete           int                          `description:"是否删除,0:未删除,1:已删除"`
+	ModifyTime         time.Time                    `description:"最近修改日期"`
+	CreateTime         time.Time                    `description:"创建日期"`
+	TableData          interface{}                  `description:"表格内容"`
+	Button             excel2.ExcelInfoDetailButton `description:"操作权限"`
+	CanEdit            bool                         `description:"是否可编辑"`
+	Editor             string                       `description:"编辑人"`
+	IsJoinPermission   int                          `description:"是否加入权限管控,0:不加入;1:加入;默认:0"`
+	HaveOperaAuth      bool                         `description:"是否有数据权限"`
+	ParentId           int                          `description:"表格的父级id"`
+	BalanceType        int                          `description:"平衡表类型:0 动态表,1静态表"`
+	UpdateUserId       int                          `description:"更新人id"`
+	UpdateUserRealName string                       `description:"更新人真实姓名"`
+	RelExcelInfoId     int                          `description:"平衡表里静态表关联的动态表excel id"`
 }
 
-// ExcelInfoDetailButton 操作按钮
-type ExcelInfoDetailButton struct {
-	RefreshButton    bool `description:"是否可刷新"`
-	CopyButton       bool `description:"是否可另存为"`
-	DownloadButton   bool `description:"是否可下载"`
-	OpButton         bool `description:"是否可编辑"`
-	DeleteButton     bool `description:"是否可删除"`
-	OpEdbButton      bool `description:"是否可生成指标"`
-	RefreshEdbButton bool `description:"是否可刷新指标"`
+type BalanceChildTableResp struct {
+	List []*excel2.ExcelInfo
+}
+
+type BalanceTableWorkerResp struct {
+	List []*excel2.ExcelWorker
+}
+
+type BalanceTableVersionListItem struct {
+	ExcelInfoId    int    `description:"表格id"`
+	UniqueCode     string `description:"表格唯一编码"`
+	BalanceType    int    `description:"平衡表类型:0 动态表,1静态表"`
+	RelExcelInfoId int    `description:"平衡表里静态表关联的动态表excel id"`
+	VersionName    string `description:"静态表版本名称"`
+}
+
+type BalanceTableVersionListResp struct {
+	List []*BalanceTableVersionListItem
 }

+ 17 - 17
models/data_manage/excel/response/sheet.go

@@ -14,21 +14,21 @@ type FindExcelInfoResp struct {
 
 // FindExcelInfo excel的数据详情
 type FindExcelInfo struct {
-	ExcelInfoId     int                   `orm:"column(excel_info_id);pk"`
-	Source          int                   `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
-	ExcelType       int                   `description:"表格类型,1:指标列,2:日期列,默认:1"`
-	ExcelName       string                `description:"表格名称"`
-	UniqueCode      string                `description:"表格唯一编码"`
-	ExcelClassifyId int                   `description:"表格分类id"`
-	SysUserId       int                   `description:"操作人id"`
-	SysUserRealName string                `description:"操作人真实姓名"`
-	ExcelImage      string                `description:"表格图片"`
-	FileUrl         string                `description:"表格下载地址"`
-	Sort            int                   `description:"排序字段,数字越小越排前面"`
-	ModifyTime      time.Time             `description:"最近修改日期"`
-	CreateTime      time.Time             `description:"创建日期"`
-	Button          ExcelInfoDetailButton `description:"操作权限"`
-	CanEdit         bool                  `description:"是否可编辑"`
-	Editor          string                `description:"编辑人"`
-	HaveOperaAuth   bool                  `description:"是否有数据权限,默认:false"`
+	ExcelInfoId     int                         `orm:"column(excel_info_id);pk"`
+	Source          int                         `description:"表格来源,1:excel插件的表格,2:自定义表格,默认:1"`
+	ExcelType       int                         `description:"表格类型,1:指标列,2:日期列,默认:1"`
+	ExcelName       string                      `description:"表格名称"`
+	UniqueCode      string                      `description:"表格唯一编码"`
+	ExcelClassifyId int                         `description:"表格分类id"`
+	SysUserId       int                         `description:"操作人id"`
+	SysUserRealName string                      `description:"操作人真实姓名"`
+	ExcelImage      string                      `description:"表格图片"`
+	FileUrl         string                      `description:"表格下载地址"`
+	Sort            int                         `description:"排序字段,数字越小越排前面"`
+	ModifyTime      time.Time                   `description:"最近修改日期"`
+	CreateTime      time.Time                   `description:"创建日期"`
+	Button          excel.ExcelInfoDetailButton `description:"操作权限"`
+	CanEdit         bool                        `description:"是否可编辑"`
+	Editor          string                      `description:"编辑人"`
+	HaveOperaAuth   bool                        `description:"是否有数据权限,默认:false"`
 }

+ 15 - 4
models/data_manage/my_chart.go

@@ -903,11 +903,14 @@ func GetChartInfoByIdList(chartInfoIdList []int) (items []*ChartInfo, err error)
 	return
 }
 
-// GetMyChartClassifyByClassifyId 主键获取分类
-func GetMyChartClassifyByClassifyId(classifyId int) (item *MyChartClassify, err error) {
+func GetChartInfoViewByIdList(chartInfoIdList []int) (items []*ChartInfoView, err error) {
+	num := len(chartInfoIdList)
+	if num <= 0 {
+		return
+	}
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT * FROM my_chart_classify WHERE my_chart_classify_id = ? `
-	err = o.Raw(sql, classifyId).QueryRow(&item)
+	sql := ` SELECT * FROM chart_info WHERE chart_info_id in (` + utils.GetOrmInReplace(num) + `) `
+	_, err = o.Raw(sql, chartInfoIdList).QueryRows(&items)
 	return
 }
 
@@ -960,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
+}

+ 11 - 5
models/db.go

@@ -23,9 +23,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 +178,15 @@ func init() {
 	// 初始化跨品种分析表
 	initCrossVariety()
 
+	// 初始化图表主题
+	initChartTheme()
+
 	//初始化AI
 	initAi()
 
 	// 报告审批
 	initReportApprove()
 
-	// 初始化图表主题
-	initChartTheme()
-
 	// 初始化指标刷新
 	initEdbRefresh()
 
@@ -311,6 +312,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), //预测指标配置
@@ -454,7 +456,8 @@ func initBusinessConf() {
 
 func initOutLink() {
 	orm.RegisterModel(
-		new(OutLink)) // 外部链接表
+		new(OutLink), // 外部链接表
+	)
 }
 
 // initEtaTrial 试用平台相关表
@@ -491,6 +494,9 @@ func initExcel() {
 		new(excel.ExcelSheet),      //ETA excel sheet
 		new(excel.ExcelSheetData),  //ETA excel sheet data
 		new(excel.ExcelEdbMapping), //ETA excel 与 指标 的关系表
+		new(excel.ExcelWorker),     // 平衡表协作人表格
+		new(excel.ExcelChartEdb),   // 平衡表做图指标
+		new(excel.ExcelChartData),  // 平衡表作图数据
 	)
 }
 

+ 4 - 1
models/ppt_english/ppt_english.go

@@ -1,9 +1,10 @@
 package ppt_english
 
 import (
+	"time"
+
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
-	"time"
 )
 
 // PptEnglish 表
@@ -25,6 +26,7 @@ type PptEnglish struct {
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
 	CoverContent  string    `description:"PPT内容-JSON"`
+	PptPage       int       `description:"PPT正文页数"`
 }
 
 type PptEnglishItem struct {
@@ -46,6 +48,7 @@ type PptEnglishItem struct {
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
 	CoverContent  string    `description:"PPT内容-JSON"`
+	PptPage       int       `description:"PPT正文页数"`
 }
 
 func GetPptEnglishList(condition string, pars []interface{}, startSize, pageSize int) (items []*PptEnglishItem, err error) {

+ 3 - 1
models/ppt_english/ppt_english_grant.go

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

+ 3 - 1
models/ppt_english/ppt_english_group.go

@@ -1,8 +1,9 @@
 package ppt_english
 
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 type PptEnglishGroup struct {
@@ -229,6 +230,7 @@ type RespGroupPptListItem struct {
 	ReportId      int    `description:"关联的报告ID"`
 	ReportCode    string `description:"关联的报告code"`
 	PublishTime   string `description:"发布时间"`
+	PptPage       int    `description:"ppt总页数"`
 }
 
 func (p RespGroupPptList) Len() int {

+ 19 - 1
models/ppt_english/ppt_english_group_mapping.go

@@ -1,8 +1,9 @@
 package ppt_english
 
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 // ppt目录和ppt 映射表
@@ -16,6 +17,7 @@ type PptEnglishGroupMapping struct {
 	AdminId         int       `description:"移动ppt到该目录的系统用户id"`
 	AdminRealName   string    `description:"系统用户名称"`
 	ChildGroupPptId int64     `description:"设置共享后的新映射ID"`
+	IsMoved         bool      `description:"true表示改PPT被人为移动过"`
 }
 
 // AddPptGroupMapping 新增目录和ppt的映射关系
@@ -41,6 +43,22 @@ func GetPptMappingListByGroupId(groupId int64) (list []*PptEnglishGroupMapping,
 	return
 }
 
+// GetPptMappingByPptId 查询目录下, pptId对应的目录映射关系
+func GetPptMappingByPptId(pptId int64) (item *PptEnglishGroupMapping, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` select * from ppt_english_group_mapping where ppt_id=? `
+	err = o.Raw(sql, pptId).QueryRow(&item)
+	return
+}
+
+// GetPptMappingListByGroupId 查询目录下,ppt列表, 降序排列
+func GetPptMappingListByGroupIdDesc(groupId int64) (list []*PptEnglishGroupMapping, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_english_group_mapping where group_id=? order by ppt_sort desc, group_ppt_id desc `
+	_, err = o.Raw(sql, groupId).QueryRows(&list)
+	return
+}
+
 // GetPptMappingListByGroupIds 根据分组ID查找
 func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptEnglishGroupMapping, err error) {
 	_, err = orm.NewOrmUsingDB("rddp").

+ 4 - 1
models/ppt_v2.go

@@ -2,9 +2,10 @@ package models
 
 import (
 	"eta/eta_api/models/ppt_english"
+	"time"
+
 	"github.com/beego/beego/v2/client/orm"
 	"github.com/rdlucklib/rdluck_tools/paging"
-	"time"
 )
 
 // PptV2 表
@@ -28,6 +29,7 @@ type PptV2 struct {
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
 	CoverContent  string    `description:"PPT内容-JSON"`
+	PptPage       int       `description:"PPT的总页数"`
 }
 
 type PptV2Item struct {
@@ -51,6 +53,7 @@ type PptV2Item struct {
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
 	CoverContent  string    `description:"PPT内容-JSON"`
+	PptPage       int       `description:"PPT的总页数"`
 }
 
 func GetPptV2List(condition string, pars []interface{}, startSize, pageSize int) (items []*PptV2Item, err error) {

+ 3 - 1
models/ppt_v2_grant.go

@@ -1,8 +1,9 @@
 package models
 
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 // PptV2Grant Ppt授权表
@@ -98,6 +99,7 @@ type PptV2InfoGrantItem struct {
 	ReportCode    string    `description:"关联的报告code"`
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
+	PptPage       int       `description:"ppt正文总页数"`
 
 	//GrantId      int64     `orm:"column(grant_id);pk;auto" description:"自增序号"`
 	//PptId        int64     `description:"ppt ID"`

+ 3 - 1
models/ppt_v2_group.go

@@ -1,8 +1,9 @@
 package models
 
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 type PptV2Group struct {
@@ -229,6 +230,7 @@ type RespGroupPptListItem struct {
 	ReportId      int    `description:"关联的报告ID"`
 	ReportCode    string `description:"关联的报告code"`
 	PublishTime   string `description:"发布时间"`
+	PptPage       int    `description:"PPT总页数"`
 }
 
 func (p RespGroupPptList) Len() int {

+ 13 - 3
models/ppt_v2_group_mapping.go

@@ -1,8 +1,9 @@
 package models
 
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 
 // ppt目录和ppt 映射表
@@ -16,6 +17,7 @@ type PptV2GroupMapping struct {
 	AdminId         int       `description:"移动ppt到该目录的系统用户id"`
 	AdminRealName   string    `description:"系统用户名称"`
 	ChildGroupPptId int64     `description:"设置共享后的新映射ID"`
+	IsMoved         bool      `description:"true表示改PPT被人为移动过"`
 }
 
 // AddPptGroupMapping 新增目录和ppt的映射关系
@@ -36,7 +38,7 @@ func GetPptMappingCountByGroupId(groupId int64) (total int64, err error) {
 // GetPptMappingListByGroupId 查询目录下,ppt列表
 func GetPptMappingListByGroupId(groupId int64) (list []*PptV2GroupMapping, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_v2_group_mapping where group_id=? order by ppt_sort asc, group_ppt_id asc `
+	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_v2_group_mapping where group_id=? order by ppt_sort desc, group_ppt_id desc `
 	_, err = o.Raw(sql, groupId).QueryRows(&list)
 	return
 }
@@ -46,7 +48,7 @@ func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptV2GroupMapping, e
 	_, err = orm.NewOrmUsingDB("rddp").
 		QueryTable("ppt_v2_group_mapping").
 		Filter("group_id__in", groupIds).
-		OrderBy("-ppt_sort", "group_ppt_id").
+		OrderBy("-ppt_sort", "-group_ppt_id").
 		All(&list)
 
 	return
@@ -60,6 +62,14 @@ func GetPptMappingByGroupPptId(groupPptId int64, adminId int) (item *PptV2GroupM
 	return
 }
 
+// GetPptMappingByPptId 查询根据ppt_Id, 查询当映单个映射关系
+func GetPptMappingByPptId(pptId int64) (item *PptV2GroupMapping, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := ` select * from ppt_v2_group_mapping where ppt_id=? `
+	err = o.Raw(sql, pptId).QueryRow(&item)
+	return
+}
+
 // Update 更新ppt目录映射的基本信息
 func (item *PptV2GroupMapping) Update(cols []string) (err error) {
 	o := orm.NewOrmUsingDB("rddp")

+ 1 - 0
models/report.go

@@ -642,6 +642,7 @@ type ElasticReportDetail struct {
 	ClassifyNameSecond string `description:"二级分类名称"`
 	Categories         string `description:"关联的品种名称(包括品种别名)"`
 	StageStr           string `description:"报告期数"`
+	BodyMd5            string `description:"MD5加密之后的内容"`
 }
 
 // GetLastPublishedDayWeekReport 获取上一篇已发布的晨周报

+ 114 - 6
routers/commentsRouter.go

@@ -817,6 +817,78 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "BalanceSeasonChartLegendPreview",
+            Router: `/excel_info/balance/chartLegend/preview`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "BalanceChartInfoAdd",
+            Router: `/excel_info/balance/chart_add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "DeleteBalanceChart",
+            Router: `/excel_info/balance/chart_del`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "BalanceChartInfoEdit",
+            Router: `/excel_info/balance/chart_edit`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetBalanceChartList",
+            Router: `/excel_info/balance/chart_list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "AddStaticExcel",
+            Router: `/excel_info/balance/static/add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "BalanceVersionList",
+            Router: `/excel_info/balance/version`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "ModifyBalanceExcelVersion",
+            Router: `/excel_info/balance/version/modify`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "GetBaseEdbInfo",
@@ -826,6 +898,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetChildTable",
+            Router: `/excel_info/child_table`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "Copy",
@@ -925,6 +1006,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "Rename",
+            Router: `/excel_info/rename`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
         beego.ControllerComments{
             Method: "BatchRefresh",
@@ -1015,6 +1105,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "GetWorker",
+            Router: `/excel_info/worker`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/excel:ExcelInfoController"],
+        beego.ControllerComments{
+            Method: "SaveExcelWorker",
+            Router: `/excel_info/worker/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/future_good:FutureGoodChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/future_good:FutureGoodChartClassifyController"],
         beego.ControllerComments{
             Method: "AddChartClassify",
@@ -4734,23 +4842,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`,

+ 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{},
 			),
 		),
 	)

+ 135 - 9
services/data/chart_info.go

@@ -1350,7 +1350,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 +1410,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 +1426,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)
@@ -3081,3 +3096,114 @@ func getEdbConvertDataMapList(chartInfoId, chartType int, calendar, startDate, e
 
 	return
 }
+
+// GetChartEdbDataV2 获取图表的指标数据
+func GetChartEdbDataV2(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, extraConfigStr string, seasonExtraConfig string, chartInfoData ChartInfoDataShow) (edbList []*data_manage.ChartEdbInfoMapping, xEdbIdValue []int, yDataList []data_manage.YData, dataResp interface{}, err error, errMsg string) {
+	edbList = make([]*data_manage.ChartEdbInfoMapping, 0)
+	xEdbIdValue = make([]int, 0)
+	yDataList = make([]data_manage.YData, 0)
+
+	var extraConfig interface{}
+	switch chartType {
+	case 7: // 柱形图
+		var barConfig data_manage.BarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "柱方图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "柱方图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	case 10: // 截面散点图
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		extraConfig = tmpExtraConfig
+	case utils.CHART_TYPE_RADAR:
+		var barConfig data_manage.RadarChartInfoReq
+		if extraConfigStr == `` {
+			errMsg = "雷达图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &barConfig)
+		if err != nil {
+			errMsg = "雷达图配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+		extraConfig = barConfig
+	default:
+		xEdbIdValue = make([]int, 0)
+		yDataList = make([]data_manage.YData, 0)
+	}
+
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err := chartInfoData.GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig)
+	if err != nil {
+		return
+	}
+
+	// 特殊图形数据处理
+	switch chartType {
+	case 7: // 柱形图
+		barChartConf := extraConfig.(data_manage.BarChartInfoReq)
+		xEdbIdValue, yDataList, err = BarChartData(mappingList, edbDataListMap, barChartConf.DateList, barChartConf.Sort)
+
+		for k := range yDataList {
+			yDataList[k].Unit = barChartConf.Unit
+			yDataList[k].UnitEn = barChartConf.UnitEn
+		}
+
+		for _, v := range edbList {
+			// 指标别名
+			if barChartConf.EdbInfoIdList != nil && len(barChartConf.EdbInfoIdList) > 0 {
+				for _, reqEdb := range barChartConf.EdbInfoIdList {
+					if v.EdbInfoId == reqEdb.EdbInfoId {
+						v.EdbAliasName = reqEdb.Name
+					}
+				}
+			}
+		}
+	case 10: // 截面散点图
+		sectionScatterConf := extraConfig.(data_manage.SectionScatterReq)
+		xEdbIdValue, dataResp, err = GetSectionScatterChartData(chartInfoId, mappingList, edbDataListMap, sectionScatterConf)
+
+		var tmpExtraConfig data_manage.SectionScatterReq
+		if extraConfigStr == `` {
+			errMsg = "截面散点图未配置"
+			err = errors.New(errMsg)
+			return
+		}
+		err = json.Unmarshal([]byte(extraConfigStr), &tmpExtraConfig)
+		if err != nil {
+			errMsg = "截面散点配置异常"
+			err = errors.New(errMsg)
+			return
+		}
+
+		// 这个数据没有必要返回给前端
+		for _, v := range edbList {
+			v.DataList = nil
+		}
+	case utils.CHART_TYPE_RADAR: //雷达图
+		radarConf := extraConfig.(data_manage.RadarChartInfoReq)
+		xEdbIdValue, dataResp, err = RadarChartData(mappingList, edbDataListMap, radarConf)
+	}
+	return
+}

+ 1533 - 0
services/data/chart_info_excel_balance.go

@@ -0,0 +1,1533 @@
+package data
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/data_manage/chart_theme"
+	excelModel "eta/eta_api/models/data_manage/excel"
+	"eta/eta_api/models/data_manage/excel/request"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data/data_manage_permission"
+	"eta/eta_api/utils"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// AddBalanceExcelChart 添加平衡表图表
+func AddBalanceExcelChart(excelInfo *excelModel.ExcelInfo, req request.AddBalanceTableChartReq, sysUser *system.Admin) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
+
+	/*// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		checkExcelInfoId := excelInfo.ExcelInfoId
+		if excelInfo.BalanceType == 1 {
+			checkExcelInfoId = excelInfo.RelExcelInfoId
+		} else {
+			if excelInfo.ParentId > 0 {
+				checkExcelInfoId = excelInfo.ParentId
+			}
+		}
+		if checkExcelInfoId != excelInfo.ExcelInfoId {
+			checkExcelInfo, err = excelModel.GetExcelInfoById(checkExcelInfoId)
+			if err != nil {
+				errMsg = "获取平衡表格信息失败"
+				err = fmt.Errorf("获取平衡表格信息失败,Err:" + err.Error())
+				return
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUser.AdminId)
+		if e != nil {
+			errMsg = "获取ETA表格权限失败"
+			err = fmt.Errorf("获取表格权限信息失败,Err" + e.Error())
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			errMsg = "无操作权限"
+			isSendEmail = false
+			return
+		}
+	}*/
+
+	if len(req.ChartEdbInfoList) == 0 {
+		errMsg = "图表数据不能为空!"
+		err = fmt.Errorf("图表数据不能为空!%s", err.Error())
+		return
+	}
+	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
+	for _, chartEdb := range req.ChartEdbInfoList {
+		excelEdb := new(excelModel.ExcelChartEdb)
+		excelEdb.EdbName = chartEdb.EdbName
+		randStr := utils.GetRandDigit(4)
+		excelEdb.EdbCode = `T` + time.Now().Format("060102150405") + "_" + randStr
+		excelEdb.ExcelInfoId = excelInfo.ExcelInfoId
+		excelEdb.DateSequence = chartEdb.DateSequenceStr
+		excelEdb.DataSequence = chartEdb.DataSequenceStr
+		excelEdb.SysUserId = sysUser.AdminId
+		excelEdb.SysUserRealName = sysUser.RealName
+		excelEdb.MaxData = chartEdb.MaxData
+		excelEdb.MinData = chartEdb.MinData
+		excelEdb.IsOrder = chartEdb.IsOrder
+		excelEdb.IsAxis = chartEdb.IsAxis
+		excelEdb.FromTag = chartEdb.FromTag
+		excelEdb.EdbInfoType = chartEdb.EdbInfoType
+		excelEdb.LeadValue = chartEdb.LeadValue
+		excelEdb.LeadUnit = chartEdb.LeadUnit
+		excelEdb.CreateTime = time.Now()
+		excelEdb.ModifyTime = time.Now()
+		excelEdb.ChartWidth = 1
+		var dateList []string
+		var dataList []float64
+		if excelInfo.BalanceType == 1 {
+			// 如果是静态表,则直接使用前端传输的数据落到数据库里
+			/*dateList, dataList, err, errMsg = utils.HandleEdbSequenceVal(chartEdb.DateSequenceVal, chartEdb.DataSequenceVal)
+			if err != nil {
+				errMsg = "时间序列或数据序列异常!"
+				err = fmt.Errorf("时间序列或数据序列异常!%s", err.Error())
+				return
+			}*/
+		}
+
+		// 处理日期列表和值列表
+		addItem := &excelModel.AddChartEdbAndDataItem{
+			ChartEdb: excelEdb,
+			DateList: dateList,
+			ValList:  dataList,
+		}
+		chartEdbList = append(chartEdbList, addItem)
+	}
+	chartInfo, err, errMsg, isSendEmail = addBalanceExcelChart(req, sysUser.AdminId, sysUser.RealName)
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表失败!%s, %s", errMsg, err.Error())
+		return
+	}
+	obj := new(excelModel.ExcelChartEdb)
+	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, []int{})
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表数据失败!%s", err.Error())
+		return
+	}
+	return
+}
+
+func addBalanceExcelChart(req request.AddBalanceTableChartReq, sysUserId int, sysUserRealName string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true // 默认错误的时候要发送邮件
+
+	req.ChartName = strings.Trim(req.ChartName, " ")
+	if req.ChartName == "" {
+		errMsg = "请填写图表名称!"
+		err = fmt.Errorf(errMsg)
+		isSendEmail = false
+		return
+	}
+	chartType := req.ChartType
+	extraConfig := req.ExtraConfig
+	// 查找默认主题设置
+	// 查找主题类型id
+	chartThemeType, err := chart_theme.GetChartThemeTypeByChartType(chartType)
+	if err != nil {
+		errMsg = "查找主题类型失败!"
+		err = fmt.Errorf("%s, %s", errMsg, err.Error())
+		return
+	}
+	chartThemeId := chartThemeType.DefaultChartThemeId
+	// 季节性图表额外配置信息
+	var seasonExtraConfig string
+
+	if len(req.ChartEdbInfoList) <= 0 {
+		errMsg = "请选择指标!"
+		err = fmt.Errorf(errMsg)
+		return
+	}
+	if chartType == 2 {
+		// 处理季节性图表横轴配置
+		{
+			if req.SeasonExtraConfig.XEndDate != "" {
+				if req.SeasonExtraConfig.XStartDate > req.SeasonExtraConfig.XEndDate && req.SeasonExtraConfig.JumpYear != 1 {
+					errMsg = "季节性图表配置信息异常:横坐标日期配置错误"
+					err = fmt.Errorf("季节性图表配置信息异常: 横坐标日期配置错误")
+					return
+				}
+				seasonExtra, tErr := json.Marshal(req.SeasonExtraConfig)
+				if tErr != nil {
+					errMsg = "季节性图表配置信息异常"
+					err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
+					return
+				}
+
+				seasonExtraConfig = string(seasonExtra)
+			}
+		}
+	}
+
+	// 图表额外配置
+	extraConfig, err, errMsg = HandleExtraConfig(chartType, extraConfig)
+	if err != nil {
+		if errMsg == `` {
+			errMsg = "指标异常!"
+		}
+		err = fmt.Errorf("指标异常!Err:" + err.Error())
+		return
+	}
+
+	//判断图表是否存在
+	var condition string
+	var pars []interface{}
+
+	// 图表名称在不同图分类下不允许重复 需求调整时间:2022年11月07日09:47:07
+	condition += " AND chart_classify_id=0 "
+
+	condition += " AND chart_name=? AND source = ? "
+	pars = append(pars, req.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)
+
+	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
+	if err != nil {
+		errMsg = "判断图表名称是否存在失败"
+		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
+		return
+	}
+
+	if count > 0 {
+		errMsg = "图表已存在,请重新填写"
+		err = fmt.Errorf("判断图表名称是否存在失败")
+		isSendEmail = false
+		return
+	}
+
+	chartInfo = new(data_manage.ChartInfo)
+	chartInfo.ChartName = req.ChartName
+	//chartInfo.EdbInfoIds = edbInfoIdStr
+	//chartInfo.ChartClassifyId = req.ChartClassifyId
+	chartInfo.SysUserId = sysUserId
+	chartInfo.SysUserRealName = sysUserRealName
+	chartInfo.CreateTime = time.Now()
+	chartInfo.ModifyTime = time.Now()
+	chartInfo.IsSetName = 0
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+
+	// todo 判断是否需要重新计算用户的start_date
+	chartInfo.DateType = 3
+
+	if chartType == 0 {
+		chartType = 1
+	}
+	chartInfo.ChartType = chartType
+
+	calendar := req.Calendar
+	if calendar == "" {
+		calendar = "公历"
+	}
+
+	chartInfo.Calendar = calendar
+	/*	chartInfo.StartDate = req.StartDate
+		chartInfo.EndDate = req.EndDate
+		chartInfo.SeasonStartDate = req.StartDate
+		chartInfo.SeasonEndDate = req.EndDate*/
+	chartInfo.LeftMin = req.LeftMin
+	chartInfo.LeftMax = req.LeftMax
+	chartInfo.RightMin = req.RightMin
+	chartInfo.RightMax = req.RightMax
+	chartInfo.Right2Min = req.Right2Min
+	chartInfo.Right2Max = req.Right2Max
+	chartInfo.MinMaxSave = req.MinMaxSave
+	//chartInfo.Disabled = disableVal
+	//chartInfo.BarConfig = barChartConf
+	chartInfo.ExtraConfig = extraConfig
+	chartInfo.SeasonExtraConfig = seasonExtraConfig
+	//chartInfo.StartYear = req.StartYear
+	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
+	chartInfo.ChartThemeId = chartThemeId
+	chartInfo.SourcesFrom = req.SourcesFrom
+	/*	chartInfo.Instructions = req.Instructions
+		chartInfo.MarkersLines = req.MarkersLines
+		chartInfo.MarkersAreas = req.MarkersAreas
+		chartInfo.Unit = req.Unit
+		chartInfo.UnitEn = req.UnitEn*/
+	/*newId, err := data_manage.AddChartInfo(chartInfo)
+	if err != nil {
+		errMsg = `保存失败`
+		err = fmt.Errorf("保存失败,Err:" + err.Error())
+		return
+	}
+	chartInfo.ChartInfoId = int(newId)*/
+
+	//添加es数据
+	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+
+	return
+}
+
+// EditBalanceExcelChart 添加平衡表图表
+func EditBalanceExcelChart(excelInfo *excelModel.ExcelInfo, req request.AddBalanceTableChartReq, sysUser *system.Admin) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
+	if len(req.ChartEdbInfoList) == 0 {
+		errMsg = "图表数据不能为空!"
+		err = fmt.Errorf("图表数据不能为空!%s", err.Error())
+		return
+	}
+	/*// 操作权限校验, 增加协作人判断
+	{
+		checkExcelInfo := excelInfo
+		checkExcelInfoId := excelInfo.ExcelInfoId
+		if excelInfo.BalanceType == 1 {
+			checkExcelInfoId = excelInfo.RelExcelInfoId
+		} else {
+			if excelInfo.ParentId > 0 {
+				checkExcelInfoId = excelInfo.ParentId
+			}
+		}
+		if checkExcelInfoId != excelInfo.ExcelInfoId {
+			checkExcelInfo, err = excelModel.GetExcelInfoById(checkExcelInfoId)
+			if err != nil {
+				errMsg = "获取平衡表格信息失败"
+				err = fmt.Errorf("获取平衡表格信息失败,Err:" + err.Error())
+				return
+			}
+		}
+		// 数据权限
+		haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUser.AdminId)
+		if e != nil {
+			errMsg = "获取ETA表格权限失败"
+			err = fmt.Errorf("获取表格权限信息失败,Err" + e.Error())
+			return
+		}
+
+		button := excelService.GetBalanceExcelInfoOpButton(sysUser.AdminId, checkExcelInfo.SysUserId, haveOperaAuth, checkExcelInfo.ExcelInfoId)
+		if !button.OpButton {
+			errMsg = "无操作权限"
+			isSendEmail = false
+			return
+		}
+	}
+	*/
+	//查询已有的mapping
+	mapping, err := excelModel.GetExcelChartEdbMappingByChartInfoId(req.ChartInfoId)
+	if err != nil {
+		errMsg = "查询图表mapping失败!"
+		err = fmt.Errorf("查询图表mapping失败!%s", err.Error())
+		return
+	}
+	deleteMap := make(map[int]int)
+	for _, v := range mapping {
+		deleteMap[v.ExcelChartEdbId] = v.ExcelChartEdbId
+	}
+
+	// 查询edbIds
+	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
+	for _, chartEdb := range req.ChartEdbInfoList {
+		if _, ok := deleteMap[chartEdb.ExcelChartEdbId]; ok {
+			delete(deleteMap, chartEdb.ExcelChartEdbId)
+		}
+		excelChartEdbId := chartEdb.ExcelChartEdbId
+		excelEdb, tmpErr := excelModel.GetExcelChartEdbById(excelChartEdbId)
+		if tmpErr != nil {
+			if tmpErr.Error() == utils.ErrNoRow() {
+				errMsg = "指标不存在!"
+				err = errors.New("指标不存在,edbInfoId:" + strconv.Itoa(excelChartEdbId))
+				return
+			} else {
+				errMsg = "获取指标信息失败!"
+				err = errors.New("获取图表的指标信息失败,Err:" + tmpErr.Error())
+				return
+			}
+		}
+
+		if excelEdb == nil {
+			errMsg = "指标已被删除,请重新选择!"
+			err = errors.New("指标不存在,ChartInfoId:" + strconv.Itoa(req.ChartInfoId))
+			return
+		} else {
+			if excelEdb.ExcelChartEdbId <= 0 {
+				errMsg = "指标已被删除,请重新选择!"
+				err = errors.New("指标不存在,ChartInfoId:" + strconv.Itoa(req.ChartInfoId))
+				return
+			}
+		}
+		excelEdb.EdbName = chartEdb.EdbName
+		excelEdb.DateSequence = chartEdb.DateSequenceStr
+		excelEdb.DataSequence = chartEdb.DataSequenceStr
+		excelEdb.MaxData = chartEdb.MaxData
+		excelEdb.MinData = chartEdb.MinData
+		excelEdb.IsOrder = chartEdb.IsOrder
+		excelEdb.IsAxis = chartEdb.IsAxis
+		excelEdb.FromTag = chartEdb.FromTag
+		excelEdb.EdbInfoType = chartEdb.EdbInfoType
+		excelEdb.LeadValue = chartEdb.LeadValue
+		excelEdb.LeadUnit = chartEdb.LeadUnit
+		excelEdb.ModifyTime = time.Now()
+		var dateList []string
+		var dataList []float64
+		if excelInfo.BalanceType == 1 {
+			// 如果是静态表,则直接使用前端传输的数据落到数据库里
+			/*dateList, dataList, err, errMsg = utils.HandleEdbSequenceVal(chartEdb.DateSequenceVal, chartEdb.DataSequenceVal)
+			if err != nil {
+				errMsg = "时间序列或数据序列异常!"
+				err = fmt.Errorf("时间序列或数据序列异常!%s", err.Error())
+				return
+			}*/
+		}
+
+		// 处理日期列表和值列表
+		addItem := &excelModel.AddChartEdbAndDataItem{
+			ChartEdb: excelEdb,
+			DateList: dateList,
+			ValList:  dataList,
+		}
+		chartEdbList = append(chartEdbList, addItem)
+	}
+	chartInfo, err, errMsg, isSendEmail = editBalanceExcelChart(req)
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表失败!%s, %s", errMsg, err.Error())
+		return
+	}
+	obj := new(excelModel.ExcelChartEdb)
+	//删除原先多余的指标
+	deleteEdbIds := make([]int, 0)
+	for k, _ := range deleteMap {
+		deleteEdbIds = append(deleteEdbIds, k)
+	}
+	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, deleteEdbIds)
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表数据失败!%s", err.Error())
+		return
+	}
+	return
+}
+
+func editBalanceExcelChart(req request.AddBalanceTableChartReq) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true // 默认错误的时候要发送邮件
+	chartType := req.ChartType
+	extraConfig := req.ExtraConfig
+
+	chartInfo, err = data_manage.GetChartInfoById(req.ChartInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "图表已被删除,请刷新页面"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		errMsg = "获取图表信息失败"
+		err = errors.New("获取图表信息失败,Err:" + err.Error())
+		return
+	}
+	// todo 查找默认主题设置
+	// todo 查找默认主题设置
+	// 查找主题类型id
+	chartThemeType, err := chart_theme.GetChartThemeTypeByChartType(chartType)
+	if err != nil {
+		errMsg = "查找主题类型失败!"
+		err = fmt.Errorf("%s, %s", errMsg, err.Error())
+		return
+	}
+	chartThemeId := chartThemeType.DefaultChartThemeId
+	// 季节性图表额外配置信息
+	var seasonExtraConfig string
+
+	if chartType == 2 {
+		// 处理季节性图表横轴配置
+		{
+			if req.SeasonExtraConfig.XEndDate != "" {
+				if req.SeasonExtraConfig.XStartDate > req.SeasonExtraConfig.XEndDate && req.SeasonExtraConfig.JumpYear != 1 {
+					errMsg = "季节性图表配置信息异常:横坐标日期配置错误"
+					err = fmt.Errorf("季节性图表配置信息异常: 横坐标日期配置错误")
+					return
+				}
+				seasonExtra, tErr := json.Marshal(req.SeasonExtraConfig)
+				if tErr != nil {
+					errMsg = "季节性图表配置信息异常"
+					err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
+					return
+				}
+
+				seasonExtraConfig = string(seasonExtra)
+			}
+		}
+	}
+
+	/*var extraConfigEdbInfoIdArr []int
+	extraConfigEdbInfoIdArr, err, errMsg = CheckChartExtraConfig(req.ChartType, req.ExtraConfig)
+	if err != nil {
+		err = errors.New("添加失败:" + err.Error())
+		return
+	}*/
+
+	// 图表额外配置
+	extraConfig, err, errMsg = HandleExtraConfig(chartType, extraConfig)
+	if err != nil {
+		if errMsg == `` {
+			errMsg = "指标异常!"
+		}
+		err = fmt.Errorf("指标异常!Err:" + err.Error())
+		return
+	}
+
+	//判断图表是否存在
+	var condition string
+	var pars []interface{}
+	condition += " AND chart_info_id<>? "
+	pars = append(pars, req.ChartInfoId)
+	// 图表名称在不同图分类下不允许重复 需求调整时间:2022年11月07日09:47:07
+	condition += " AND chart_classify_id=0 "
+
+	condition += " AND chart_name=? AND source = ? "
+	pars = append(pars, req.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)
+
+	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
+	if err != nil {
+		errMsg = "判断图表名称是否存在失败"
+		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
+		return
+	}
+
+	if count > 0 {
+		errMsg = "图表已存在,请重新填写"
+		err = fmt.Errorf("判断图表名称是否存在失败")
+		isSendEmail = false
+		return
+	}
+	// todo 判断是否是禁用的图表
+	//	disableVal := data.CheckIsDisableChart(edbInfoIdArr)
+	chartInfo.ChartName = req.ChartName
+	//chartInfo.EdbInfoIds = edbInfoIdStr
+	//chartInfo.ChartClassifyId = req.ChartClassifyId
+	chartInfo.ModifyTime = time.Now()
+	chartInfo.IsSetName = 0
+	// todo 判断是否需要重新计算用户的start_date
+	chartInfo.DateType = 3
+
+	if chartType == 0 {
+		chartType = 1
+	}
+	chartInfo.ChartType = chartType
+
+	calendar := req.Calendar
+	if calendar == "" {
+		calendar = "公历"
+	}
+
+	chartInfo.Calendar = calendar
+	/*	chartInfo.StartDate = req.StartDate
+		chartInfo.EndDate = req.EndDate
+		chartInfo.SeasonStartDate = req.StartDate
+		chartInfo.SeasonEndDate = req.EndDate*/
+	chartInfo.LeftMin = req.LeftMin
+	chartInfo.LeftMax = req.LeftMax
+	chartInfo.RightMin = req.RightMin
+	chartInfo.RightMax = req.RightMax
+	chartInfo.Right2Min = req.Right2Min
+	chartInfo.Right2Max = req.Right2Max
+	chartInfo.MinMaxSave = req.MinMaxSave
+	//chartInfo.Disabled = disableVal
+	//chartInfo.BarConfig = barChartConf
+	chartInfo.ExtraConfig = extraConfig
+	chartInfo.SeasonExtraConfig = seasonExtraConfig
+	//chartInfo.StartYear = req.StartYear
+	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
+	chartInfo.ChartThemeId = chartThemeId
+	chartInfo.SourcesFrom = req.SourcesFrom
+	/*	chartInfo.Instructions = req.Instructions
+		chartInfo.MarkersLines = req.MarkersLines
+		chartInfo.MarkersAreas = req.MarkersAreas
+		chartInfo.Unit = req.Unit
+		chartInfo.UnitEn = req.UnitEn*/
+	/*newId, err := data_manage.AddChartInfo(chartInfo)
+	if err != nil {
+		errMsg = `保存失败`
+		err = fmt.Errorf("保存失败,Err:" + err.Error())
+		return
+	}
+	chartInfo.ChartInfoId = int(newId)*/
+
+	//添加es数据
+	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+
+	return
+}
+
+func GetBalanceExcelChartDetail(chartInfo *data_manage.ChartInfoView, mappingListTmp []*excelModel.ExcelChartEdb, sysUser *system.Admin, dataListMap map[int][]*data_manage.EdbDataList) (resp *data_manage.ChartInfoDetailResp, err error, errMsg string) {
+	// 图表数据权限
+	{
+		// 已授权分类id
+		permissionChartIdList, permissionClassifyIdList, e := data_manage_permission.GetUserChartAndClassifyPermissionList(sysUser.AdminId, chartInfo.ChartInfoId, chartInfo.ChartClassifyId)
+		if e != nil {
+			errMsg = "获取失败"
+			err = fmt.Errorf("获取已授权分类id数据失败,Err:" + err.Error())
+			return
+		}
+		chartInfo.HaveOperaAuth = data_manage_permission.CheckChartPermissionByPermissionIdList(chartInfo.IsJoinPermission, 0, chartInfo.ChartInfoId, chartInfo.ChartClassifyId, permissionChartIdList, permissionClassifyIdList)
+	}
+
+	chartInfoId := chartInfo.ChartInfoId
+	resp = new(data_manage.ChartInfoDetailResp)
+
+	// 获取主题样式
+	chartTheme, err := GetChartThemeConfig(chartInfo.ChartThemeId, 1, chartInfo.ChartType)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取主题信息失败 Err:%s", err.Error())
+		return
+	}
+	chartInfo.ChartThemeStyle = chartTheme.Config
+	chartInfo.ChartThemeId = chartTheme.ChartThemeId
+
+	dateType := chartInfo.DateType
+	fmt.Println("dateType:", dateType)
+
+	chartType := chartInfo.ChartType
+	startDate := chartInfo.StartDate
+	endDate := chartInfo.EndDate
+	seasonStartDate := chartInfo.SeasonStartDate
+	seasonEndDate := chartInfo.SeasonEndDate
+	startYear := chartInfo.StartYear
+
+	calendar := chartInfo.Calendar
+
+	if calendar == "" {
+		calendar = "公历"
+	}
+
+	mappingList := make([]*data_manage.ChartEdbInfoMapping, 0)
+	//循环组装映射关系
+	for _, v := range mappingListTmp {
+		dataList := make([]*data_manage.EdbDataList, 0)
+		dataListTmp, ok := dataListMap[v.ExcelChartEdbId]
+		if ok {
+			dataList = dataListTmp
+		} else {
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.ExcelChartEdbId))
+			return
+		}
+		startDateStr, endDateStr, _, endVal, maxValue, minValue := getBalanceDataListStartDateAndValue(dataList)
+		mapping := &data_manage.ChartEdbInfoMapping{
+			EdbInfoId:         v.ExcelChartEdbId,
+			SourceName:        "",
+			Source:            0,
+			SubSource:         0,
+			EdbCode:           v.EdbCode,
+			EdbName:           v.EdbName,
+			EdbAliasName:      v.EdbName,
+			EdbNameEn:         "",
+			EdbAliasNameEn:    "",
+			EdbType:           0,
+			Frequency:         "",
+			FrequencyEn:       "",
+			Unit:              "",
+			UnitEn:            "",
+			StartDate:         startDateStr,
+			EndDate:           endDateStr,
+			ModifyTime:        v.ModifyTime.Format(utils.FormatDateTime),
+			ChartEdbMappingId: v.ExcelChartEdbId,
+			ChartInfoId:       chartInfoId,
+			MaxData:           v.MaxData,
+			MinData:           v.MinData,
+			IsOrder:           v.IsOrder,
+			IsAxis:            v.IsAxis,
+			//EdbInfoType:         0,
+			//EdbInfoCategoryType: 0,
+			LeadValue:         v.LeadValue,
+			LeadUnit:          v.LeadUnit,
+			LeadUnitEn:        "",
+			ChartStyle:        "",
+			ChartColor:        "",
+			PredictChartColor: "",
+			ChartWidth:        v.ChartWidth,
+			ChartType:         chartType,
+			LatestDate:        endDateStr,
+			LatestValue:       endVal,
+			MoveLatestDate:    "",
+			UniqueCode:        "",
+			MinValue:          minValue,
+			MaxValue:          maxValue,
+			DataList:          nil,
+			IsNullData:        false,
+			MappingSource:     0,
+			RegionType:        "",
+			ClassifyId:        0,
+			IsConvert:         0,
+			ConvertType:       0,
+			ConvertValue:      0,
+			ConvertUnit:       "",
+			ConvertEnUnit:     "",
+			IsJoinPermission:  0,
+			HaveOperaAuth:     true,
+		}
+		mappingList = append(mappingList, mapping)
+	}
+	if chartType == 2 {
+		startDate = seasonStartDate
+		endDate = seasonEndDate
+		if dateType <= 0 {
+			if startDate != "" {
+				dateType = 5
+			} else {
+				dateType = utils.DateTypeNYears
+			}
+		}
+	} else {
+		if dateType <= 0 {
+			dateType = 3
+		}
+	}
+	yearMax := 0
+	if dateType == utils.DateTypeNYears {
+		for _, v := range mappingList {
+			if v.LatestDate != "" {
+				lastDateT, tErr := time.Parse(utils.FormatDate, v.LatestDate)
+				if tErr != nil {
+					errMsg = "获取失败"
+					err = fmt.Errorf("获取图表日期信息失败,Err:" + tErr.Error())
+					return
+				}
+				if lastDateT.Year() > yearMax {
+					yearMax = lastDateT.Year()
+				}
+			}
+		}
+	}
+	startDate, endDate = utils.GetDateByDateTypeV2(dateType, startDate, endDate, startYear, yearMax)
+
+	if chartInfo.ChartType == 2 {
+		chartInfo.StartDate = startDate
+		chartInfo.EndDate = endDate
+	}
+	// 图表额外数据参数
+	extraConfigStr := chartInfo.ExtraConfig
+	// 柱方图的一些配置
+	var barConfig data_manage.BarChartInfoReq
+	if chartInfo != nil && chartInfo.ChartType == 7 {
+		if chartInfo.BarConfig == `` {
+			err = fmt.Errorf("柱方图未配置")
+			errMsg = "柱方图未配置"
+			return
+		}
+		err = json.Unmarshal([]byte(chartInfo.BarConfig), &barConfig)
+		if err != nil {
+			err = fmt.Errorf("柱方图配置异常 json.Unmarshal Err:%s", err.Error())
+			errMsg = "柱方图配置异常"
+			return
+		}
+		extraConfigStr = chartInfo.BarConfig
+	}
+	// 获取表格数据
+
+	excelChartInfoDataShow := new(ExcelChartInfoDataShow)
+	excelChartInfoDataShow.DataListMap = dataListMap
+
+	if chartInfo.HaveOperaAuth {
+		// 获取图表中的指标数据
+		edbList, xEdbIdValue, yDataList, dataResp, e, msg := GetChartEdbDataV2(chartInfoId, chartType, calendar, startDate, endDate, mappingList, extraConfigStr, chartInfo.SeasonExtraConfig, excelChartInfoDataShow)
+		if e != nil {
+			err = fmt.Errorf("获取图表,指标数据失败,Err:%s", e.Error())
+			errMsg = msg
+			return
+		}
+		// 单位
+		if chartType == utils.CHART_TYPE_BAR && len(yDataList) > 0 {
+			chartInfo.Unit = yDataList[0].Unit
+			chartInfo.UnitEn = yDataList[0].UnitEn
+		}
+		warnEdbList := make([]string, 0)
+		for _, v := range edbList {
+			if v.IsNullData {
+				warnEdbList = append(warnEdbList, v.EdbName+"("+v.EdbCode+")")
+			}
+		}
+		if len(warnEdbList) > 0 {
+			chartInfo.WarnMsg = `图表引用指标异常,异常指标:` + strings.Join(warnEdbList, ",")
+		}
+		if chartInfoId > 0 && chartInfo != nil {
+			//判断是否加入我的图库
+			{
+				var myChartCondition string
+				var myChartPars []interface{}
+				myChartCondition += ` AND a.admin_id=? `
+				myChartPars = append(myChartPars, sysUser.AdminId)
+				myChartCondition += ` AND a.chart_info_id=? `
+				myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+				myChartList, e := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+				if e != nil && e.Error() != utils.ErrNoRow() {
+					errMsg = "获取失败"
+					err = fmt.Errorf("获取我的图表信息失败,GetMyChartByCondition,Err:" + e.Error())
+					return
+				}
+				if myChartList != nil && len(myChartList) > 0 {
+					chartInfo.IsAdd = true
+					chartInfo.MyChartId = myChartList[0].MyChartId
+					chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+				}
+			}
+		}
+		//判断是否需要展示英文标识
+		chartInfo.IsEnChart = CheckIsEnChart(chartInfo.ChartNameEn, edbList, chartInfo.Source, chartInfo.ChartType)
+
+		// 图表的指标来源
+		sourceNameList, sourceNameEnList := GetEdbSourceByEdbInfoIdList(edbList)
+
+		chartInfo.ChartSource = strings.Join(sourceNameList, ",")
+		chartInfo.ChartSourceEn = strings.Join(sourceNameEnList, ",")
+
+		// todo 指标权限
+		{
+			for _, item := range edbList {
+				// 数据权限
+				item.HaveOperaAuth = true
+			}
+		}
+
+		resp.EdbInfoList = edbList
+		resp.XEdbIdValue = xEdbIdValue
+		resp.YDataList = yDataList
+		resp.DataResp = dataResp
+	} else {
+		resp.EdbInfoList = mappingList
+	}
+
+	//图表操作权限
+	chartInfo.IsEdit = CheckOpChartPermission(sysUser, chartInfo.SysUserId, chartInfo.HaveOperaAuth)
+	chartInfo.Button = data_manage.ChartViewButton{
+		IsEdit:    chartInfo.IsEdit,
+		IsEnChart: chartInfo.IsEnChart,
+		IsAdd:     chartInfo.IsAdd,
+		IsCopy:    true,
+		IsSetName: chartInfo.IsSetName,
+	}
+
+	resp.ChartInfo = chartInfo
+	resp.BarChartInfo = barConfig
+	return
+}
+
+// GetBalanceExcelEdbDataMapList 获取指标最后的基础数据
+func GetBalanceExcelEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string, dataListMap map[int][]*data_manage.EdbDataList) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
+
+	for _, v := range mappingList {
+		//fmt.Println("v:", v.EdbInfoId)
+		item := new(data_manage.ChartEdbInfoMapping)
+		item.EdbInfoId = v.EdbInfoId
+		item.SourceName = v.SourceName
+		item.Source = v.Source
+		item.EdbCode = v.EdbCode
+		item.EdbName = v.EdbName
+		item.EdbNameEn = v.EdbNameEn
+		item.Frequency = v.Frequency
+		item.EdbType = v.EdbType
+		item.FrequencyEn = GetFrequencyEn(v.Frequency)
+		if v.Unit != `无` {
+			item.Unit = v.Unit
+		}
+		item.UnitEn = v.UnitEn
+		item.StartDate = v.StartDate
+		item.EndDate = v.EndDate
+		item.ModifyTime = v.ModifyTime
+		item.EdbInfoCategoryType = v.EdbInfoCategoryType
+		item.PredictChartColor = v.PredictChartColor
+		item.ClassifyId = v.ClassifyId
+		if chartInfoId <= 0 {
+			item.IsAxis = 1
+			item.LeadValue = 0
+			item.LeadUnit = ""
+			item.ChartEdbMappingId = 0
+			item.ChartInfoId = 0
+			item.IsOrder = false
+			item.EdbInfoType = 1
+			item.ChartStyle = ""
+			item.ChartColor = ""
+			item.ChartWidth = 0
+			item.MaxData = v.MaxValue
+			item.MinData = v.MinValue
+		} else {
+			item.IsAxis = v.IsAxis
+			item.EdbInfoType = v.EdbInfoType
+			item.LeadValue = v.LeadValue
+			item.LeadUnit = v.LeadUnit
+			item.LeadUnitEn = GetLeadUnitEn(v.LeadUnit)
+			item.ChartEdbMappingId = v.ChartEdbMappingId
+			item.ChartInfoId = v.ChartInfoId
+			item.ChartStyle = v.ChartStyle
+			item.ChartColor = v.ChartColor
+			item.ChartWidth = v.ChartWidth
+			item.IsOrder = v.IsOrder
+			item.MaxData = v.MaxData
+			item.MinData = v.MinData
+		}
+		item.LatestValue = v.LatestValue
+		item.LatestDate = v.LatestDate
+		item.UniqueCode = v.UniqueCode
+		item.MoveLatestDate = v.LatestDate
+		item.EdbAliasName = v.EdbAliasName
+		item.IsConvert = v.IsConvert
+		item.ConvertType = v.ConvertType
+		item.ConvertValue = v.ConvertValue
+		item.ConvertUnit = v.ConvertUnit
+		item.ConvertEnUnit = v.ConvertEnUnit
+		item.IsJoinPermission = v.IsJoinPermission
+
+		var startDateReal string
+		var diffSeconds int64
+		if chartType == 2 { //季节性图
+			startDateReal = startDate
+		} else {
+			if v.EdbInfoType == 0 && v.LeadUnit != "" && v.LeadValue > 0 { //领先指标
+				var startTimeRealTemp time.Time
+				startDateParse, _ := time.Parse(utils.FormatDate, startDate)
+				switch v.LeadUnit {
+				case "天":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -v.LeadValue)
+				case "月":
+					startTimeRealTemp = startDateParse.AddDate(0, -v.LeadValue, 0)
+				case "季":
+					startTimeRealTemp = startDateParse.AddDate(0, -3*v.LeadValue, 0)
+				case "周":
+					startTimeRealTemp = startDateParse.AddDate(0, 0, -7*v.LeadValue)
+				case "年":
+					startTimeRealTemp = startDateParse.AddDate(-v.LeadValue, 0, 0)
+				}
+				if startTimeRealTemp.Before(startDateParse) {
+					startDateReal = startTimeRealTemp.Format(utils.FormatDate)
+					diffSeconds = (int64(startTimeRealTemp.UnixNano()) - int64(startDateParse.UnixNano())) / 1e6
+				} else {
+					startDateReal = startDate
+					diffSeconds = 0
+				}
+
+				// 预测指标的开始日期也要偏移
+				{
+					day, tmpErr := utils.GetDaysBetween2Date(utils.FormatDate, startDate, startDateReal)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					moveLatestDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, item.MoveLatestDate, time.Local)
+					if tmpErr != nil {
+						err = tmpErr
+						return
+					}
+					item.MoveLatestDate = moveLatestDateTime.AddDate(0, 0, day).Format(utils.FormatDate)
+				}
+			} else {
+				startDateReal = startDate
+			}
+		}
+		//fmt.Println("line 1011 chart:", v.Source, v.EdbInfoId, startDateReal, endDate)
+		calendarPreYear := 0
+		if calendar == "农历" {
+			newStartDateReal, e := time.Parse(utils.FormatDate, startDateReal)
+			if e != nil {
+				err = fmt.Errorf("时间解析 time.Parse(%s, %s) error: %v", utils.FormatDate, startDateReal, e)
+				return
+			}
+			calendarPreYear = newStartDateReal.Year() - 1
+			newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
+			startDateReal = newStartDateReal.Format(utils.FormatDate)
+		}
+		dataList := make([]*data_manage.EdbDataList, 0)
+		dataListTmp, ok := dataListMap[v.EdbInfoId]
+		if ok {
+			dataList = dataListTmp
+		} else {
+			err = errors.New(fmt.Sprint("获取失败,指标类型异常", v.EdbInfoId))
+			return
+		}
+		if v.IsConvert == 1 {
+			switch v.ConvertType {
+			case 1:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value * v.ConvertValue
+				}
+				//item.MaxData = item.MaxData * v.ConvertValue
+				//item.MinData = item.MinData * v.ConvertValue
+			case 2:
+				for i, data := range dataList {
+					dataList[i].Value = data.Value / v.ConvertValue
+				}
+				//item.MaxData = item.MaxData / v.ConvertValue
+				//item.MinData = item.MinData / v.ConvertValue
+			case 3:
+				for i, data := range dataList {
+					if data.Value <= 0 {
+						err = errors.New("数据中含有负数或0,无法对数运算")
+						return
+					}
+					dataList[i].Value = math.Log(data.Value) / math.Log(v.ConvertValue)
+				}
+				//item.MaxData = math.Log(item.MaxData) / math.Log(v.ConvertValue)
+				//item.MinData = math.Log(item.MinData) / math.Log(v.ConvertValue)
+			}
+		}
+
+		edbDataListMap[v.EdbInfoId] = dataList
+
+		if diffSeconds != 0 && v.EdbInfoType == 0 {
+			dataListLen := len(dataList)
+			for i := 0; i < dataListLen; i++ {
+				dataList[i].DataTimestamp = dataList[i].DataTimestamp - diffSeconds
+			}
+		}
+
+		if chartType == 2 {
+			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
+			if tmpErr != nil {
+				//item.DataList = dataList
+				item.IsNullData = true
+				edbList = append(edbList, item)
+				continue
+			}
+
+			if calendar == "农历" {
+				if len(dataList) <= 0 {
+					result := new(data_manage.EdbDataResult)
+					item.DataList = result
+				} else {
+					result, tmpErr := data_manage.AddCalculateQuarterV6(dataList)
+					if tmpErr != nil {
+						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
+						return
+					}
+					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					if tErr != nil {
+						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+						return
+					}
+					item.DataList = quarterDataList
+				}
+
+			} else {
+				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				if tErr != nil {
+					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
+					return
+				}
+				item.DataList = quarterDataList
+			}
+
+		} else if chartType == 7 || chartType == utils.CHART_TYPE_RADAR { //柱方图
+			//item.DataList = dataList
+		} else {
+			item.DataList = dataList
+		}
+		edbList = append(edbList, item)
+	}
+
+	return
+}
+
+func CheckBalanceChartCacheAndPermission(chartInfo *data_manage.ChartInfoView, isCache bool, sysUser *system.Admin) (resp *data_manage.ChartInfoDetailFromUniqueCodeResp, isOk bool, msg, errMsg string) {
+	//判断是否存在缓存,如果存在缓存,那么直接从缓存中获取
+	adminId := sysUser.AdminId
+	// todo 图表数据权限
+	// 已授权分类id
+	permissionChartIdList, permissionClassifyIdList, err := data_manage_permission.GetUserChartAndClassifyPermissionList(adminId, chartInfo.ChartInfoId, chartInfo.ChartClassifyId)
+	if err != nil {
+		errMsg = "获取已授权分类id数据失败,Err:" + err.Error()
+		return
+	}
+
+	defer func() {
+		if isOk {
+			// 图表权限校验
+			{
+				resp.ChartInfo.HaveOperaAuth = data_manage_permission.CheckChartPermissionByPermissionIdList(chartInfo.IsJoinPermission, 0, chartInfo.ChartInfoId, chartInfo.ChartClassifyId, permissionChartIdList, permissionClassifyIdList)
+
+				//图表操作权限
+				chartInfo.IsEdit = CheckOpChartPermission(sysUser, chartInfo.SysUserId, resp.ChartInfo.HaveOperaAuth)
+				chartInfo.Button = data_manage.ChartViewButton{
+					IsEdit:    chartInfo.IsEdit,
+					IsEnChart: chartInfo.IsEnChart,
+					IsAdd:     chartInfo.IsAdd,
+					IsCopy:    true,
+					IsSetName: chartInfo.IsSetName,
+				}
+
+				//if !resp.ChartInfo.HaveOperaAuth {
+				//	for _, v := range resp.EdbInfoList {
+				//		v.DataList = nil
+				//	}
+				//	resp.DataResp = nil
+				//	resp.XEdbIdValue = []int{}
+				//	resp.YDataList = []data_manage.YData{}
+				//}
+			}
+
+			// todo 是否需要返回平衡表指标权限即判断平衡表的表格数据权限
+			{
+				// 查询图表关联的表格ID
+				excelInfo, e := excelModel.GetExcelInfoByChartInfoId(chartInfo.ChartInfoId)
+				if e != nil {
+					errMsg = "获取图表关联的表格ID失败,Err:" + e.Error()
+					err = e
+					return
+				}
+				checkExcelInfo := excelInfo
+				if excelInfo.Source == utils.BALANCE_TABLE {
+					checkExcelInfoId := excelInfo.ExcelInfoId
+					if excelInfo.BalanceType == 1 {
+						checkExcelInfoId = excelInfo.RelExcelInfoId
+					} else {
+						if excelInfo.ParentId > 0 {
+							checkExcelInfoId = excelInfo.ParentId
+						}
+					}
+					if checkExcelInfoId != excelInfo.ExcelInfoId {
+						checkExcelInfo, err = excelModel.GetExcelInfoById(checkExcelInfoId)
+						if err != nil {
+							errMsg = "获取平衡表格信息失败"
+							err = errors.New("获取平衡表格信息失败,Err:" + err.Error())
+							return
+						}
+					}
+				}
+
+				haveOperaAuth, e := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, adminId)
+				if e != nil {
+					errMsg = "获取平衡表格数据权限失败"
+					err = errors.New("获取表格权限信息失败,Err" + e.Error())
+					return
+				}
+				// 数据权限
+				for _, v := range resp.EdbInfoList {
+					v.HaveOperaAuth = haveOperaAuth
+				}
+			}
+		}
+	}()
+	key := GetChartInfoDataKey(chartInfo.ChartInfoId)
+	if utils.Re == nil && isCache {
+		if utils.Re == nil && utils.Rc.IsExist(key) {
+			if redisData, err1 := utils.Rc.RedisBytes(key); err1 == nil {
+				err := json.Unmarshal(redisData, &resp)
+				if err != nil || resp == nil {
+					return
+				}
+				// 这里跟当前用户相关的信息重新查询写入resp, 不使用缓存中的
+				var myCond string
+				var myPars []interface{}
+				myCond += ` AND a.admin_id=? `
+				myPars = append(myPars, adminId)
+				myCond += ` AND a.chart_info_id=? `
+				myPars = append(myPars, chartInfo.ChartInfoId)
+				myList, err := data_manage.GetMyChartByCondition(myCond, myPars)
+				if err != nil && err.Error() != utils.ErrNoRow() {
+					msg = "获取失败"
+					errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+					return
+				}
+				resp.ChartInfo.IsAdd = false
+				resp.ChartInfo.MyChartId = 0
+				resp.ChartInfo.MyChartClassifyId = ""
+				if myList != nil && len(myList) > 0 {
+					resp.ChartInfo.IsAdd = true
+					resp.ChartInfo.MyChartId = myList[0].MyChartId
+					resp.ChartInfo.MyChartClassifyId = myList[0].MyChartClassifyId
+				}
+
+				//判断是否加入我的图库
+				{
+					var myChartCondition string
+					var myChartPars []interface{}
+					myChartCondition += ` AND a.admin_id=? `
+					myChartPars = append(myChartPars, adminId)
+					myChartCondition += ` AND a.chart_info_id=? `
+					myChartPars = append(myChartPars, chartInfo.ChartInfoId)
+
+					myChartList, err := data_manage.GetMyChartByCondition(myChartCondition, myChartPars)
+					if err != nil && err.Error() != utils.ErrNoRow() {
+						msg = "获取失败"
+						errMsg = "获取我的图表信息失败,GetMyChartByCondition,Err:" + err.Error()
+						return
+					}
+					if myChartList != nil && len(myChartList) > 0 {
+						chartInfo.IsAdd = true
+						chartInfo.MyChartId = myChartList[0].MyChartId
+						chartInfo.MyChartClassifyId = myChartList[0].MyChartClassifyId
+					}
+				}
+
+				isOk = true
+				fmt.Println("source redis")
+				return
+			}
+		}
+	}
+	return
+}
+
+// GetBalanceExcelSeasonChartLegendPreview 获取预览的季节性图例
+func GetBalanceExcelSeasonChartLegendPreview(dataList []*data_manage.EdbDataList, calendar string, seasonExtraConfigReq data_manage.SeasonExtraItem) (quarterDataList data_manage.QuarterDataList, err error, errMsg string) {
+	seasonExtraConfig := ""
+	if seasonExtraConfigReq.XEndDate != "" {
+		if seasonExtraConfigReq.XStartDate > seasonExtraConfigReq.XEndDate && seasonExtraConfigReq.JumpYear != 1 {
+			errMsg = "季节性图表配置信息异常:横坐标日期配置错误"
+			err = fmt.Errorf("季节性图表配置信息异常: 横坐标日期配置错误")
+			return
+		}
+		seasonExtra, tErr := json.Marshal(seasonExtraConfigReq)
+		if tErr != nil {
+			errMsg = "季节性图表配置信息异常"
+			err = fmt.Errorf("季节性图表配置信息异常,Err:" + tErr.Error())
+			return
+		}
+
+		seasonExtraConfig = string(seasonExtra)
+	}
+	var latestDate time.Time //最新日期
+	startDate, endDate, _, _, _, _ := getBalanceDataListStartDateAndValue(dataList)
+	calendarPreYear := 0
+	startDateReal := startDate
+	latestDate, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
+	if calendar == "农历" {
+		newStartDateReal, e := time.Parse(utils.FormatDate, startDateReal)
+		if e != nil {
+			err = fmt.Errorf("开始时间解析失败 time.Parse:" + e.Error())
+			return
+		}
+		calendarPreYear = newStartDateReal.Year() - 1
+		newStartDateReal = newStartDateReal.AddDate(-1, 0, 0)
+		startDateReal = newStartDateReal.Format(utils.FormatDate)
+	}
+	if calendar == "农历" {
+		if len(dataList) <= 0 {
+			return
+		} else {
+			result, tmpErr := data_manage.AddCalculateQuarterV6(dataList)
+			if tmpErr != nil {
+				err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
+				return
+			}
+			quarterDataList, err = GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+			if err != nil {
+				err = errors.New("获取季节性图表数据失败,Err:" + err.Error())
+				return
+			}
+		}
+
+	} else {
+		quarterDataList, err = GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+		if err != nil {
+			err = errors.New("获取季节性图表数据失败,Err:" + err.Error())
+			return
+		}
+	}
+	return
+}
+
+func getBalanceDataListStartDateAndValue(dataList []*data_manage.EdbDataList) (startDate, endDate string, startVal, endVal, maxVal, minVal float64) {
+	if len(dataList) == 0 {
+		return
+	}
+	startDate = dataList[0].DataTime
+	startVal = dataList[0].Value
+	maxVal = dataList[0].Value
+	minVal = dataList[0].Value
+	endDate = dataList[len(dataList)-1].DataTime
+	endVal = dataList[len(dataList)-1].Value
+	for _, v := range dataList {
+		if v.DataTime < startDate {
+			startDate = v.DataTime
+			startVal = v.Value
+		}
+		if v.DataTime > endDate {
+			endDate = v.DataTime
+			endVal = v.Value
+		}
+		if v.Value > maxVal {
+			maxVal = v.Value
+		}
+		if v.Value < minVal {
+			minVal = v.Value
+		}
+	}
+	return
+}
+
+// AddBalanceStaticExcel 另存为和存为静态表以及子表的复制都调用该接口
+func AddBalanceStaticExcel(oldExcelInfo *excelModel.ExcelInfo, versionName string, sysUser *system.Admin, parentId, relExcelInfoId, balanceType int, childExcelList []*excelModel.ExcelInfo) (excelInfo *excelModel.ExcelInfo, err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true
+
+	versionName = utils.TrimLRStr(versionName)
+	// 检验分类下是否存在该表格名称
+	{
+		var condition string
+		var pars []interface{}
+		condition += " AND rel_excel_info_id=? "
+		pars = append(pars, oldExcelInfo.ExcelInfoId)
+
+		condition += " AND version_name=? "
+		pars = append(pars, versionName)
+
+		count, tmpErr := excelModel.GetExcelInfoCountByCondition(condition, pars)
+		if tmpErr != nil {
+			errMsg = "查询版本号失败"
+			err = tmpErr
+			return
+		}
+		if count > 0 {
+			errMsg = "表格版本号已存在,请重新填写表格名称"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+	}
+
+	// 表格信息
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	excelName := oldExcelInfo.ExcelName
+	if parentId == 0 {
+		excelName += "(" + versionName + ")"
+	}
+
+	// 处理表格内容, 静态表去除动态指标关联
+	content := oldExcelInfo.Content
+	excelInfo = &excelModel.ExcelInfo{
+		//ExcelInfoId:     0,
+		ExcelName:          excelName,
+		Source:             oldExcelInfo.Source,
+		ExcelType:          oldExcelInfo.ExcelType,
+		UniqueCode:         utils.MD5(utils.EXCEL_DATA_PREFIX + "_" + timestamp),
+		ExcelClassifyId:    oldExcelInfo.ExcelClassifyId,
+		SysUserId:          sysUser.AdminId,
+		SysUserRealName:    sysUser.RealName,
+		Content:            content,
+		ExcelImage:         oldExcelInfo.ExcelImage,
+		FileUrl:            oldExcelInfo.FileUrl,
+		ParentId:           parentId,
+		RelExcelInfoId:     relExcelInfoId,
+		VersionName:        versionName,
+		UpdateUserId:       sysUser.AdminId,
+		UpdateUserRealName: sysUser.AdminName,
+		BalanceType:        balanceType,
+		Sort:               oldExcelInfo.Sort,
+		IsDelete:           0,
+		ModifyTime:         time.Now(),
+		CreateTime:         time.Now(),
+	}
+
+	excelEdbMappingList := make([]*excelModel.ExcelEdbMapping, 0)
+	if balanceType == 1 {
+		// 获取excel与指标的关系表
+		excelEdbMappingList, err = excelModel.GetAllExcelEdbMappingByExcelInfoId(excelInfo.ExcelInfoId)
+		if err != nil {
+			errMsg = "获取失败"
+			return
+		}
+		for k, v := range excelEdbMappingList {
+			v.ExcelEdbMappingId = 0
+			v.ExcelInfoId = 0
+			excelEdbMappingList[k] = v
+		}
+	}
+
+	var childExcel *excelModel.ExcelInfo
+	err = excelModel.AddExcelInfo(excelInfo, excelEdbMappingList, childExcel)
+	if err != nil {
+		errMsg = "保存失败"
+		return
+	}
+	if parentId == 0 && len(childExcelList) > 0 {
+		for _, childExcelInfo := range childExcelList {
+			_, err, errMsg, isSendEmail = AddBalanceStaticExcel(childExcelInfo, versionName, sysUser, excelInfo.ExcelInfoId, relExcelInfoId, balanceType, []*excelModel.ExcelInfo{})
+			if err != nil {
+				return
+			}
+		}
+	} else if parentId > 0 {
+		// 如果复制的是动态表的子表,则同步复制关联的图表
+		// 查出所有的chart_list, 同步复制图表和图表指标
+		// 相关联指标
+		mappingListTmp, e := excelModel.GetExcelChartEdbMappingByExcelInfoId(oldExcelInfo.ExcelInfoId)
+		if e != nil {
+			errMsg = "获取图表指标失败"
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", e.Error())
+			return
+		}
+		mappingListMap := make(map[int][]*excelModel.ExcelChartEdb, 0)
+		charInfoIds := make([]int, 0)
+		for k, _ := range mappingListTmp {
+			mappingListTmp[k].ExcelInfoId = excelInfo.ExcelInfoId
+			mappingListMap[mappingListTmp[k].ChartInfoId] = append(mappingListMap[mappingListTmp[k].ChartInfoId], mappingListTmp[k])
+		}
+		for k, _ := range mappingListMap {
+			charInfoIds = append(charInfoIds, k)
+		}
+		if len(charInfoIds) > 0 {
+			chartInfoList, e := data_manage.GetChartInfoViewByIdList(charInfoIds)
+			if e != nil {
+				errMsg = "获取失败"
+				err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", e.Error())
+				return
+			}
+			for _, chartInfo := range chartInfoList {
+				mappingList, ok := mappingListMap[chartInfo.ChartInfoId]
+				if !ok {
+					err = fmt.Errorf("未找到图表关联的指标信息")
+					return
+				}
+				err, errMsg, isSendEmail = CopyBalanceExcelChart(chartInfo, mappingList, versionName, sysUser)
+				if err != nil {
+					err = fmt.Errorf("复制图表失败 Err:%s", err.Error())
+					return
+				}
+			}
+		}
+	}
+	return
+}
+
+// CopyBalanceExcelChart 复制平衡表图表
+func CopyBalanceExcelChart(oldChartInfo *data_manage.ChartInfoView, oldChartEdbList []*excelModel.ExcelChartEdb, versionName string, sysUser *system.Admin) (err error, errMsg string, isSendEmail bool) {
+	chartEdbList := make([]*excelModel.AddChartEdbAndDataItem, 0)
+	if versionName != "" {
+		oldChartInfo.ChartName += "(" + versionName + ")"
+	}
+	for _, chartEdb := range oldChartEdbList {
+		excelEdb := new(excelModel.ExcelChartEdb)
+		excelEdb.EdbName = chartEdb.EdbName
+		if versionName != "" {
+			excelEdb.EdbName += "(" + versionName + ")"
+		}
+		randStr := utils.GetRandDigit(4)
+		excelEdb.EdbCode = `T` + time.Now().Format("060102150405") + "_" + randStr
+		excelEdb.ExcelInfoId = chartEdb.ExcelInfoId
+		excelEdb.DateSequence = chartEdb.DateSequence
+		excelEdb.DataSequence = chartEdb.DataSequence
+		excelEdb.SysUserId = sysUser.AdminId
+		excelEdb.SysUserRealName = sysUser.RealName
+		excelEdb.MaxData = chartEdb.MaxData
+		excelEdb.MinData = chartEdb.MinData
+		excelEdb.IsOrder = chartEdb.IsOrder
+		excelEdb.IsAxis = chartEdb.IsAxis
+		excelEdb.FromTag = chartEdb.FromTag
+		excelEdb.EdbInfoType = chartEdb.EdbInfoType
+		excelEdb.LeadValue = chartEdb.LeadValue
+		excelEdb.LeadUnit = chartEdb.LeadUnit
+		excelEdb.CreateTime = time.Now()
+		excelEdb.ModifyTime = time.Now()
+		var dateList []string
+		var dataList []float64
+		// todo 是否需要存储静态表的数据
+
+		// 处理日期列表和值列表
+		addItem := &excelModel.AddChartEdbAndDataItem{
+			ChartEdb: excelEdb,
+			DateList: dateList,
+			ValList:  dataList,
+		}
+		chartEdbList = append(chartEdbList, addItem)
+	}
+	chartInfo, err, errMsg, isSendEmail := copyBalanceExcelChart(oldChartInfo, sysUser.AdminId, sysUser.RealName)
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表失败!%s, %s", errMsg, err.Error())
+		return
+	}
+	obj := new(excelModel.ExcelChartEdb)
+	err = obj.AddChartEdbAndData(chartEdbList, chartInfo, []int{})
+	if err != nil {
+		errMsg = "新增图表失败!"
+		err = fmt.Errorf("新增图表数据失败!%s", err.Error())
+		return
+	}
+	return
+}
+
+func copyBalanceExcelChart(oldChartInfo *data_manage.ChartInfoView, sysUserId int, sysUserRealName string) (chartInfo *data_manage.ChartInfo, err error, errMsg string, isSendEmail bool) {
+	isSendEmail = true // 默认错误的时候要发送邮件
+
+	oldChartInfo.ChartName = strings.Trim(oldChartInfo.ChartName, " ")
+	if oldChartInfo.ChartName == "" {
+		errMsg = "请填写图表名称!"
+		err = fmt.Errorf(errMsg)
+		isSendEmail = false
+		return
+	}
+	//判断图表是否存在
+	var condition string
+	var pars []interface{}
+
+	// 图表名称在不同图分类下不允许重复 需求调整时间:2022年11月07日09:47:07
+	condition += " AND chart_classify_id=0 "
+
+	condition += " AND chart_name=? AND source = ? "
+	pars = append(pars, oldChartInfo.ChartName, utils.CHART_SOURCE_BALANCE_EXCEL)
+
+	count, err := data_manage.GetChartInfoCountByCondition(condition, pars)
+	if err != nil {
+		errMsg = "判断图表名称是否存在失败"
+		err = fmt.Errorf("判断图表名称是否存在失败,Err:" + err.Error())
+		return
+	}
+
+	if count > 0 {
+		/*errMsg = "图表已存在,请重新填写"
+		err = fmt.Errorf("判断图表名称是否存在失败")
+		isSendEmail = false
+		return*/
+		oldChartInfo.ChartName += " " + strconv.Itoa(count)
+	}
+
+	chartInfo = new(data_manage.ChartInfo)
+	chartInfo.ChartName = oldChartInfo.ChartName
+	//chartInfo.EdbInfoIds = edbInfoIdStr
+	//chartInfo.ChartClassifyId = req.ChartClassifyId
+	chartInfo.SysUserId = sysUserId
+	chartInfo.SysUserRealName = sysUserRealName
+	chartInfo.CreateTime = time.Now()
+	chartInfo.ModifyTime = time.Now()
+	chartInfo.IsSetName = 0
+	timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
+	chartInfo.UniqueCode = utils.MD5(utils.CHART_PREFIX + "_" + timestamp)
+
+	// todo 判断是否需要重新计算用户的start_date
+	chartInfo.DateType = oldChartInfo.DateType
+	chartInfo.ChartType = oldChartInfo.ChartType
+	chartInfo.Calendar = oldChartInfo.Calendar
+	/*	chartInfo.StartDate = req.StartDate
+		chartInfo.EndDate = req.EndDate
+		chartInfo.SeasonStartDate = req.StartDate
+		chartInfo.SeasonEndDate = req.EndDate*/
+	chartInfo.LeftMin = oldChartInfo.LeftMin
+	chartInfo.LeftMax = oldChartInfo.LeftMax
+	chartInfo.RightMin = oldChartInfo.RightMin
+	chartInfo.RightMax = oldChartInfo.RightMax
+	chartInfo.Right2Min = oldChartInfo.Right2Min
+	chartInfo.Right2Max = oldChartInfo.Right2Max
+	chartInfo.MinMaxSave = oldChartInfo.MinMaxSave
+	//chartInfo.Disabled = disableVal
+	//chartInfo.BarConfig = barChartConf
+	chartInfo.ExtraConfig = oldChartInfo.ExtraConfig
+	chartInfo.SeasonExtraConfig = oldChartInfo.SeasonExtraConfig
+	//chartInfo.StartYear = req.StartYear
+	chartInfo.Source = utils.CHART_SOURCE_BALANCE_EXCEL
+	chartInfo.ChartThemeId = oldChartInfo.ChartThemeId
+	chartInfo.SourcesFrom = oldChartInfo.SourcesFrom
+	/*	chartInfo.Instructions = req.Instructions
+		chartInfo.MarkersLines = req.MarkersLines
+		chartInfo.MarkersAreas = req.MarkersAreas
+		chartInfo.Unit = req.Unit
+		chartInfo.UnitEn = req.UnitEn*/
+	/*newId, err := data_manage.AddChartInfo(chartInfo)
+	if err != nil {
+		errMsg = `保存失败`
+		err = fmt.Errorf("保存失败,Err:" + err.Error())
+		return
+	}
+	chartInfo.ChartInfoId = int(newId)*/
+
+	//添加es数据
+	//go EsAddOrEditChartInfo(chartInfo.ChartInfoId)
+
+	return
+}

+ 30 - 0
services/data/chart_info_interface.go

@@ -0,0 +1,30 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+)
+
+type ChartInfoDataShow interface {
+	GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error)
+}
+
+type BaseChartInfoDataShow struct {
+}
+
+// GetEdbDataMapList 获取指标最后的基础数据
+func (e *BaseChartInfoDataShow) GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err = GetEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig)
+	return
+}
+
+type ExcelChartInfoDataShow struct {
+	DataListMap map[int][]*data_manage.EdbDataList
+}
+
+// GetEdbDataMapList 获取指标最后的基础数据
+func (e *ExcelChartInfoDataShow) GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
+	// 指标对应的所有数据
+	edbDataListMap, edbList, err = GetBalanceExcelEdbDataMapList(chartInfoId, chartType, calendar, startDate, endDate, mappingList, seasonExtraConfig, e.DataListMap)
+	return
+}

+ 4 - 0
services/data/data_manage_permission/data_move.go

@@ -429,6 +429,10 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 		condition += " AND source = ? "
 		pars = append(pars, subSource)
 
+		if subSource == utils.BALANCE_TABLE {
+			condition += " AND parent_id = 0 AND balance_type = 0 "
+		}
+
 		total, err = excel.GetExcelInfoCountByCondition(condition, pars)
 		if err != nil {
 			return

+ 7 - 1
services/data/data_manage_permission/edb_permission.go

@@ -119,7 +119,13 @@ func SetEdbChartPermission(source, subSource, userId int, authUserList []int, is
 	case 6:
 		// ETA表格
 		content += `(ETA表格)`
-		tmpList, tmpErr := excel.GetNoContentExcelListByExcelInfoIdList(dataIdList)
+		tmpList := make([]*excel.MyExcelInfoList, 0)
+		var tmpErr error
+		if subSource == utils.BALANCE_TABLE {
+			tmpList, tmpErr = excel.GetNoContentExcelListByExcelInfoIdAndParentId(dataIdList)
+		} else {
+			tmpList, tmpErr = excel.GetNoContentExcelListByExcelInfoIdList(dataIdList)
+		}
 		if tmpErr != nil {
 			err = tmpErr
 			return

+ 27 - 0
services/data/data_manage_permission/excel.go

@@ -153,3 +153,30 @@ func CheckExcelPermission(excelIsJoinPermission, excelClassifyIsJoinPermission,
 
 	return
 }
+
+func CheckBalanceExcelPermissionByExcelInfoId(excelInfo *excel.ExcelInfo, excelIsJoinPermission, userId int) (hasAuth bool, err error) {
+	// 查询父级ID
+	if excelInfo.Source != utils.BALANCE_TABLE {
+		return
+	}
+	parentId := excelInfo.ParentId
+	if excelInfo.BalanceType == 1 { //静态表关联的动态表的权限
+		parentId = excelInfo.RelExcelInfoId
+	}
+	parentExcelInfo, err := excel.GetExcelInfoById(parentId)
+	if err != nil {
+		err = fmt.Errorf("查询表格信息出错 err: %v", err)
+		return
+	}
+	excelClassifyId := parentExcelInfo.ExcelClassifyId
+	excelInfoId := parentExcelInfo.ExcelInfoId
+	currClassify, err := excel.GetExcelClassifyById(excelClassifyId)
+	if err != nil {
+		return
+	}
+	if currClassify != nil {
+		return CheckExcelPermission(excelIsJoinPermission, currClassify.IsJoinPermission, userId, excelInfoId, excelClassifyId)
+	}
+
+	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
+}

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

+ 452 - 0
services/data/excel/balance_table.go

@@ -0,0 +1,452 @@
+package excel
+
+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/utils"
+	"fmt"
+	"github.com/xuri/excelize/v2"
+	"strconv"
+	"time"
+)
+
+// 将表格信息转化成指标数据
+func GetBalanceExcelData(excelDetail *excelModel.ExcelInfo, lang string) (newDataMap map[int]map[int]request.MixedTableCellDataReq, allRows, allCols int, err error, errMsg string) {
+	var result request.MixedTableReq
+	err = json.Unmarshal([]byte(excelDetail.Content), &result)
+	if err != nil {
+		err = errors.New("表格json转结构体失败,Err:" + err.Error())
+		return
+	}
+	//todo 语言兼容
+	newData, tmpErr, tmpErrMsg := GetMixedTableCellData(result, lang)
+	if tmpErr != nil {
+		errMsg = "获取失败"
+		if tmpErrMsg != `` {
+			errMsg = tmpErrMsg
+		}
+		err = errors.New("获取最新的数据失败,Err:" + tmpErr.Error())
+		return
+	}
+
+	allRows = len(newData)
+	allCols = 0
+	newDataMap = make(map[int]map[int]request.MixedTableCellDataReq)
+	for r, row := range newData {
+		tmp := len(row)
+		if tmp > allCols {
+			allCols = tmp
+		}
+		colMap := make(map[int]request.MixedTableCellDataReq)
+		for c, col := range row {
+			colMap[c] = col
+		}
+		newDataMap[r] = colMap
+	}
+	return
+}
+
+func GetBalanceExcelChartList(excelInfo *excelModel.ExcelInfo, lang string) (list []*data_manage.ChartInfoView, mappingListMap map[int][]*excelModel.ExcelChartEdb, dataListMap map[int][]*data_manage.EdbDataList, err error, errMsg string) {
+	newExcelDataMap, excelAllRows, excelAllCols, err, errMsg := GetBalanceExcelData(excelInfo, lang)
+	if err != nil {
+		return
+	}
+	dataListMap = make(map[int][]*data_manage.EdbDataList)
+	// 相关联指标
+	mappingListTmp, err := excelModel.GetExcelChartEdbMappingByExcelInfoId(excelInfo.ExcelInfoId)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	mappingListMap = make(map[int][]*excelModel.ExcelChartEdb, 0)
+	charInfoIds := make([]int, 0)
+	for _, mapping := range mappingListTmp {
+		mappingListMap[mapping.ChartInfoId] = append(mappingListMap[mapping.ChartInfoId], mapping)
+		err, errMsg = GetBalanceExcelEdbData(mapping, newExcelDataMap, dataListMap, excelAllRows, excelAllCols)
+		if err != nil {
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+			return
+		}
+	}
+	for k, _ := range mappingListMap {
+		charInfoIds = append(charInfoIds, k)
+	}
+	list = make([]*data_manage.ChartInfoView, 0)
+	if len(charInfoIds) > 0 {
+		chartInfoList, e := data_manage.GetChartInfoViewByIdList(charInfoIds)
+		if e != nil {
+			errMsg = "获取失败"
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", e.Error())
+			return
+		}
+		list = chartInfoList
+		/*for _, chartInfo := range chartInfoList {
+			mappingList, ok := mappingListMap[chartInfo.ChartInfoId]
+			if !ok {
+				err = fmt.Errorf("未找到图表关联的指标信息")
+				return
+			}
+			var chartInfoResp *data_manage.ChartInfoDetailResp
+			chartInfoResp, err, errMsg = GetBalanceExcelChartDetail(chartInfo, mappingList, sysUser, dataListMap)
+			if err != nil {
+				return
+			}
+			list = append(list, chartInfoResp)
+		}*/
+	}
+	return
+}
+
+// 将表格信息转化成指标数据
+func GetBalanceExcelEdbData(excelEdbMappingItem *excelModel.ExcelChartEdb, newMixedTableCellDataListMap map[int]map[int]request.MixedTableCellDataReq, dataListMap map[int][]*data_manage.EdbDataList, allRows, allCols int) (err error, errMsg string) {
+	var dateList, dataList []string
+	// 日期序列
+	{
+		_, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(excelEdbMappingItem.DateSequence)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		startNum = startNum - 1
+		endNum = endNum - 1
+		// 选择行的数据
+		if isRow {
+			// 因为是选择一行的数据,所以开始行和结束行时一样的
+			//endNum = startNum - 1
+
+			// 开始列名、结束列
+			var startColumn, endColumn int
+			if isAll {
+				// 结束列(其实也就是整列的个数)
+				endColumn = allCols - 1
+			} else {
+				tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + startColumnName
+					err = errors.New(errMsg)
+					return
+				}
+
+				tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + endColumnName
+					err = errors.New(errMsg)
+					return
+				}
+				startColumn = tmpStartColumn - 1
+				endColumn = tmpEndColumn - 1
+			}
+
+			// 最大列数,如果设置的超过了最大列数,那么结束列就是最大列数
+			maxCol := allCols
+			if endColumn > maxCol {
+				endColumn = maxCol - 1
+			}
+
+			// 长度固定,避免一直申请内存空间
+			dateList = make([]string, endColumn-startColumn+1)
+
+			i := 0
+			for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
+				currCell, ok := newMixedTableCellDataListMap[startNum][currColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currColumn, startNum)
+					err = errors.New(errMsg)
+					return
+				}
+				dateList[i] = currCell.ShowValue
+				i++
+			}
+
+		} else if isColumn { // 选择列的数据
+			if isAll {
+				// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
+				endNum = allRows - 1
+			}
+
+			startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+			if tmpErr != nil {
+				errMsg = "列名异常:" + startColumnName
+				err = errors.New(errMsg)
+				return
+			}
+			startColumn = startColumn - 1
+
+			// 最大行数,如果设置的超过了最大行数,那么结束行就是最大行数
+			maxRow := allRows
+			if endNum > maxRow {
+				endNum = maxRow - 1
+			}
+			// 长度固定,避免一直申请内存空间
+			dateList = make([]string, endNum-startNum+1)
+			i := 0
+			for currRow := startNum; currRow <= endNum; currRow++ {
+				currCell, ok := newMixedTableCellDataListMap[currRow][startColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currRow, startColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dateList = append(dateList, currCell.Value)
+				dateList[i] = currCell.ShowValue
+				i++
+			}
+		}
+
+	}
+
+	// 数据序列
+	{
+		_, startColumnName, endColumnName, startNum, endNum, isAll, isRow, isColumn, tmpErr := GetSheetStr(excelEdbMappingItem.DataSequence)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+
+		startNum = startNum - 1
+		endNum = endNum - 1
+		// 选择行的数据
+		if isRow {
+			// 开始列名、结束列
+			var startColumn, endColumn int
+			if isAll {
+				// 结束列(其实也就是整列的个数)
+				endColumn = allCols - 1
+			} else {
+
+				tmpStartColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + startColumnName
+					err = errors.New(errMsg)
+					return
+				}
+
+				tmpEndColumn, tmpErr := excelize.ColumnNameToNumber(endColumnName)
+				if tmpErr != nil {
+					errMsg = "列名异常:" + endColumnName
+					err = errors.New(errMsg)
+					return
+				}
+				startColumn = tmpStartColumn - 1
+				endColumn = tmpEndColumn - 1
+			}
+
+			// 最大列数,如果设置的超过了最大列数,那么结束列就是最大列数
+			maxCol := allCols
+			if endColumn > maxCol {
+				endColumn = maxCol - 1
+			}
+			// 长度固定,避免一直申请内存空间
+			dataList = make([]string, endColumn-startColumn+1)
+			i := 0
+			for currColumn := startColumn; currColumn <= endColumn; currColumn++ {
+				currCell, ok := newMixedTableCellDataListMap[startNum][currColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", startColumn, currColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dataList = append(dataList, currCell.Value)
+				dataList[i] = currCell.ShowValue
+				i++
+			}
+
+		} else if isColumn { // 选择列的数据
+			if isAll {
+				// 选择一整列的话,结束行得根据实际情况调整(其实也就是整个sheet有多少行)
+				endNum = allRows - 1
+			}
+
+			startColumn, tmpErr := excelize.ColumnNameToNumber(startColumnName)
+			if tmpErr != nil {
+				errMsg = "列名异常:" + startColumnName
+				err = errors.New(errMsg)
+				return
+			}
+			startColumn = startColumn - 1
+
+			// 最大行数,如果设置的超过了最大行数,那么结束行就是最大行数
+			maxRow := allRows
+			if endNum > maxRow {
+				endNum = maxRow - 1
+			}
+
+			// 长度固定,避免一直申请内存空间
+			dataList = make([]string, endNum-startNum+1)
+			i := 0
+			for currRow := startNum; currRow <= endNum; currRow++ {
+				currCell, ok := newMixedTableCellDataListMap[currRow][startColumn]
+				if !ok {
+					errMsg = fmt.Sprintf("第%d列,第%d行数据异常", currRow, startColumn)
+					err = errors.New(errMsg)
+					return
+				}
+				//dataList = append(dataList, currCell.Value)
+				dataList[i] = currCell.ShowValue
+				i++
+			}
+		}
+	}
+
+	//fmt.Println(dateList, dataList)
+	//fmt.Println("日期序列结束")
+
+	// 将excel中的日期、数据系列处理
+	//newDateList, newDataList, err, errMsg := excel2.HandleEdbSequenceVal(dateList, dataList)
+	newDateList, newDataList := dateList, dataList
+	if err != nil {
+		err = fmt.Errorf(" 处理日期和数据系列失败 %s", err.Error())
+		return
+	}
+	newDataMap := make(map[int]float64, len(newDataList))
+	for i, v := range newDataList {
+		val, e := strconv.ParseFloat(v, 64)
+		if e != nil {
+			err = fmt.Errorf(" 处理日期和数据系列失败 %s", e.Error())
+			return
+		}
+		newDataMap[i] = val
+	}
+	//组装成excelEdbData
+	list := make([]*data_manage.EdbDataList, 0)
+
+	for i, v := range newDateList {
+		// todo 处理DataTimestamp
+		dataTime, e := time.ParseInLocation(utils.FormatDate, v, time.Local)
+		if e != nil {
+			err = errors.New("time.Parse Err:" + err.Error())
+			return
+		}
+		timestamp := dataTime.UnixNano() / 1e6
+		tmp := &data_manage.EdbDataList{
+			EdbDataId:     i,
+			EdbInfoId:     excelEdbMappingItem.ExcelChartEdbId,
+			DataTime:      v,
+			DataTimestamp: timestamp,
+			Value:         newDataMap[i],
+		}
+		list = append(list, tmp)
+	}
+	dataListMap[excelEdbMappingItem.ExcelChartEdbId] = list
+	return
+}
+
+// 获取单个图表信息
+func GetBalanceExcelChartSingle(chartInfo *data_manage.ChartInfoView, lang string) (mappingListTmp []*excelModel.ExcelChartEdb, dataListMap map[int][]*data_manage.EdbDataList, err error, errMsg string) {
+	// 相关联指标
+	mappingListTmp, err = excelModel.GetExcelChartEdbMappingByChartInfoId(chartInfo.ChartInfoId)
+	if err != nil {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	if len(mappingListTmp) <= 0 {
+		errMsg = "获取失败"
+		err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	excelInfoId := mappingListTmp[0].ExcelInfoId
+	// 查询所有子表
+	excelInfo, err := excelModel.GetExcelInfoById(excelInfoId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			errMsg = "表格不存在"
+			err = fmt.Errorf(errMsg)
+			return
+		}
+		errMsg = "查询子表失败"
+		err = fmt.Errorf(" 查询子表失败图表,指标信息失败 Err:%s", err.Error())
+		return
+	}
+	// 获取图表详情
+	newExcelDataMap, excelAllRows, excelAllCols, err, errMsg := GetBalanceExcelData(excelInfo, lang)
+	if err != nil {
+		return
+	}
+	dataListMap = make(map[int][]*data_manage.EdbDataList)
+
+	for _, mapping := range mappingListTmp {
+		err, errMsg = GetBalanceExcelEdbData(mapping, newExcelDataMap, dataListMap, excelAllRows, excelAllCols)
+		if err != nil {
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", err.Error())
+			return
+		}
+	}
+	return
+}
+
+// TransferBalanceExcelContentToStatic 将平衡表动态表的内容转换为静态表的格式
+func TransferBalanceExcelContentToStatic(excelDetail *excelModel.ExcelInfo, lang string) (newContent string, err error) {
+	var mixedTableReq request.MixedTableReq
+	err = json.Unmarshal([]byte(excelDetail.Content), &mixedTableReq)
+	if err != nil {
+		err = errors.New("表格json转结构体失败,Err:" + err.Error())
+		return
+	}
+
+	cellRelationConf := mixedTableReq.CellRelation
+	//config := mixedTableReq.Data
+	// 单元格关系配置x信息
+	cellRelationConfMap := make(map[string]request.CellRelationConf)
+	cellRelationConfList := make([]request.CellRelationConf, 0)
+	cellRelationConfNewList := make([]request.CellRelationConf, 0)
+	if cellRelationConf != `` {
+		err = json.Unmarshal([]byte(cellRelationConf), &cellRelationConfList)
+		if err != nil {
+			return
+		}
+
+		for _, v := range cellRelationConfList {
+			if v.Type == request.EdbDT || v.Type == request.InsertDataDT || v.Type == request.PopInsertDataDT || v.Type == request.InsertEdbCalculateDataDT || v.Type == request.DateCalculateDataDT {
+			} else {
+				cellRelationConfNewList = append(cellRelationConfNewList, v)
+			}
+		}
+	}
+
+	cellRelationConfByte, err := json.Marshal(cellRelationConfNewList)
+	if err != nil {
+		err = fmt.Errorf("cellRelationConf json转结构体失败,Err:%s", err.Error())
+		return
+	}
+	cellRelationConf = string(cellRelationConfByte)
+
+	newData, tmpErr, tmpErrMsg := GetMixedTableCellData(mixedTableReq, "")
+	if tmpErr != nil {
+		err = errors.New(tmpErrMsg + "获取最新的数据失败 ,Err:" + tmpErr.Error())
+		return
+	}
+	for r, row := range newData {
+		for c, cell := range row {
+			// todo 系统日期类型,原先是不可编辑,转成静态表之后是否变成可编辑
+			cell.EdbInfoId = 0
+			if cell.DataType != request.FormulateCalculateDataDT { //除了公式计算,其他类型都转成自定义类型
+				cell.DataType = request.CustomTextDT //除了计算公式的关联关系被保留,其余绑定关系都删除
+				if _, ok := cellRelationConfMap[cell.Uid]; ok {
+					delete(cellRelationConfMap, cell.Uid)
+				}
+			}
+			if cell.DataTime != "" {
+				cell.DataTimeType = request.CustomDateT
+			}
+			cell.Value = cell.ShowValue
+			row[c] = cell
+		}
+		newData[r] = row
+	}
+	var newMixedTableReq request.MixedTableReq
+	newMixedTableReq.CellRelation = cellRelationConf
+	newMixedTableReq.Data = newData
+	newMixedTableByte, err := json.Marshal(newMixedTableReq)
+	if err != nil {
+		err = fmt.Errorf("newData json转结构体失败,Err:%s", err.Error())
+		return
+	}
+	newContent = string(newMixedTableByte)
+	return
+}

+ 80 - 22
services/data/excel/excel_info.go

@@ -51,31 +51,55 @@ func GetExcelDetailInfoByUnicode(unicode string, sysUserId int, lang string) (ex
 }
 
 func formatExcelInfo2Detail(excelInfo *excel.ExcelInfo, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) {
+	checkExcelInfo := excelInfo
+	if excelInfo.Source == utils.BALANCE_TABLE {
+		checkExcelInfoId := excelInfo.ExcelInfoId
+		if excelInfo.BalanceType == 1 {
+			checkExcelInfoId = excelInfo.RelExcelInfoId
+		} else {
+			if excelInfo.ParentId > 0 {
+				checkExcelInfoId = excelInfo.ParentId
+			}
+		}
+		if checkExcelInfoId != excelInfo.ExcelInfoId {
+			checkExcelInfo, err = excel.GetExcelInfoById(checkExcelInfoId)
+			if err != nil {
+				errMsg = "获取平衡表格信息失败"
+				err = errors.New("获取平衡表格信息失败,Err:" + err.Error())
+				return
+			}
+		}
+	}
 	// 数据权限
-	haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(excelInfo.ExcelInfoId, excelInfo.ExcelClassifyId, excelInfo.IsJoinPermission, sysUserId)
+	haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(checkExcelInfo.ExcelInfoId, checkExcelInfo.ExcelClassifyId, checkExcelInfo.IsJoinPermission, sysUserId)
 	if err != nil {
 		err = errors.New("获取表格权限信息失败,Err" + err.Error())
 		return
 	}
 
 	excelDetail = response.ExcelInfoDetail{
-		ExcelInfoId:     excelInfo.ExcelInfoId,
-		Source:          excelInfo.Source,
-		ExcelType:       excelInfo.ExcelType,
-		ExcelName:       excelInfo.ExcelName,
-		UniqueCode:      excelInfo.UniqueCode,
-		ExcelClassifyId: excelInfo.ExcelClassifyId,
-		SysUserId:       excelInfo.SysUserId,
-		SysUserRealName: excelInfo.SysUserRealName,
-		Content:         excelInfo.Content,
-		ExcelImage:      excelInfo.ExcelImage,
-		FileUrl:         excelInfo.FileUrl,
-		Sort:            excelInfo.Sort,
-		IsDelete:        excelInfo.IsDelete,
-		ModifyTime:      excelInfo.ModifyTime,
-		CreateTime:      excelInfo.CreateTime,
-		TableData:       nil,
-		HaveOperaAuth:   haveOperaAuth,
+		ExcelInfoId:        excelInfo.ExcelInfoId,
+		Source:             excelInfo.Source,
+		ExcelType:          excelInfo.ExcelType,
+		ExcelName:          excelInfo.ExcelName,
+		UniqueCode:         excelInfo.UniqueCode,
+		ExcelClassifyId:    excelInfo.ExcelClassifyId,
+		SysUserId:          excelInfo.SysUserId,
+		SysUserRealName:    excelInfo.SysUserRealName,
+		Content:            excelInfo.Content,
+		ExcelImage:         excelInfo.ExcelImage,
+		FileUrl:            excelInfo.FileUrl,
+		Sort:               excelInfo.Sort,
+		IsDelete:           excelInfo.IsDelete,
+		ModifyTime:         excelInfo.ModifyTime,
+		CreateTime:         excelInfo.CreateTime,
+		TableData:          nil,
+		HaveOperaAuth:      haveOperaAuth,
+		ParentId:           excelInfo.ParentId,
+		BalanceType:        excelInfo.BalanceType,
+		UpdateUserId:       excelInfo.UpdateUserId,
+		UpdateUserRealName: excelInfo.UpdateUserRealName,
+		RelExcelInfoId:     excelInfo.RelExcelInfoId,
 	}
 
 	// 无权限,不需要返回数据
@@ -130,7 +154,7 @@ func formatExcelInfo2Detail(excelInfo *excel.ExcelInfo, sysUserId int, lang stri
 		}
 
 		excelDetail.TableData = result
-	case utils.MIXED_TABLE: // 混合表格
+	case utils.MIXED_TABLE, utils.BALANCE_TABLE: // 混合表格 平衡表
 		var result request.MixedTableReq
 		err = json.Unmarshal([]byte(excelDetail.Content), &result)
 		if err != nil {
@@ -149,11 +173,14 @@ func formatExcelInfo2Detail(excelInfo *excel.ExcelInfo, sysUserId int, lang stri
 		result.Data = newData
 		excelDetail.TableData = result
 	}
+	if excelDetail.Source == utils.BALANCE_TABLE {
+		excelDetail.Button = GetBalanceExcelInfoOpButton(sysUserId, checkExcelInfo.SysUserId, excelDetail.HaveOperaAuth, checkExcelInfo.ExcelInfoId)
+	}
 	return
 }
 
 // GetExcelInfoOpButton 获取ETA表格的操作权限
-func GetExcelInfoOpButton(sysUser *system.Admin, belongUserId, source int, haveOperaAuth bool) (button response.ExcelInfoDetailButton) {
+func GetExcelInfoOpButton(sysUser *system.Admin, belongUserId, source int, haveOperaAuth bool) (button excel.ExcelInfoDetailButton) {
 	// 如果没有数据权限,那么直接返回
 	if !haveOperaAuth {
 		return
@@ -182,6 +209,37 @@ func GetExcelInfoOpButton(sysUser *system.Admin, belongUserId, source int, haveO
 	return
 }
 
+// GetBalanceExcelInfoOpButton 获取ETA平衡表格的操作权限
+func GetBalanceExcelInfoOpButton(sysUserId, parentSysUserId int, haveOperaAuth bool, parentExcelInfoId int) (button excel.ExcelInfoDetailButton) {
+	// 如果没有数据权限,那么直接返回
+	if !haveOperaAuth {
+		return
+	}
+	//非管理员角色查看其他用户创建的表格,可刷新、另存为、下载表格;
+	button.RefreshButton = true
+	button.CopyButton = true
+	button.DownloadButton = true
+
+	if sysUserId == parentSysUserId {
+		button.OpButton = true
+		button.RefreshEdbButton = true
+		button.OpWorkerButton = true
+	} else {
+		obj := new(excel.ExcelWorker)
+		workerList, err := obj.GetByExcelInfoId(parentExcelInfoId)
+		if err == nil {
+			for _, v := range workerList {
+				if v.SysUserId == sysUserId {
+					button.OpButton = true
+					button.RefreshEdbButton = true
+					break
+				}
+			}
+		}
+	}
+	return
+}
+
 // GetFirstEdbDataList 获取第一列的数据
 func GetFirstEdbDataList(edbInfo *data_manage.EdbInfo, num int, manualDateList []string) (resultDataList []request.ManualDataReq, err error) {
 	var dataList []*data_manage.EdbDataList
@@ -492,10 +550,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)
 }

+ 49 - 2
services/data/excel/excel_op.go

@@ -53,6 +53,53 @@ func Delete(excelInfo *excelModel.ExcelInfo, sysUser *system.Admin) (err error,
 			isSendEmail = false
 			return
 		}
+	} else if excelInfo.Source == utils.BALANCE_TABLE {
+		// 如果父级删除是否删除子表和静态表,同时删除图表和图表数据
+		excelIds := make([]int, 0)
+		//查询动态表所有的子表,并复制为静态表
+		condition := " AND source=?"
+		var pars []interface{}
+		pars = append(pars, utils.BALANCE_TABLE)
+		excelIds = append(excelIds, excelInfo.ExcelInfoId)
+		if excelInfo.ParentId == 0 {
+			if excelInfo.BalanceType == 0 {
+				condition += "  AND (parent_id = ? or rel_excel_info_id=?)"
+				pars = append(pars, excelInfo.ExcelInfoId, excelInfo.ExcelInfoId)
+			} else if excelInfo.BalanceType == 1 {
+				condition += " AND (parent_id = ?)"
+				pars = append(pars, excelInfo.ExcelInfoId)
+			}
+			excelList, e := excelModel.GetNoContentExcelInfoListByConditionNoPage(condition, pars)
+			if e != nil {
+				err = fmt.Errorf("获取子表失败 %s", err.Error())
+				errMsg = "获取子表失败"
+				return
+			}
+			for _, v := range excelList {
+				excelIds = append(excelIds, v.ExcelInfoId)
+			}
+		}
+
+		// 相关联指标
+		mappingListTmp, e := excelModel.GetExcelChartEdbMappingByExcelInfoIds(excelIds)
+		if e != nil {
+			errMsg = "获取失败"
+			err = fmt.Errorf(" 获取图表,指标信息失败 Err:%s", e.Error())
+			return
+		}
+
+		charInfoIds := make([]int, 0)
+		for _, v := range mappingListTmp {
+			charInfoIds = append(charInfoIds, v.ChartInfoId)
+		}
+		err = excelModel.DeleteExcelChartEdbAndData(excelIds, charInfoIds)
+		if err != nil {
+			errMsg = "删除表格失败"
+			err = fmt.Errorf("删除图表,指标信息失败 Err:%s", err.Error())
+			return
+		}
+
+		return
 	}
 
 	// 标记删除
@@ -172,8 +219,8 @@ func Copy(oldExcelInfoId, excelClassifyId int, excelName string, sysUser *system
 			v.ExcelInfoId = 0
 			list[k] = v
 		}
-
-		err = excelModel.AddExcelInfo(excelInfo, list)
+		var childExcel *excelModel.ExcelInfo
+		err = excelModel.AddExcelInfo(excelInfo, list, childExcel)
 		if err != nil {
 			errMsg = "保存失败"
 		}

+ 58 - 14
services/data/future_good/chart_info.go

@@ -376,13 +376,27 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 // BarChartData 获取数据
 func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMappingList []*future_good2.FutureGoodEdbInfo, edbDataListMap map[int][]*data_manage.EdbDataList, barChartInfoDateList []data_manage.BarChartInfoDateReq, regionType, latestDate string) (edbIdList []int, yDataList []data_manage.YData, err error) {
 	// 指标数据数组(10086:{"2022-12-02":100.01,"2022-12-01":102.3})
-	edbDataMap := make(map[int]map[string]float64)
+	// 现货指标数据map
+	baseEdbDataMap := make(map[string]float64)
 	for edbInfoId, edbDataList := range edbDataListMap {
+		if edbInfoId == edbInfoMapping.EdbInfoId {
+			for _, edbData := range edbDataList {
+				baseEdbDataMap[edbData.DataTime] = edbData.Value
+			}
+		}
+	}
+
+	// 期货指标数据map
+	futureGoodEdbDataMap := make(map[int]map[string]float64)
+	for edbInfoId, edbDataList := range edbDataListMap {
+		if edbInfoId == edbInfoMapping.EdbInfoId {
+			continue
+		}
 		edbDateData := make(map[string]float64)
 		for _, edbData := range edbDataList {
 			edbDateData[edbData.DataTime] = edbData.Value
 		}
-		edbDataMap[edbInfoId] = edbDateData
+		futureGoodEdbDataMap[edbInfoId] = edbDateData
 	}
 
 	// edbIdList 指标展示顺序;x轴的指标顺序
@@ -429,7 +443,7 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 		xEdbInfoIdList := make([]int, 0)    // 当前数据的指标id列表
 
 		// 现货指标
-		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[edbInfoMapping.EdbInfoId], edbDataMap[edbInfoMapping.EdbInfoId])
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, edbDataListMap[edbInfoMapping.EdbInfoId], baseEdbDataMap, futureGoodEdbDataMap)
 		if tmpErr != nil {
 			err = tmpErr
 			return
@@ -442,8 +456,13 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 			noDataIdList = append(noDataIdList, edbInfoMapping.EdbInfoId)
 			noDataIdMap[edbInfoMapping.EdbInfoId] = edbInfoMapping.EdbInfoId
 		}
-		currMonth := findDateTime.Month() // 当前月份
-		currYear := findDateTime.Year()   // 当前年份
+		//currMonth := findDateTime.Month() // 当前月份
+		//currYear := findDateTime.Year()   // 当前年份
+
+		// 用实际日期的月份作为基准,往前推12个月(2024-5-13 16:26:43修改)
+		currMonth := realDateTime.Month() // 当前月份
+		currYear := realDateTime.Year()   // 当前年份
+
 		xEdbInfoIdList = append(xEdbInfoIdList, edbInfoMapping.EdbInfoId)
 		mList := make([]int, 0) // 间隔月份
 		indexList := make([]int, 0)
@@ -482,7 +501,7 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 			//}
 			//tmpRealDateTime := findDateTime	// 按照配置找到的日期
 			tmpRealDateTime := realDateTime // 实际现货的日期
-			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
+			tmpFindDataValue, tmpIsFind := futureGoodEdbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
 			yDataMap[futureGoodMapping.FutureGoodEdbInfoId] = tmpFindDataValue
 
 			findDataList = append(findDataList, tmpFindDataValue)
@@ -860,7 +879,7 @@ func getFutureGoodEdbInfoList(latestDateTime time.Time, tmpFutureGoodEdbInfoList
 }
 
 // GetNeedDateData 获取合约内需要的日期数据
-func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList, edbDataMap map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
+func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList, edbDataMap map[string]float64, allEdbDataMap map[int]map[string]float64) (findDateTime time.Time, findDataValue float64, isFind bool, err error) {
 	//dataList := edbDataListMap[edbInfoId] //指标的所有数据值
 	if len(dataList) <= 0 {
 		// 没有数据的指标id
@@ -873,18 +892,43 @@ func GetNeedDateData(needDateTime time.Time, dataList []*data_manage.EdbDataList
 		return
 	}
 
+	// 该日期存在数据的期货指标的最小数量,目前是现货和期货各1个,总共2个
+	maxCount := 1
+
 	for tmpDateTime := needDateTime; tmpDateTime.After(minDateTime) || tmpDateTime.Equal(minDateTime); tmpDateTime = tmpDateTime.AddDate(0, 0, -1) {
 		tmpDate := tmpDateTime.Format(utils.FormatDate)
-		if tmpValue, ok := edbDataMap[tmpDate]; ok { //如果能找到数据,那么就返回
-			// 数据为0,也直接返回,做无值处理
-			if tmpValue == 0 {
-				return
+		tmpValue, ok := edbDataMap[tmpDate]
+		if !ok {
+			continue
+		}
+
+		// 该日期存在数据的指标数量
+		count := 0
+
+		for _, currEdbDataMap := range allEdbDataMap {
+			_, tmpIsFind := currEdbDataMap[tmpDate]
+			if tmpIsFind {
+				count++
+				if count >= maxCount {
+					continue
+				}
 			}
-			findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
-			findDataValue = tmpValue
-			isFind = true
+		}
+
+		// 该日期存在数据的期货指标数量小于2个,那么要继续往前找
+		if count < maxCount {
+			continue
+		}
+
+		//如果能找到数据,那么就返回
+		// 数据为0,也直接返回,做无值处理
+		if tmpValue == 0 {
 			return
 		}
+		findDateTime, _ = time.ParseInLocation(utils.FormatDate, tmpDate, time.Local)
+		findDataValue = tmpValue
+		isFind = true
+		return
 	}
 
 	return

+ 4 - 2
services/data/future_good/profit_chart_info.go

@@ -248,7 +248,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 		xEdbInfoIdList := make([]int, 0)   // 当前数据的指标id列表
 
 		// 现货指标
-		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataList, baseEdbDateData)
+		realDateTime, findDataValue, isFind, tmpErr := GetNeedDateData(findDateTime, baseDataList, baseEdbDateData, edbDataMap)
 		if tmpErr != nil {
 			err = tmpErr
 			return
@@ -274,7 +274,9 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 			//findDateTime
 
 			// 获取当前日期相对开始日期的期数
-			tmpN := (currDate.Year()-findDateTime.Year())*12 + int(currDate.Month()-findDateTime.Month())
+			//tmpN := (currDate.Year()-findDateTime.Year())*12 + int(currDate.Month()-findDateTime.Month())
+			// 用实际日期的月份作为基准,往前推12个月(2024-5-13 16:26:43修改)
+			tmpN := (currDate.Year()-realDateTime.Year())*12 + int(currDate.Month()-realDateTime.Month())
 			if tmpN <= 0 {
 				continue
 			}

+ 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

+ 182 - 48
services/elastic/elastic.go

@@ -266,6 +266,35 @@ func SearchEdbInfoData(indexName, keywordStr string, from, size, filterSource, s
 	//})
 
 	//关键字匹配
+	//shouldMap := map[string]interface{}{
+	//	"should": []interface{}{
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbCode": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbName": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbNameEn": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//	},
+	//}
+
+	// 默认使用中文名字字段去匹配
+	keywordNameKey := `EdbName`
+	// 如果没有中文,则使用英文名称字段去匹配
+	if !utils.ContainsChinese(keywordStr) {
+		keywordNameKey = `EdbNameEn`
+	}
 	shouldMap := map[string]interface{}{
 		"should": []interface{}{
 			map[string]interface{}{
@@ -276,21 +305,16 @@ func SearchEdbInfoData(indexName, keywordStr string, from, size, filterSource, s
 			},
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"EdbName": keywordStr,
-					//"Frequency.keyword": "月度",
-				},
-			},
-			map[string]interface{}{
-				"match": map[string]interface{}{
-					"EdbNameEn": keywordStr,
+					keywordNameKey: keywordStr,
 					//"Frequency.keyword": "月度",
 				},
 			},
 		},
 	}
-	mustMap = append(mustMap, map[string]interface{}{
-		"bool": shouldMap,
-	})
+
+	//mustMap = append(mustMap, map[string]interface{}{
+	//	"bool": shouldMap,
+	//})
 
 	return searchEdbInfoData(indexName, mustMap, mustNotMap, shouldMap, from, size)
 }
@@ -638,6 +662,35 @@ func SearchAddPredictEdbInfoData(indexName, keywordStr string, noPermissionEdbIn
 	})
 
 	//关键字匹配
+	//shouldMap := map[string]interface{}{
+	//	"should": []interface{}{
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbCode": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbName": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbNameEn": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//	},
+	//}
+
+	// 默认使用中文名字字段去匹配
+	keywordNameKey := `EdbName`
+	// 如果没有中文,则使用英文名称字段去匹配
+	if !utils.ContainsChinese(keywordStr) {
+		keywordNameKey = `EdbNameEn`
+	}
 	shouldMap := map[string]interface{}{
 		"should": []interface{}{
 			map[string]interface{}{
@@ -648,7 +701,7 @@ func SearchAddPredictEdbInfoData(indexName, keywordStr string, noPermissionEdbIn
 			},
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"EdbName": keywordStr,
+					keywordNameKey: keywordStr,
 					//"Frequency.keyword": "月度",
 				},
 			},
@@ -999,34 +1052,61 @@ func SearchChartInfoData(indexName, keywordStr string, showSysId int, sourceList
 	})
 
 	//关键字匹配
+	//shouldMap := map[string]interface{}{
+	//	"should": []interface{}{
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartName": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartName": map[string]interface{}{
+	//					"query":    keywordStr,
+	//					"operator": "and",
+	//				},
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartNameEn": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartNameEn": map[string]interface{}{
+	//					"query":    keywordStr,
+	//					"operator": "and",
+	//				},
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//	},
+	//}
+
+	// 默认使用中文名字字段去匹配
+	keywordNameKey := `ChartName`
+	// 如果没有中文,则使用英文名称字段去匹配
+	if !utils.ContainsChinese(keywordStr) {
+		keywordNameKey = `ChartNameEn`
+	}
 	shouldMap := map[string]interface{}{
 		"should": []interface{}{
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"ChartName": keywordStr,
-					//"Frequency.keyword": "月度",
-				},
-			},
-			// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
-			map[string]interface{}{
-				"match": map[string]interface{}{
-					"ChartName": map[string]interface{}{
-						"query":    keywordStr,
-						"operator": "and",
-					},
-					//"Frequency.keyword": "月度",
-				},
-			},
-			map[string]interface{}{
-				"match": map[string]interface{}{
-					"ChartNameEn": keywordStr,
+					keywordNameKey: keywordStr,
 					//"Frequency.keyword": "月度",
 				},
 			},
 			// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"ChartNameEn": map[string]interface{}{
+					keywordNameKey: map[string]interface{}{
 						"query":    keywordStr,
 						"operator": "and",
 					},
@@ -1035,6 +1115,7 @@ func SearchChartInfoData(indexName, keywordStr string, showSysId int, sourceList
 			},
 		},
 	}
+
 	mustMap = append(mustMap, map[string]interface{}{
 		"bool": shouldMap,
 	})
@@ -1182,34 +1263,62 @@ func SearchMyChartInfoData(indexName, keywordStr string, adminId int, noPermissi
 	}
 
 	//关键字匹配
+
+	//shouldMap := map[string]interface{}{
+	//	"should": []interface{}{
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartName": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartName": map[string]interface{}{
+	//					"query":    keywordStr,
+	//					"operator": "and",
+	//				},
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartNameEn": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"ChartNameEn": map[string]interface{}{
+	//					"query":    keywordStr,
+	//					"operator": "and",
+	//				},
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//	},
+	//}
+
+	// 默认使用中文名字字段去匹配
+	keywordNameKey := `ChartName`
+	// 如果没有中文,则使用英文名称字段去匹配
+	if !utils.ContainsChinese(keywordStr) {
+		keywordNameKey = `ChartNameEn`
+	}
 	shouldMap := map[string]interface{}{
 		"should": []interface{}{
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"ChartName": keywordStr,
+					keywordNameKey: keywordStr,
 					//"Frequency.keyword": "月度",
 				},
 			},
 			// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"ChartName": map[string]interface{}{
-						"query":    keywordStr,
-						"operator": "and",
-					},
-					//"Frequency.keyword": "月度",
-				},
-			},
-			map[string]interface{}{
-				"match": map[string]interface{}{
-					"ChartNameEn": keywordStr,
-					//"Frequency.keyword": "月度",
-				},
-			},
-			// 因为关键词被分了,所以需要用下面的语句来让他 整个词 查询,从而加重整词的权重
-			map[string]interface{}{
-				"match": map[string]interface{}{
-					"ChartNameEn": map[string]interface{}{
+					keywordNameKey: map[string]interface{}{
 						"query":    keywordStr,
 						"operator": "and",
 					},
@@ -1218,6 +1327,7 @@ func SearchMyChartInfoData(indexName, keywordStr string, adminId int, noPermissi
 			},
 		},
 	}
+
 	mustMap = append(mustMap, map[string]interface{}{
 		"bool": shouldMap,
 	})
@@ -1473,6 +1583,29 @@ func SearchEdbInfoDataByAdminId(indexName, keywordStr string, from, size, filter
 	//})
 
 	//关键字匹配
+	//shouldMap := map[string]interface{}{
+	//	"should": []interface{}{
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbCode": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//		map[string]interface{}{
+	//			"match": map[string]interface{}{
+	//				"EdbName": keywordStr,
+	//				//"Frequency.keyword": "月度",
+	//			},
+	//		},
+	//	},
+	//}
+
+	// 默认使用中文名字字段去匹配
+	keywordNameKey := `EdbName`
+	// 如果没有中文,则使用英文名称字段去匹配
+	if !utils.ContainsChinese(keywordStr) {
+		keywordNameKey = `EdbNameEn`
+	}
 	shouldMap := map[string]interface{}{
 		"should": []interface{}{
 			map[string]interface{}{
@@ -1483,12 +1616,13 @@ func SearchEdbInfoDataByAdminId(indexName, keywordStr string, from, size, filter
 			},
 			map[string]interface{}{
 				"match": map[string]interface{}{
-					"EdbName": keywordStr,
+					keywordNameKey: keywordStr,
 					//"Frequency.keyword": "月度",
 				},
 			},
 		},
 	}
+
 	mustMap = append(mustMap, map[string]interface{}{
 		"bool": shouldMap,
 	})

+ 23 - 0
services/eta_forum/eta_forum_hub.go

@@ -504,3 +504,26 @@ func ChartThemeSave(theme *chart_theme.ChartTheme) (err error) {
 	}
 	return
 }
+
+// ChartThemeTypeSave  上传主题类型信息
+func ChartThemeTypeSave(theme *chart_theme.ChartThemeType) (err error) {
+	if utils.BusinessCode == "" || (utils.BusinessCode != utils.BusinessCodeRelease && utils.BusinessCode != utils.BusinessCodeDebug && utils.BusinessCode != utils.BusinessCodeSandbox) {
+		return
+	}
+	//req.BusinessCode = utils.BusinessCode
+	reqJson, err := json.Marshal(theme)
+	if err != nil {
+		err = fmt.Errorf("参数解析异常,Err:" + err.Error())
+		return
+	}
+	respItem, err := ChartThemeTypeSaveLib(string(reqJson))
+	if err != nil {
+		err = fmt.Errorf("上传图表主题信息失败,Err:" + err.Error())
+		return
+	}
+	if respItem.Ret != 200 {
+		err = fmt.Errorf("上传图表主题信息失败,Err:%v,errMsg:%v", respItem.Msg, respItem.ErrMsg)
+		return
+	}
+	return
+}

+ 10 - 0
services/eta_forum/eta_forum_hub_lib.go

@@ -70,6 +70,16 @@ func ChartThemeSaveLib(req string) (resp *models.BaseResponse, err error) {
 	return
 }
 
+// ChartThemeTypeSaveLib 上传图表主题类型信息
+func ChartThemeTypeSaveLib(req string) (resp *models.BaseResponse, err error) {
+	_, resultByte, err := post(req, "/v1/chart/theme/type/save")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
 // post
 func post(paramStr string, urlStr string) (resp *models.BaseResponse, result []byte, err error) {
 	if utils.ETA_FORUM_HUB_URL == "" {

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

+ 49 - 1
services/ppt/ppt_english_group.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"eta/eta_api/models/ppt_english"
 	"eta/eta_api/models/system"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
@@ -371,7 +372,7 @@ func GetGroupPptEnglishList(groupId int64, adminId int) (ret ppt_english.RespGro
 			return
 		}
 		groups = append(groups, groupInfo)
-		groupPptList, tErr = ppt_english.GetPptMappingListByGroupId(groupId)
+		groupPptList, tErr = ppt_english.GetPptMappingListByGroupIdDesc(groupId)
 		if tErr != nil {
 			err = errors.New("目录里的ppt查询出错:" + tErr.Error())
 			return
@@ -403,6 +404,16 @@ func GetGroupPptEnglishList(groupId int64, adminId int) (ret ppt_english.RespGro
 	}
 
 	for _, v := range pptList {
+		// 解决部分历史ppt数据不存在TotalPages的情况
+		if v.PptPage == 0 {
+			var pptContent []services.PPTContent
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				err = errors.New("解析ppt内容出错" + err.Error())
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		pptMap[v.PptId] = v
 	}
 
@@ -430,6 +441,7 @@ func GetGroupPptEnglishList(groupId int64, adminId int) (ret ppt_english.RespGro
 							ReportId:      pptInfo.ReportId,
 							ReportCode:    pptInfo.ReportCode,
 							PublishTime:   utils.DealDateTimeZero(pptInfo.PublishTime, utils.FormatDateTime),
+							PptPage:       pptInfo.PptPage,
 						}
 						if pptV.ChildGroupPptId > 0 {
 							tmp.IsSingleShare = 1
@@ -1213,7 +1225,15 @@ func GetMyPptEnglishList(adminId int, keyword string) (ret ppt_english.RespGroup
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &ppt_english.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1229,6 +1249,7 @@ func GetMyPptEnglishList(adminId int, keyword string) (ret ppt_english.RespGroup
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1270,7 +1291,15 @@ func GetSharePptEnglishList(adminId int, keyword string, isPrivate bool) (ret pp
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &ppt_english.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1286,6 +1315,7 @@ func GetSharePptEnglishList(adminId int, keyword string, isPrivate bool) (ret pp
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1330,7 +1360,15 @@ func GetGrantPptEnglishList(adminId int, keyword, sourceType string) (ret ppt_en
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &ppt_english.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1347,6 +1385,7 @@ func GetGrantPptEnglishList(adminId int, keyword, sourceType string) (ret ppt_en
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1405,7 +1444,15 @@ func SearchEnglishPptList(adminId int, keyword string) (ret ppt_english.RespGrou
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &ppt_english.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1419,6 +1466,7 @@ func SearchEnglishPptList(adminId int, keyword string) (ret ppt_english.RespGrou
 			PptxUrl:       v.PptxUrl,
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}

+ 47 - 0
services/ppt/ppt_group.go

@@ -5,6 +5,7 @@ import (
 	"errors"
 	"eta/eta_api/models"
 	"eta/eta_api/models/system"
+	"eta/eta_api/services"
 	"eta/eta_api/utils"
 	"fmt"
 	"sort"
@@ -591,6 +592,15 @@ func GetGroupPptList(groupId int64, adminId int) (ret models.RespGroupPptList, e
 	}
 
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			var pptContent []services.PPTContent
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				err = errors.New("解析ppt内容出错" + err.Error())
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		pptMap[v.PptId] = v
 	}
 
@@ -619,6 +629,7 @@ func GetGroupPptList(groupId int64, adminId int) (ret models.RespGroupPptList, e
 							ReportId:      pptInfo.ReportId,
 							ReportCode:    pptInfo.ReportCode,
 							PublishTime:   utils.DealDateTimeZero(pptInfo.PublishTime, utils.FormatDateTime),
+							PptPage:       pptInfo.PptPage,
 						}
 						if pptV.ChildGroupPptId > 0 {
 							tmp.IsSingleShare = 1
@@ -1575,7 +1586,15 @@ func GetMyPptList(adminId int, keyword string) (ret models.RespGroupPptList, err
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &models.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1592,6 +1611,7 @@ func GetMyPptList(adminId int, keyword string) (ret models.RespGroupPptList, err
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1633,7 +1653,15 @@ func GetSharePptList(adminId int, keyword string, isPrivate bool) (ret models.Re
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &models.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1650,6 +1678,7 @@ func GetSharePptList(adminId int, keyword string, isPrivate bool) (ret models.Re
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1694,7 +1723,15 @@ func GetGrantPptList(adminId int, keyword, sourceType string) (ret models.RespGr
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &models.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1711,6 +1748,7 @@ func GetGrantPptList(adminId int, keyword, sourceType string) (ret models.RespGr
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
 			PublishTime:   utils.DealDateTimeZero(v.PublishTime, utils.FormatDateTime),
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}
@@ -1743,7 +1781,15 @@ func SearchPptList(adminId int, keyword string) (ret models.RespGroupPptList, er
 		return
 	}
 
+	var pptContent []services.PPTContent
 	for _, v := range pptList {
+		if v.PptPage == 0 {
+			err = json.Unmarshal([]byte(v.Content), &pptContent)
+			if err != nil {
+				return
+			}
+			v.PptPage = len(pptContent)
+		}
 		tmpV := &models.RespGroupPptListItem{
 			GroupPptId:    int64(v.PptId),
 			PptId:         int64(v.PptId),
@@ -1758,6 +1804,7 @@ func SearchPptList(adminId int, keyword string) (ret models.RespGroupPptList, er
 			PptxUrl:       v.PptxUrl,
 			ReportId:      v.ReportId,
 			ReportCode:    v.ReportCode,
+			PptPage:       v.PptPage,
 		}
 		list = append(list, tmpV)
 	}

+ 15 - 0
services/report.go

@@ -353,6 +353,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 {

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

+ 2 - 2
services/task.go

@@ -40,8 +40,8 @@ func Task() {
 
 	go AutoInsertAdminOperateRecordToDB()
 
-	// 测试用-生成bloomberg数据
-	//go InsertBloombergIndex()
+	// 指标刷新
+	go data.HandleEdbRefreshQueue()
 
 	// 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)
 		}
 	}
 

+ 44 - 44
utils/common.go

@@ -2305,6 +2305,50 @@ func GetColorMap() map[int]string {
 	return colorMap
 }
 
+// SecondsToHHMMSS 秒转HH:MM:SS
+func SecondsToHHMMSS(seconds int) string {
+	duration := time.Duration(seconds) * time.Second
+	hours := int(duration.Hours())
+	minutes := int(duration.Minutes()) % 60
+	seconds = int(duration.Seconds()) % 60
+
+	if hours > 0 {
+		return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
+	} else {
+		return fmt.Sprintf("%02d:%02d", minutes, seconds)
+	}
+}
+
+// MillisecondsToHHMMSS 毫秒转HH:MM:SS
+func MillisecondsToHHMMSS(ms int) string {
+	duration := time.Duration(ms) * time.Millisecond
+	hours := int(duration / (time.Hour))
+	minutes := int((duration % (time.Hour)) / time.Minute)
+	seconds := int((duration % time.Hour % time.Minute) / time.Second)
+
+	// 将整数小时、分钟和秒数转换为字符串,并添加冒号分隔符
+	hourStr := strconv.Itoa(hours)
+	minuteStr := strconv.Itoa(minutes)
+	secondStr := strconv.Itoa(seconds)
+
+	// 根据不足两位数的情况补零
+	if len(hourStr) == 1 {
+		hourStr = "0" + hourStr
+	}
+	if len(minuteStr) == 1 {
+		minuteStr = "0" + minuteStr
+	}
+	if len(secondStr) == 1 {
+		secondStr = "0" + secondStr
+	}
+
+	return hourStr + ":" + minuteStr + ":" + secondStr
+}
+
+func ByteToMB(byteCount int) float64 {
+	return float64(byteCount) / (1024 * 1024)
+}
+
 // 检查src属性是否以http或data:image开头
 func isValidSrc(src string) bool {
 	// 使用Parse函数解析URL
@@ -2402,47 +2446,3 @@ func customXssPolicy() (p *bluemonday.Policy) {
 	p.AllowAttrs("allowfullscreen").OnElements("iframe")
 	return
 }
-
-// SecondsToHHMMSS 秒转HH:MM:SS
-func SecondsToHHMMSS(seconds int) string {
-	duration := time.Duration(seconds) * time.Second
-	hours := int(duration.Hours())
-	minutes := int(duration.Minutes()) % 60
-	seconds = int(duration.Seconds()) % 60
-
-	if hours > 0 {
-		return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
-	} else {
-		return fmt.Sprintf("%02d:%02d", minutes, seconds)
-	}
-}
-
-// MillisecondsToHHMMSS 毫秒转HH:MM:SS
-func MillisecondsToHHMMSS(ms int) string {
-	duration := time.Duration(ms) * time.Millisecond
-	hours := int(duration / (time.Hour))
-	minutes := int((duration % (time.Hour)) / time.Minute)
-	seconds := int((duration % time.Hour % time.Minute) / time.Second)
-
-	// 将整数小时、分钟和秒数转换为字符串,并添加冒号分隔符
-	hourStr := strconv.Itoa(hours)
-	minuteStr := strconv.Itoa(minutes)
-	secondStr := strconv.Itoa(seconds)
-
-	// 根据不足两位数的情况补零
-	if len(hourStr) == 1 {
-		hourStr = "0" + hourStr
-	}
-	if len(minuteStr) == 1 {
-		minuteStr = "0" + minuteStr
-	}
-	if len(secondStr) == 1 {
-		secondStr = "0" + secondStr
-	}
-
-	return hourStr + ":" + minuteStr + ":" + secondStr
-}
-
-func ByteToMB(byteCount int) float64 {
-	return float64(byteCount) / (1024 * 1024)
-}

+ 13 - 13
utils/config.go

@@ -193,19 +193,6 @@ var (
 // BusinessCode 商家编码
 var BusinessCode string
 
-// 日志配置
-var (
-	LogPath     string //调用过程中的日志存放地址
-	LogFile     string
-	LogDataPath string //调用过程中图表相关的日志存放地址
-	LogDataFile string
-	BinLogPath  string //数据库相关的日志存放地址
-	BinLogFile  string
-	ApiLogPath  string //接口请求地址和接口返回值日志存放地址
-	ApiLogFile  string
-	LogMaxDays  int //日志最大保留天数
-)
-
 // MinIo配置
 var (
 	MinIoBucketname       string
@@ -221,6 +208,19 @@ var (
 	MinIoRegion           string
 )
 
+// 日志配置
+var (
+	LogPath     string //调用过程中的日志存放地址
+	LogFile     string
+	LogDataPath string //调用过程中图表相关的日志存放地址
+	LogDataFile string
+	BinLogPath  string //数据库相关的日志存放地址
+	BinLogFile  string
+	ApiLogPath  string //接口请求地址和接口返回值日志存放地址
+	ApiLogFile  string
+	LogMaxDays  int //日志最大保留天数
+)
+
 // PythonUrlReport2Img 生成长图服务地址
 var PythonUrlReport2Img string
 

+ 2 - 0
utils/constants.go

@@ -277,6 +277,7 @@ const (
 	CHART_SOURCE_LINE_FEATURE_PERCENTILE         = 8  // 统计特征-百分位图表
 	CHART_SOURCE_LINE_FEATURE_FREQUENCY          = 9  // 统计特征-频率分布图表
 	CHART_SOURCE_CROSS_HEDGING                   = 10 // 跨品种分析图表
+	CHART_SOURCE_BALANCE_EXCEL                   = 11 // 平衡表图表
 )
 
 // 批量配置图表的位置来源
@@ -299,6 +300,7 @@ const (
 	TIME_TABLE            = 2 // 时间序列表格
 	MIXED_TABLE           = 3 // 混合表格
 	CUSTOM_ANALYSIS_TABLE = 4 // 自定义分析表格
+	BALANCE_TABLE         = 5 // 平衡表
 )
 
 // 图表样式类型

+ 1 - 1
utils/logs.go

@@ -43,7 +43,7 @@ func init() {
 	b, _ := json.Marshal(logConf)
 	FileLog.SetLogger(logs.AdapterFile, string(b))
 	FileLog.EnableFuncCallDepth(true)
-
+	
 	initBinlog()
 	initApiLog()
 	initFileLogData()