Browse Source

Merge branch 'eta/1.7.3' into ETA_1.8.0

zwxi 11 months ago
parent
commit
8024360863

+ 7 - 3
controllers/ai/ai.go

@@ -102,7 +102,7 @@ func (this *AiController) List() {
 			historyChatList = append(historyChatList, *historyChat)
 			historyChatList = append(historyChatList, *historyChat)
 		}
 		}
 
 
-		answer, err = aiser.ChatAutoMsg(req.Ask, historyChatList)
+		answer, err = aiser.ChatAutoMsg(req.Ask, historyChatList, req.Model)
 		if err != nil {
 		if err != nil {
 			br.Msg = "获取数据失败!"
 			br.Msg = "获取数据失败!"
 			br.ErrMsg = "获取数据失败,ChatAutoMsg,Err:" + err.Error()
 			br.ErrMsg = "获取数据失败,ChatAutoMsg,Err:" + err.Error()
@@ -111,6 +111,7 @@ func (this *AiController) List() {
 	}
 	}
 	resp.Ask = req.Ask
 	resp.Ask = req.Ask
 	resp.Answer = answer
 	resp.Answer = answer
+	resp.Model = req.Model
 
 
 	if req.AiChatTopicId <= 0 { //新增
 	if req.AiChatTopicId <= 0 { //新增
 		topic := new(aimod.AiChatTopic)
 		topic := new(aimod.AiChatTopic)
@@ -131,7 +132,7 @@ func (this *AiController) List() {
 		chatItem.Ask = req.Ask
 		chatItem.Ask = req.Ask
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.Answer = answer
 		chatItem.Answer = answer
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[req.Model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.CreateTime = time.Now()
 		chatItem.CreateTime = time.Now()
@@ -149,7 +150,7 @@ func (this *AiController) List() {
 		chatItem.Ask = req.Ask
 		chatItem.Ask = req.Ask
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.Answer = answer
 		chatItem.Answer = answer
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[req.Model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.CreateTime = time.Now()
 		chatItem.CreateTime = time.Now()
@@ -226,6 +227,9 @@ func (this *AiController) TopicDetail() {
 		br.ErrMsg = "获取主题记录信息失败,Err:" + err.Error()
 		br.ErrMsg = "获取主题记录信息失败,Err:" + err.Error()
 		return
 		return
 	}
 	}
+	for index := range list {
+		list[index].Model = aimod.ModelViewMap[list[index].Model]
+	}
 	resp := new(aimod.AiChatDetailResp)
 	resp := new(aimod.AiChatDetailResp)
 	resp.List = list
 	resp.List = list
 	br.Ret = 200
 	br.Ret = 200

+ 13 - 7
controllers/ai/ai_file.go

@@ -39,6 +39,7 @@ func (this *AiFileController) FileUpload() {
 		br.ErrMsg = "获取资源信息失败,Err:" + err.Error()
 		br.ErrMsg = "获取资源信息失败,Err:" + err.Error()
 		return
 		return
 	}
 	}
+	model := this.GetString("Model")
 
 
 	aiChatTopicId, _ := this.GetInt("AiChatTopicId")
 	aiChatTopicId, _ := this.GetInt("AiChatTopicId")
 
 
@@ -96,7 +97,7 @@ func (this *AiFileController) FileUpload() {
 		ResourceUrl:  resourceUrl,
 		ResourceUrl:  resourceUrl,
 		ResourceName: uploadFileName,
 		ResourceName: uploadFileName,
 	}
 	}
-	uploadResult, err := aiser.OpenAiFileUpload(resourceUrl, uploadFileName)
+	uploadResult, err := aiser.OpenAiFileUpload(resourceUrl, uploadFileName, model)
 	if err != nil {
 	if err != nil {
 		br.Msg = "文件上传失败"
 		br.Msg = "文件上传失败"
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
@@ -148,7 +149,7 @@ func (this *AiFileController) FileUpload() {
 		chatItem.AiChatTopicId = aiChatTopicId
 		chatItem.AiChatTopicId = aiChatTopicId
 		chatItem.Ask = uploadFileName
 		chatItem.Ask = uploadFileName
 		chatItem.AskUuid = utils.MD5(uploadFileName)
 		chatItem.AskUuid = utils.MD5(uploadFileName)
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		if uploadResult != nil && uploadResult.Data != nil {
 		if uploadResult != nil && uploadResult.Data != nil {
@@ -169,7 +170,7 @@ func (this *AiFileController) FileUpload() {
 		chatItem.AiChatTopicId = aiChatTopicId
 		chatItem.AiChatTopicId = aiChatTopicId
 		chatItem.Ask = uploadFileName
 		chatItem.Ask = uploadFileName
 		chatItem.AskUuid = utils.MD5(fileName)
 		chatItem.AskUuid = utils.MD5(fileName)
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		if uploadResult != nil && uploadResult.Data != nil {
 		if uploadResult != nil && uploadResult.Data != nil {
@@ -331,7 +332,7 @@ func (this *AiFileController) FileRetrieve() {
 		frList = append(frList, *frItem)
 		frList = append(frList, *frItem)
 	}
 	}
 
 
-	fileRetrieveResp, err := aiser.FileRetrieve(assistantId, threadId, frList, req.OpenaiFileId)
+	fileRetrieveResp, err := aiser.FileRetrieve(assistantId, threadId, req.Model, frList, req.OpenaiFileId)
 	if err != nil {
 	if err != nil {
 		br.Msg = "获取数据失败!"
 		br.Msg = "获取数据失败!"
 		br.ErrMsg = "获取数据失败,FileRetrieve,Err:" + err.Error()
 		br.ErrMsg = "获取数据失败,FileRetrieve,Err:" + err.Error()
@@ -370,7 +371,7 @@ func (this *AiFileController) FileRetrieve() {
 		chatItem.Ask = req.Ask
 		chatItem.Ask = req.Ask
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.AskUuid = utils.MD5(req.Ask)
 		chatItem.Answer = answer
 		chatItem.Answer = answer
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[req.Model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.CreateTime = time.Now()
 		chatItem.CreateTime = time.Now()
@@ -388,7 +389,7 @@ func (this *AiFileController) FileRetrieve() {
 		chatItem.Ask = req.Ask
 		chatItem.Ask = req.Ask
 		chatItem.AskUuid = askUuid
 		chatItem.AskUuid = askUuid
 		chatItem.Answer = answer
 		chatItem.Answer = answer
-		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.Model = EnabledModelsForMap[req.Model]
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserId = this.SysUser.AdminId
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.SysUserRealName = this.SysUser.RealName
 		chatItem.CreateTime = time.Now()
 		chatItem.CreateTime = time.Now()
@@ -417,7 +418,7 @@ func (this *AiFileController) FileRetrieve() {
 			return
 			return
 		}
 		}
 	}
 	}
-
+	resp.Model = aimod.ModelViewMap[req.Model]
 	resp.AiChatTopicId = req.AiChatTopicId
 	resp.AiChatTopicId = req.AiChatTopicId
 	resp.Ask = req.Ask
 	resp.Ask = req.Ask
 	resp.Answer = answer
 	resp.Answer = answer
@@ -427,3 +428,8 @@ func (this *AiFileController) FileRetrieve() {
 	br.Data = resp
 	br.Data = resp
 	return
 	return
 }
 }
+
+var EnabledModelsForMap = map[string]string{
+	"Kimi":        "moonshot-v1-32k",
+	"GPT-4 Turbo": "gpt-4-1106-preview",
+}

+ 523 - 0
controllers/data_manage/bloomberg_data.go

@@ -0,0 +1,523 @@
+package data_manage
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/models/system"
+	"eta/eta_api/services/data"
+	etaTrialService "eta/eta_api/services/eta_trial"
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// BloombergDataController 彭博数据源
+type BloombergDataController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 指标列表
+// @Description 指标列表
+// @Param   PageSize  query  int  false  "每页数据量"
+// @Param   CurrentIndex  query  int  false  "页码"
+// @Param   Frequency  query  string  false  "频度"
+// @Param   Keywords  query  string  false  "指标ID/指标名称"
+// @Param   ListAll  query  bool  false  "列表全选"
+// @Param   SortField  query  int  false  "排序字段: 0-默认; 1-开始时间; 2-最新时间; 3-更新时间"
+// @Param   SortRule  query  int  false  "排序方式: 0-默认; 1-正序; 2-倒序"
+// @Success 200 {object} data_manage.BloombergSourceListResp
+// @router /bloomberg_source/list [get]
+func (this *BloombergDataController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	params := new(data_manage.BloombergSourceListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+
+	cond := ``
+	pars := make([]interface{}, 0)
+	// 筛选项
+	{
+		params.Keywords = strings.TrimSpace(params.Keywords)
+		if params.Keywords != "" {
+			cond += fmt.Sprintf(` AND (%s LIKE ? OR %s LIKE ?)`, data_manage.BaseFromBloombergIndexCols.IndexCode, data_manage.BaseFromBloombergIndexCols.IndexName)
+			kw := fmt.Sprint("%", params.Keywords, "%")
+			pars = append(pars, kw, kw)
+		}
+		if params.Frequency != "" {
+			cond += fmt.Sprintf(` AND %s = ?`, data_manage.BaseFromBloombergIndexCols.Frequency)
+			pars = append(pars, params.Frequency)
+		}
+	}
+
+	// 分页列表
+	bloombergOb := new(data_manage.BaseFromBloombergIndex)
+	total, e := bloombergOb.GetCountByCondition(cond, pars)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取Bloomberg原始指标列表总数失败, Err: " + e.Error()
+		return
+	}
+	var startSize int
+	if params.PageSize <= 0 {
+		params.PageSize = utils.PageSize20
+	}
+	if params.CurrentIndex <= 0 {
+		params.CurrentIndex = 1
+	}
+	startSize = utils.StartIndex(params.CurrentIndex, params.PageSize)
+
+	// 排序, 默认创建时间倒序
+	orderFields := map[int]string{
+		0: data_manage.BaseFromBloombergIndexCols.CreateTime, 1: data_manage.BaseFromBloombergIndexCols.StartDate,
+		2: data_manage.BaseFromBloombergIndexCols.EndDate, 3: data_manage.BaseFromBloombergIndexCols.ModifyTime,
+	}
+	orderType := map[int]string{0: "DESC", 1: "ASC", 2: "DESC"}
+	orderRule := fmt.Sprintf("%s %s", orderFields[params.SortField], orderType[params.SortRule])
+
+	// 列表
+	edbList := make([]*data_manage.BaseFromBloombergIndex, 0)
+	if params.ListAll {
+		list, e := bloombergOb.GetItemsByCondition(cond, pars, []string{}, orderRule, 0)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取Bloomberg原始指标列表失败, Err: " + e.Error()
+			return
+		}
+		edbList = list
+	} else {
+		list, e := bloombergOb.GetPageItemsByCondition(cond, pars, []string{}, orderRule, startSize, params.PageSize)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取Bloomberg原始指标分页列表失败, Err: " + e.Error()
+			return
+		}
+		edbList = list
+	}
+
+	// 获取指标库已有指标
+	existsEdb, e := data_manage.GetEdbCodesBySource(utils.DATA_SOURCE_BLOOMBERG)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取Bloomberg已添加的指标失败, Err: " + e.Error()
+		return
+	}
+	existMap := make(map[string]*data_manage.EdbInfo)
+	for _, v := range existsEdb {
+		existMap[v.EdbCode] = v
+	}
+
+	respList := make([]*data_manage.BaseFromBloombergIndexItem, 0)
+	for _, v := range edbList {
+		t := data_manage.FormatBaseFromBloombergIndex2Item(v)
+		ed := existMap[v.IndexCode]
+		if ed != nil {
+			t.EdbExist = 1
+			t.EdbInfoId = ed.EdbInfoId
+			t.EdbUniqueCode = ed.UniqueCode
+			t.EdbClassifyId = ed.ClassifyId
+		}
+		respList = append(respList, t)
+	}
+	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	dataResp := new(data_manage.BloombergSourceListResp)
+	dataResp.Paging = page
+	dataResp.List = respList
+
+	br.Data = dataResp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// BatchAdd
+// @Title 批量新增
+// @Description 批量新增
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /bloomberg_source/batch_add [post]
+func (this *BloombergDataController) BatchAdd() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+
+	deleteCache := true
+	cacheKey := "CACHE_EDB_INFO_BATCH_ADD_BLOOMBERG_" + strconv.Itoa(sysUser.AdminId)
+	defer func() {
+		if deleteCache {
+			_ = utils.Rc.Delete(cacheKey)
+		}
+	}()
+	if !utils.Rc.SetNX(cacheKey, 1, 30*time.Second) {
+		deleteCache = false
+		br.Msg = "系统处理中,请稍后重试!"
+		br.ErrMsg = "系统处理中,请稍后重试!" + sysUser.RealName + ";data:" + string(this.Ctx.Input.RequestBody)
+		return
+	}
+	var req []*data_manage.AddEdbInfoReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+	if len(req) > 30 {
+		br.Msg = "批量添加指标数量不得超过30个"
+		return
+	}
+	indexNames := make([]string, 0)
+	for _, v := range req {
+		v.EdbCode = strings.TrimSpace(v.EdbCode)
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不可为空"
+			return
+		}
+		v.EdbName = strings.TrimSpace(v.EdbName)
+		if v.EdbName == "" {
+			br.Msg = "请输入指标名称"
+			return
+		}
+		indexNames = append(indexNames, v.EdbName)
+		v.Frequency = strings.TrimSpace(v.Frequency)
+		if v.Frequency == "" {
+			br.Msg = "请选择频度"
+			return
+		}
+		v.Unit = strings.TrimSpace(v.Unit)
+		if v.Unit == "" {
+			br.Msg = "请输入单位"
+			return
+		}
+		if v.ClassifyId <= 0 {
+			br.Msg = "请选择分类"
+			return
+		}
+	}
+
+	// 限定同一时间最多批量新增30个指标
+	for _, v := range req {
+		var r data.BloombergIndexSource2EdbReq
+		r.EdbCode = v.EdbCode
+		r.EdbName = v.EdbName
+		r.Frequency = v.Frequency
+		r.Unit = v.Unit
+		r.ClassifyId = v.ClassifyId
+		r.AdminId = sysUser.AdminId
+		r.AdminRealName = sysUser.RealName
+
+		edbInfo, e, errMsg, skip := data.BloombergIndexSource2Edb(r, this.Lang)
+		if e != nil {
+			br.Msg = "操作失败"
+			if errMsg != "" {
+				br.Msg = errMsg
+			}
+			br.ErrMsg = e.Error()
+			return
+		}
+		if skip {
+			continue
+		}
+
+		// 试用平台更新用户累计新增指标数
+		if utils.BusinessCode == utils.BusinessCodeSandbox {
+			go func() {
+				adminItem, e := system.GetSysAdminById(sysUser.AdminId)
+				if e != nil {
+					tips := fmt.Sprintf("试用平台更新用户累计新增指标数-获取用户失败, Err: " + e.Error())
+					utils.FileLog.Info(tips)
+					return
+				}
+				if adminItem.DepartmentName != "ETA试用客户" {
+					return
+				}
+				var ur etaTrialService.EtaTrialUserReq
+				ur.Mobile = adminItem.Mobile
+				_, _ = etaTrialService.UpdateUserIndexNum(ur)
+			}()
+		}
+
+		// 新增操作日志
+		{
+			edbLog := new(data_manage.EdbInfoLog)
+			edbLog.EdbInfoId = edbInfo.EdbInfoId
+			edbLog.SourceName = edbInfo.SourceName
+			edbLog.Source = edbInfo.Source
+			edbLog.EdbCode = edbInfo.EdbCode
+			edbLog.EdbName = edbInfo.EdbName
+			edbLog.ClassifyId = edbInfo.ClassifyId
+			edbLog.SysUserId = sysUser.AdminId
+			edbLog.SysUserRealName = sysUser.RealName
+			edbLog.CreateTime = time.Now()
+			edbLog.Content = string(this.Ctx.Input.RequestBody)
+			edbLog.Status = "新增指标"
+			edbLog.Method = this.Ctx.Input.URI()
+			go data_manage.AddEdbInfoLog(edbLog)
+		}
+	}
+
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+	br.IsAddLog = true
+}
+
+// NameCheck
+// @Title 重名校验
+// @Description 批量新增
+// @Param	request	body data_manage.AddEdbInfoReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /bloomberg_source/name_check [post]
+func (this *BloombergDataController) NameCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req []*data_manage.AddEdbInfoReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	if len(req) == 0 {
+		br.Msg = "请选择指标"
+		return
+	}
+
+	type NameCheckResult struct {
+		EdbCode string
+		EdbName string
+		Exist   bool
+	}
+	indexNames := make([]string, 0)
+	resp := make([]*NameCheckResult, 0)
+	for _, v := range req {
+		v.EdbCode = strings.TrimSpace(v.EdbCode)
+		if v.EdbCode == "" {
+			br.Msg = "指标ID不可为空"
+			return
+		}
+		v.EdbName = strings.TrimSpace(v.EdbName)
+		if v.EdbName == "" {
+			br.Msg = "请输入指标名称"
+			return
+		}
+		indexNames = append(indexNames, v.EdbName)
+		resp = append(resp, &NameCheckResult{
+			EdbCode: v.EdbCode,
+			EdbName: v.EdbName,
+		})
+	}
+
+	// 重名校验
+	edbList, e := data_manage.GetEdbInfoByNameArr(indexNames)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取重名指标失败, Err: " + e.Error()
+		return
+	}
+	nameExists := make(map[string]bool)
+	for _, v := range edbList {
+		nameExists[v.EdbName] = true
+	}
+	if len(nameExists) > 0 {
+		for _, v := range resp {
+			v.Exist = nameExists[v.EdbName]
+		}
+	}
+
+	br.Data = resp
+	br.Msg = "操作成功"
+	br.Ret = 200
+	br.Success = true
+}
+
+// AddCheck
+// @Title 新增校验
+// @Description 新增校验
+// @Param	request	body data_manage.BloombergSourceBatchAddCheckReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /bloomberg_source/add_check [post]
+func (this *BloombergDataController) AddCheck() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req *data_manage.BloombergSourceBatchAddCheckReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+	codeMax := 30
+	codeLen := len(req.IndexCodes)
+
+	// 排序, 默认创建时间倒序
+	orderFields := map[int]string{
+		0: data_manage.BaseFromBloombergIndexCols.CreateTime, 1: data_manage.BaseFromBloombergIndexCols.StartDate,
+		2: data_manage.BaseFromBloombergIndexCols.EndDate, 3: data_manage.BaseFromBloombergIndexCols.ModifyTime,
+	}
+	orderType := map[int]string{0: "DESC", 1: "ASC", 2: "DESC"}
+	orderRule := fmt.Sprintf("%s %s", orderFields[req.SortField], orderType[req.SortRule])
+
+	// 获取指标库已有指标
+	existsEdb, e := data_manage.GetEdbCodesBySource(utils.DATA_SOURCE_BLOOMBERG)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取Bloomberg已添加的指标失败, Err: " + e.Error()
+		return
+	}
+	existMap := make(map[string]*data_manage.EdbInfo)
+	for _, v := range existsEdb {
+		existMap[v.EdbCode] = v
+	}
+
+	// 非全选-不需要频率等筛选条件
+	bloombergOb := new(data_manage.BaseFromBloombergIndex)
+	if !req.ListAll {
+		if codeLen == 0 {
+			br.Msg = "请选择指标"
+			return
+		}
+		if codeLen > codeMax {
+			br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMax)
+			return
+		}
+
+		// 查询选中的指标
+		cond := fmt.Sprintf(` AND %s IN (%s)`, data_manage.BaseFromBloombergIndexCols.IndexCode, utils.GetOrmInReplace(codeLen))
+		pars := make([]interface{}, 0)
+		pars = append(pars, req.IndexCodes)
+		list, e := bloombergOb.GetItemsByCondition(cond, pars, []string{}, orderRule, 0)
+		if e != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取Bloomberg原始指标列表失败, Err: " + e.Error()
+			return
+		}
+		resp := make([]*data_manage.BaseFromBloombergIndexItem, 0)
+		for _, v := range list {
+			t := data_manage.FormatBaseFromBloombergIndex2Item(v)
+			ed := existMap[v.IndexCode]
+			if ed != nil {
+				t.EdbExist = 1
+				t.EdbInfoId = ed.EdbInfoId
+				t.EdbUniqueCode = ed.UniqueCode
+				t.EdbClassifyId = ed.ClassifyId
+			}
+			resp = append(resp, t)
+		}
+
+		br.Data = resp
+		br.Msg = "校验成功"
+		br.Ret = 200
+		br.Success = true
+		return
+	}
+
+	// 全选-需要频率等筛选条件
+	cond := ``
+	pars := make([]interface{}, 0)
+	// 筛选项
+	req.Keywords = strings.TrimSpace(req.Keywords)
+	if req.Keywords != "" {
+		cond += fmt.Sprintf(` AND (%s LIKE ? OR %s LIKE ?)`, data_manage.BaseFromBloombergIndexCols.IndexCode, data_manage.BaseFromBloombergIndexCols.IndexName)
+		kw := fmt.Sprint("%", req.Keywords, "%")
+		pars = append(pars, kw, kw)
+	}
+	if req.Frequency != "" {
+		cond += fmt.Sprintf(` AND %s = ?`, data_manage.BaseFromBloombergIndexCols.Frequency)
+		pars = append(pars, req.Frequency)
+	}
+	// 排除对应指标
+	if codeLen > 0 {
+		cond += fmt.Sprintf(` AND %s NOT IN (%s)`, data_manage.BaseFromBloombergIndexCols.IndexCode, utils.GetOrmInReplace(codeLen))
+		pars = append(pars, req.IndexCodes)
+	}
+	// 查询max+1个指标
+	list, e := bloombergOb.GetItemsByCondition(cond, pars, []string{}, orderRule, codeMax+1)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取Bloomberg原始指标列表失败, Err: " + e.Error()
+		return
+	}
+	if len(list) > codeMax {
+		br.Msg = fmt.Sprintf("最多只能选择%d个指标", codeMax)
+		return
+	}
+
+	resp := make([]*data_manage.BaseFromBloombergIndexItem, 0)
+	for _, v := range list {
+		t := data_manage.FormatBaseFromBloombergIndex2Item(v)
+		ed := existMap[v.IndexCode]
+		if ed != nil {
+			t.EdbExist = 1
+			t.EdbInfoId = ed.EdbInfoId
+			t.EdbUniqueCode = ed.UniqueCode
+			t.EdbClassifyId = ed.ClassifyId
+		}
+		resp = append(resp, t)
+	}
+
+	br.Data = resp
+	br.Msg = "校验成功"
+	br.Ret = 200
+	br.Success = true
+}

+ 38 - 0
controllers/data_manage/chart_info.go

@@ -1105,6 +1105,44 @@ func (this *ChartInfoController) ChartInfoDetail() {
 			br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 			br.ErrMsg = "获取图表,指标信息失败,Err:" + err.Error()
 			return
 			return
 		}
 		}
+
+		// 指标权限
+		{
+
+			classifyMap := make(map[int]*data_manage.EdbClassify)
+
+			// 分类
+			{
+				classifyIdList := make([]int, 0)
+				for _, v := range edbList {
+					classifyIdList = append(classifyIdList, v.ClassifyId)
+				}
+				classifyList, tmpErr := data_manage.GetEdbClassifyByIdList(classifyIdList)
+				if tmpErr != nil {
+					br.Msg = "获取失败"
+					br.ErrMsg = "获取分类列表失败,Err:" + tmpErr.Error()
+					return
+				}
+				for _, v := range classifyList {
+					classifyMap[v.ClassifyId] = v
+				}
+			}
+			// 获取所有有权限的指标和分类
+			permissionEdbIdList, permissionClassifyIdList, err := data_manage_permission.GetUserEdbAndClassifyPermissionList(sysUser.AdminId, 0, 0)
+			if err != nil {
+				br.Msg = "获取失败"
+				br.ErrMsg = "获取所有有权限的指标和分类失败,Err:" + err.Error()
+				return
+			}
+
+			for _, item := range edbList {
+				// 数据权限
+				if currClassify, ok := classifyMap[item.ClassifyId]; ok {
+					item.HaveOperaAuth = data_manage_permission.CheckEdbPermissionByPermissionIdList(item.IsJoinPermission, currClassify.IsJoinPermission, item.EdbInfoId, item.ClassifyId, permissionEdbIdList, permissionClassifyIdList)
+				}
+			}
+		}
+
 		// 单位
 		// 单位
 		if chartType == utils.CHART_TYPE_BAR && len(yDataList) > 0 {
 		if chartType == utils.CHART_TYPE_BAR && len(yDataList) > 0 {
 			chartInfo.Unit = yDataList[0].Unit
 			chartInfo.Unit = yDataList[0].Unit

+ 2 - 2
controllers/data_manage/chart_theme.go

@@ -160,7 +160,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 		chartInfo.ChartName = "散点图"
 		chartInfo.ChartName = "散点图"
 	case 7: // 柱形图
 	case 7: // 柱形图
 		edbInfoIdList = []int{1, 2, 3, 4, 5}
 		edbInfoIdList = []int{1, 2, 3, 4, 5}
-		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":"#00f","Name":""},{"Type":1,"Date":"","Value":0,"Color":"#f00","Name":""}],"Sort":{"Sort":0,"DateIndex":0},"XEdbList":null,"YEdbList":null,"Unit":"千桶","UnitEn":""}`
+		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 = "柱形图"
 		chartInfo.ChartName = "柱形图"
 	case 10: // 截面散点图
 	case 10: // 截面散点图
 		edbInfoIdList = []int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
 		edbInfoIdList = []int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
@@ -170,7 +170,7 @@ func (c *ChartThemeController) GetThemePreviewData() {
 		edbInfoIdList = []int{19, 20, 21, 22, 23, 24}
 		edbInfoIdList = []int{19, 20, 21, 22, 23, 24}
 		chartInfo.LeftMin = "10000"
 		chartInfo.LeftMin = "10000"
 		chartInfo.LeftMax = "60000"
 		chartInfo.LeftMax = "60000"
-		extraConfigStr = `{"DateList":[{"Type":3,"Date":"2023-11-01","Value":0,"Color":"#00f","Name":""},{"Type":1,"Date":"","Value":0,"Color":"#f00","Name":""}]}`
+		extraConfigStr = `{"DateList":[{"Type":3,"Date":"2023-11-01","Value":0,"Color":"","Name":""},{"Type":1,"Date":"","Value":0,"Color":"","Name":""}]}`
 		chartInfo.ChartName = "雷达图"
 		chartInfo.ChartName = "雷达图"
 	default:
 	default:
 		br.Msg = "暂不支持该类型"
 		br.Msg = "暂不支持该类型"

+ 4 - 4
controllers/data_manage/excel/excel_classify.go

@@ -42,10 +42,10 @@ func (this *ExcelClassifyController) List() {
 	//只看我的
 	//只看我的
 	isShowMe, _ := this.GetBool("IsShowMe")
 	isShowMe, _ := this.GetBool("IsShowMe")
 	// 自定义分析只看自己的
 	// 自定义分析只看自己的
-	if source == utils.CUSTOM_ANALYSIS_TABLE {
-		br = AnalysisClassifyList(this)
-		return
-	}
+	//if source == utils.CUSTOM_ANALYSIS_TABLE {
+	//	br = AnalysisClassifyList(this)
+	//	return
+	//}
 
 
 	showUserId := 0
 	showUserId := 0
 	if isShowMe {
 	if isShowMe {

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

@@ -95,8 +95,24 @@ func (this *VarietyController) EdbList() {
 		}
 		}
 
 
 		if tmpItem, ok := edbInfoAndClassifyMap[v.EdbInfoId]; ok {
 		if tmpItem, ok := edbInfoAndClassifyMap[v.EdbInfoId]; ok {
-			v.ClassifyName = tmpItem.FirstClassifyName + "/" + tmpItem.SecondClassifyName
-			v.ClassifyId = tmpItem.SecondClassifyId
+			classifyNameList := make([]string, 0)
+
+			// 所属分类
+			{
+				classifyList, tmpErr, errMsg := data.GetFullClassifyByClassifyId(tmpItem.ClassifyId)
+				if tmpErr != nil {
+					br.Msg = errMsg
+					br.ErrMsg = "获取ETA指标的分类信息失败,Err:" + err.Error()
+					return
+				}
+				for _, tmpClassify := range classifyList {
+					classifyNameList = append(classifyNameList, tmpClassify.ClassifyName)
+				}
+			}
+
+			v.ClassifyName = strings.Join(classifyNameList, "/")
+
+			v.ClassifyId = tmpItem.ClassifyId
 			v.EdbCode = tmpItem.EdbCode
 			v.EdbCode = tmpItem.EdbCode
 			v.UniqueCode = tmpItem.UniqueCode
 			v.UniqueCode = tmpItem.UniqueCode
 		} else {
 		} else {

+ 372 - 0
controllers/fe_calendar/fe_calendar_matter.go

@@ -0,0 +1,372 @@
+package fe_calendar
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/fe_calendar"
+	"eta/eta_api/utils"
+	"fmt"
+	"strings"
+	"time"
+)
+
+// FeCalendarMatterController 外汇日历-事项
+type FeCalendarMatterController struct {
+	controllers.BaseAuthController
+}
+
+// List
+// @Title 事项列表
+// @Description 事项列表
+// @Param   ChartPermissionId	query	int		true	"品种ID"
+// @Param   StartDate			query	string	true	"开始日期"
+// @Param   EndDate				query   string	true	"结束日期"
+// @Success 200 {object} fe_calendar.FeCalendarMatterListItem
+// @router /matter/list [get]
+func (this *FeCalendarMatterController) List() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	params := new(fe_calendar.FeCalendarMatterListReq)
+	if e := this.ParseForm(params); e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "入参解析失败, Err: " + e.Error()
+		return
+	}
+	if params.ChartPermissionId <= 0 {
+		br.Msg = "请选择品种"
+		return
+	}
+
+	cond := ``
+	pars := make([]interface{}, 0)
+	if params.ChartPermissionId > 0 {
+		cond += fmt.Sprintf(` AND %s = ?`, fe_calendar.FeCalendarMatterCols.ChartPermissionId)
+		pars = append(pars, params.ChartPermissionId)
+	}
+	if params.StartDate != "" && params.EndDate != "" {
+		_, e := time.Parse(utils.FormatDate, params.StartDate)
+		if e != nil {
+			br.Msg = "开始日期格式有误"
+			return
+		}
+		_, e = time.Parse(utils.FormatDate, params.EndDate)
+		if e != nil {
+			br.Msg = "结束日期格式有误"
+			return
+		}
+		cond += fmt.Sprintf(` AND %s >= ? AND %s <= ?`, fe_calendar.FeCalendarMatterCols.MatterDate, fe_calendar.FeCalendarMatterCols.MatterDate)
+		pars = append(pars, params.StartDate, params.EndDate)
+	}
+
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	order := fmt.Sprintf(`%s ASC, %s ASC`, fe_calendar.FeCalendarMatterCols.MatterDate, fe_calendar.FeCalendarMatterCols.Sort)
+	matters, e := matterOb.GetItemsByCondition(cond, pars, []string{}, order)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取事项列表失败, Err: " + e.Error()
+		return
+	}
+
+	dateMatter := make(map[string][]*fe_calendar.FeCalendarMatterItem)
+	for _, v := range matters {
+		d := v.MatterDate.Format(utils.FormatDate)
+		if dateMatter[d] == nil {
+			dateMatter[d] = make([]*fe_calendar.FeCalendarMatterItem, 0)
+		}
+		dateMatter[d] = append(dateMatter[d], fe_calendar.FormatFeCalendarMatter2Item(v))
+	}
+	dateExist := make(map[string]bool)
+	resp := make([]*fe_calendar.FeCalendarMatterListItem, 0)
+	for _, v := range matters {
+		d := v.MatterDate.Format(utils.FormatDate)
+		if dateExist[d] {
+			continue
+		}
+		dateExist[d] = true
+		resp = append(resp, &fe_calendar.FeCalendarMatterListItem{
+			Date:    d,
+			Matters: dateMatter[d],
+		})
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Detail
+// @Title 事项详情
+// @Description 事项详情
+// @Param   ChartPermissionId  query  int  true  "品种ID"
+// @Param   MatterDate  query  string  true  "事项日期"
+// @Success 200 {object} fe_calendar.FeCalendarMatterItem
+// @router /matter/detail [get]
+func (this *FeCalendarMatterController) Detail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	permissionId, _ := this.GetInt("ChartPermissionId")
+	if permissionId <= 0 {
+		br.Msg = "请选择品种"
+		return
+	}
+	matterDate := this.GetString("MatterDate")
+	if matterDate == "" {
+		br.Msg = "请选择日期"
+		return
+	}
+	_, e := time.Parse(utils.FormatDate, matterDate)
+	if e != nil {
+		br.Msg = "日期格式有误"
+		return
+	}
+
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	cond := fmt.Sprintf(` AND %s = ? AND %s = ?`, fe_calendar.FeCalendarMatterCols.ChartPermissionId, fe_calendar.FeCalendarMatterCols.MatterDate)
+	pars := make([]interface{}, 0)
+	pars = append(pars, permissionId, matterDate)
+	order := fmt.Sprintf(`%s ASC`, fe_calendar.FeCalendarMatterCols.Sort)
+	matters, e := matterOb.GetItemsByCondition(cond, pars, []string{}, order)
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取事项列表失败, Err: " + e.Error()
+		return
+	}
+	resp := make([]*fe_calendar.FeCalendarMatterItem, 0)
+	for _, v := range matters {
+		resp = append(resp, fe_calendar.FormatFeCalendarMatter2Item(v))
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}
+
+// Save
+// @Title 保存事项
+// @Description 保存事项
+// @Param	request	body fe_calendar.FeCalendarMatterSaveReq true "type json string"
+// @Success 200 string "操作成功"
+// @router /matter/save [post]
+func (this *FeCalendarMatterController) Save() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	var req fe_calendar.FeCalendarMatterSaveReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	// 参数校验
+	if req.ChartPermissionId <= 0 {
+		br.Msg = "请选择品种"
+		return
+	}
+	if req.MatterDate == "" {
+		br.Msg = "请选择日期"
+		return
+	}
+	var matterMonth string
+	matterDate, e := time.ParseInLocation(utils.FormatDate, req.MatterDate, time.Local)
+	if e != nil {
+		br.Msg = "日期格式有误"
+		return
+	}
+	matterMonth = matterDate.Format("2006-01")
+	if len(req.Matters) > 0 {
+		for _, v := range req.Matters {
+			if v.MatterType != fe_calendar.MatterTypeFree && v.MatterType != fe_calendar.MatterTypeEdb && v.MatterType != fe_calendar.MatterTypePredict {
+				br.Msg = "事项类型有误"
+				br.ErrMsg = fmt.Sprintf("事项类型有误, MatterType: %d", v.MatterType)
+				return
+			}
+			v.Title = strings.TrimSpace(v.Title)
+			if v.Title == "" {
+				br.Msg = "请输入指标/事项名称"
+				return
+			}
+			if len([]rune(v.Title)) > 15 {
+				br.Msg = "名称超出15个字,请重新编辑"
+				return
+			}
+			if v.MatterType == fe_calendar.MatterTypeEdb || v.MatterType == fe_calendar.MatterTypePredict {
+				if v.EdbInfoId <= 0 || v.EdbUniqueCode == "" || v.EdbCode == "" {
+					br.Msg = "指标信息有误"
+					br.ErrMsg = fmt.Sprintf("指标信息有误, EdbInfoId: %d, EdbUniqueCode: %s, EdbCode: %s", v.EdbInfoId, v.EdbUniqueCode, v.EdbCode)
+					return
+				}
+			}
+		}
+	}
+
+	// 品种信息
+	permissionItem, e := models.GetChartPermissionById(req.ChartPermissionId)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取品种失败, Err: " + e.Error()
+		return
+	}
+
+	// 获取已有事项
+	matterOb := new(fe_calendar.FeCalendarMatter)
+	cond := fmt.Sprintf(` AND %s = ? AND %s = ?`, fe_calendar.FeCalendarMatterCols.ChartPermissionId, fe_calendar.FeCalendarMatterCols.MatterDate)
+	pars := make([]interface{}, 0)
+	pars = append(pars, req.ChartPermissionId, req.MatterDate)
+	order := fmt.Sprintf(`%s ASC`, fe_calendar.FeCalendarMatterCols.Sort)
+	matters, e := matterOb.GetItemsByCondition(cond, pars, []string{}, order)
+	if e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "获取已有事项列表失败, Err: " + e.Error()
+		return
+	}
+
+	addMatters := make([]*fe_calendar.FeCalendarMatter, 0)
+	editMatters := make([]*fe_calendar.FeCalendarMatter, 0)
+	removeMatters := make([]*fe_calendar.FeCalendarMatter, 0)
+	updateCols := []string{fe_calendar.FeCalendarMatterCols.Title, fe_calendar.FeCalendarMatterCols.FontColor, fe_calendar.FeCalendarMatterCols.FillingColor, fe_calendar.FeCalendarMatterCols.FontBold, fe_calendar.FeCalendarMatterCols.Sort, fe_calendar.FeCalendarMatterCols.ChartPermissionName, fe_calendar.FeCalendarMatterCols.ModifyTime}
+
+	editIds := make([]int, 0)
+	editMatterMap := make(map[int]*fe_calendar.FeCalendarMatterSaveItem)
+	for _, v := range req.Matters {
+		// 更新的事项map
+		if v.FeCalendarMatterId > 0 {
+			editIds = append(editIds, v.FeCalendarMatterId)
+			editMatterMap[v.FeCalendarMatterId] = v
+			continue
+		}
+		// 新增事项
+		addMatters = append(addMatters, &fe_calendar.FeCalendarMatter{
+			ChartPermissionId:   req.ChartPermissionId,
+			ChartPermissionName: permissionItem.PermissionName,
+			MatterMonth:         matterMonth,
+			MatterDate:          matterDate,
+			Title:               strings.TrimSpace(v.Title),
+			MatterType:          v.MatterType,
+			EdbInfoId:           v.EdbInfoId,
+			EdbUniqueCode:       v.EdbUniqueCode,
+			EdbCode:             v.EdbCode,
+			FontColor:           v.FontColor,
+			FillingColor:        v.FillingColor,
+			FontBold:            v.FontBold,
+			Sort:                v.Sort,
+			SysUserId:           sysUser.AdminId,
+			SysUserName:         sysUser.RealName,
+			CreateTime:          time.Now().Local(),
+			ModifyTime:          time.Now().Local(),
+		})
+	}
+	for _, v := range matters {
+		// 移除的事项
+		if !utils.InArrayByInt(editIds, v.FeCalendarMatterId) {
+			removeMatters = append(removeMatters, v)
+			continue
+		}
+		// 编辑的事项
+		ed := editMatterMap[v.FeCalendarMatterId]
+		if ed != nil {
+			v.Title = strings.TrimSpace(ed.Title)
+			v.FontColor = ed.FontColor
+			v.FillingColor = ed.FillingColor
+			v.FontBold = ed.FontBold
+			v.Sort = ed.Sort
+			v.ChartPermissionName = permissionItem.PermissionName
+			v.ModifyTime = time.Now().Local()
+			editMatters = append(editMatters, v)
+		}
+	}
+
+	// 保存/删除
+	if e = matterOb.Save(addMatters, editMatters, removeMatters, updateCols); e != nil {
+		br.Msg = "操作失败"
+		br.ErrMsg = "保存事项失败, Err: " + e.Error()
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "操作成功"
+}
+
+// PermissionList
+// @Title 品种列表
+// @Description 品种列表
+// @Success 200 {object} models.SimpleChartPermission
+// @router /permission/list [get]
+func (this *FeCalendarMatterController) PermissionList() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		if br.ErrMsg == "" {
+			br.IsSendEmail = false
+		}
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	permissions, e := models.GetChartPermissionsByProductId()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取品种列表失败, Err: " + e.Error()
+		return
+	}
+	resp := make([]*models.SimpleChartPermission, 0)
+	parentPermissions := make(map[int][]*models.SimpleChartPermission, 0)
+	for _, v := range permissions {
+		if v.ParentId > 0 {
+			if parentPermissions[v.ParentId] == nil {
+				parentPermissions[v.ParentId] = make([]*models.SimpleChartPermission, 0)
+			}
+			parentPermissions[v.ParentId] = append(parentPermissions[v.ParentId], models.FormatChartPermission2Simple(v))
+			continue
+		}
+		resp = append(resp, models.FormatChartPermission2Simple(v))
+	}
+	for _, v := range resp {
+		v.Children = parentPermissions[v.ChartPermissionId]
+	}
+
+	br.Data = resp
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 5 - 2
controllers/report.go

@@ -1286,8 +1286,11 @@ func (this *ReportUploadCommonController) UploadImg() {
 	}
 	}
 	pass := filetype.IsImage(fileData)
 	pass := filetype.IsImage(fileData)
 	if !pass {
 	if !pass {
-		err = fmt.Errorf("文件格式有误")
-		return
+		kind, _ := filetype.Match(fileData)
+		if kind.Extension != "pdf" {
+			err = fmt.Errorf("文件格式有误")
+			return
+		}
 	}
 	}
 
 
 	ext := path.Ext(h.Filename)
 	ext := path.Ext(h.Filename)

+ 58 - 57
controllers/target.go

@@ -928,6 +928,63 @@ func (this *TargetController) ImportData() {
 					if strings.Contains(closeVal, "#N/A") {
 					if strings.Contains(closeVal, "#N/A") {
 						continue
 						continue
 					}
 					}
+
+					//校验表格中的日期格式
+					if strings.Contains(createDate, "-") {
+						//如果是带有 - 的普通日期格式文本
+						_, timeErr := time.Parse("2006-1-2", createDate)
+						if timeErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+					} else if strings.Contains(createDate, "/") {
+						//如果是带有 / 的普通日期格式文本
+						createDateTime, timeErr := time.Parse("2006/1/2", createDate)
+						if timeErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+						createDate = createDateTime.Format("2006-01-02")
+					} else {
+						//可能是excel的日期格式
+						_, tmpErr := strconv.Atoi(createDate)
+						if tmpErr != nil {
+							failItem := new(models.EdbdataImportFail)
+							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
+							failItem.ClassifyName = classifyName
+							failItem.CreateDate = createDate
+							failItem.SecName = secName
+							failItem.Close = closeVal
+							failItem.Remark = "日期格式异常"
+							failItem.Frequency = frequency
+							failItem.Unit = unit
+							failDatas = append(failDatas, failItem)
+							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
+							continue
+						}
+						createDate = utils.ConvertToFormatDay(createDate) //录入日期
+					}
+
 					closeValFloat, err := cells[3].Float() //值
 					closeValFloat, err := cells[3].Float() //值
 
 
 					if err != nil {
 					if err != nil {
@@ -987,62 +1044,6 @@ func (this *TargetController) ImportData() {
 					}
 					}
 					//fmt.Println(classifyName, createDate, secName, closeVal)
 					//fmt.Println(classifyName, createDate, secName, closeVal)
 
 
-					//校验表格中的日期格式
-					if strings.Contains(createDate, "-") {
-						//如果是带有 - 的普通日期格式文本
-						_, timeErr := time.Parse("2006-1-2", createDate)
-						if timeErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-					} else if strings.Contains(createDate, "/") {
-						//如果是带有 / 的普通日期格式文本
-						createDateTime, timeErr := time.Parse("2006/1/2", createDate)
-						if timeErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-						createDate = createDateTime.Format("2006-01-02")
-					} else {
-						//可能是excel的日期格式
-						_, tmpErr := strconv.Atoi(createDate)
-						if tmpErr != nil {
-							failItem := new(models.EdbdataImportFail)
-							failItem.SysUserId = strconv.Itoa(sysUser.AdminId)
-							failItem.ClassifyName = classifyName
-							failItem.CreateDate = createDate
-							failItem.SecName = secName
-							failItem.Close = closeVal
-							failItem.Remark = "日期格式异常"
-							failItem.Frequency = frequency
-							failItem.Unit = unit
-							failDatas = append(failDatas, failItem)
-							//go utils.SendEmail(utils.APPNAME+"失败提醒", "导入数据 获取分类:Err:"+err.Error(), utils.EmailSendToUsers)
-							continue
-						}
-						createDate = utils.ConvertToFormatDay(createDate) //录入日期
-					}
-
 					//获取指标分类信息
 					//获取指标分类信息
 					classify, ok := edbDataClassifyMap[classifyName]
 					classify, ok := edbDataClassifyMap[classifyName]
 					if !ok {
 					if !ok {
@@ -1294,7 +1295,7 @@ func (this *TargetController) ImportFailListDownload() {
 		row.AddCell().SetValue(v.ClassifyName)
 		row.AddCell().SetValue(v.ClassifyName)
 		row.AddCell().SetValue(v.CreateDate)
 		row.AddCell().SetValue(v.CreateDate)
 		row.AddCell().SetValue(v.SecName)
 		row.AddCell().SetValue(v.SecName)
-		row.AddCell().SetValue(v.Close)
+		row.AddCell().SetString(v.Close)
 		row.AddCell().SetValue(v.Frequency)
 		row.AddCell().SetValue(v.Frequency)
 		row.AddCell().SetValue(v.Unit)
 		row.AddCell().SetValue(v.Unit)
 		row.AddCell().SetValue(v.Remark)
 		row.AddCell().SetValue(v.Remark)

+ 18 - 12
controllers/user_login.go

@@ -269,19 +269,7 @@ func (this *UserLoginController) Login() {
 	}
 	}
 	req.Username = strings.TrimSpace(req.Username)
 	req.Username = strings.TrimSpace(req.Username)
 	req.Mobile = strings.TrimSpace(req.Mobile)
 	req.Mobile = strings.TrimSpace(req.Mobile)
-	if req.Mobile != "" {
-		if !utils.ValidateMobileFormatat(req.Mobile) {
-			br.Msg = "您的手机号输入有误, 请检查"
-			return
-		}
-	}
 	req.Email = strings.TrimSpace(req.Email)
 	req.Email = strings.TrimSpace(req.Email)
-	if req.Email != "" {
-		if !utils.ValidateEmailFormatat(req.Email) {
-			br.Msg = "您的邮箱输入有误, 请检查"
-			return
-		}
-	}
 	req.VerifyCode = strings.TrimSpace(req.VerifyCode)
 	req.VerifyCode = strings.TrimSpace(req.VerifyCode)
 	if req.LoginType != 1 && req.LoginType != 2 && req.LoginType != 3 {
 	if req.LoginType != 1 && req.LoginType != 2 && req.LoginType != 3 {
 		br.Msg = "登录方式有误"
 		br.Msg = "登录方式有误"
@@ -1040,16 +1028,34 @@ func (this *UserLoginController) BaseInfo() {
 		return
 		return
 	}
 	}
 
 
+	logoCn, e := models.GetBusinessConfByKey("LogoCN")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+
+	logoEn, e := models.GetBusinessConfByKey("LogoEN")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
+
 	type BaseInfoResp struct {
 	type BaseInfoResp struct {
 		Icp      *models.BusinessConf `description:"Icp信息"`
 		Icp      *models.BusinessConf `description:"Icp信息"`
 		ETATitle *models.BusinessConf `description:"eta系统名称"`
 		ETATitle *models.BusinessConf `description:"eta系统名称"`
 		TabName  *models.BusinessConf `description:"tab页名称"`
 		TabName  *models.BusinessConf `description:"tab页名称"`
+		LogoCn   *models.BusinessConf `description:"中文logo"`
+		LogoEn   *models.BusinessConf `description:"英文logo"`
 	}
 	}
 
 
 	resp := BaseInfoResp{
 	resp := BaseInfoResp{
 		Icp:      icp,
 		Icp:      icp,
 		ETATitle: title,
 		ETATitle: title,
 		TabName:  tabName,
 		TabName:  tabName,
+		LogoCn:   logoCn,
+		LogoEn:   logoEn,
 	}
 	}
 
 
 	br.Data = resp
 	br.Data = resp

+ 9 - 1
models/aimod/ai.go

@@ -1,8 +1,9 @@
 package aimod
 package aimod
 
 
 import (
 import (
-	"github.com/beego/beego/v2/client/orm"
 	"time"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
 )
 )
 
 
 type AiChatTopic struct {
 type AiChatTopic struct {
@@ -35,6 +36,7 @@ type AiChat struct {
 type ChatReq struct {
 type ChatReq struct {
 	AiChatTopicId int    `description:"主题id"`
 	AiChatTopicId int    `description:"主题id"`
 	Ask           string `description:"提问"`
 	Ask           string `description:"提问"`
+	Model         string `description:"模型"`
 }
 }
 
 
 func GetAiChatByAsk(askUuid string) (item *AiChat, err error) {
 func GetAiChatByAsk(askUuid string) (item *AiChat, err error) {
@@ -98,6 +100,12 @@ type AiChatView struct {
 	ModifyTime     string `description:"修改时间"`
 	ModifyTime     string `description:"修改时间"`
 }
 }
 
 
+var ModelViewMap = map[string]string{
+	"gpt-4-1106-preview": "GPT-4 Turbo",
+	"moonshot-v1-32k":    "Kimi",
+	// "moonshot-v1-8k":     "Kimi",
+}
+
 func GetAiChatList(aiChatTopicId int) (item []*AiChatView, err error) {
 func GetAiChatList(aiChatTopicId int) (item []*AiChatView, err error) {
 	sql := ` SELECT * FROM ai_chat WHERE ai_chat_topic_id=? ORDER BY create_time ASC `
 	sql := ` SELECT * FROM ai_chat WHERE ai_chat_topic_id=? ORDER BY create_time ASC `
 	o := orm.NewOrmUsingDB("ai")
 	o := orm.NewOrmUsingDB("ai")

+ 1 - 0
models/aimod/ai_file.go

@@ -4,4 +4,5 @@ type FileRetrieveReq struct {
 	AiChatTopicId int      `description:"主题id"`
 	AiChatTopicId int      `description:"主题id"`
 	Ask           string   `description:"提问问题,如果是上传文件,则填入文件名称"`
 	Ask           string   `description:"提问问题,如果是上传文件,则填入文件名称"`
 	OpenaiFileId  []string `description:"openai返回的文件id"`
 	OpenaiFileId  []string `description:"openai返回的文件id"`
+	Model         string   `description:"模型名称"`
 }
 }

+ 46 - 0
models/chart_permission.go

@@ -7,6 +7,10 @@ import (
 	"time"
 	"time"
 )
 )
 
 
+const (
+	FiccProductId = 1
+)
+
 // ChartPermission 报告权限表
 // ChartPermission 报告权限表
 type ChartPermission struct {
 type ChartPermission struct {
 	ChartPermissionId     int       `orm:"column(chart_permission_id);pk" description:"问题ID" json:"chart_permission_id"`
 	ChartPermissionId     int       `orm:"column(chart_permission_id);pk" description:"问题ID" json:"chart_permission_id"`
@@ -210,3 +214,45 @@ func (c *ChartPermission) GetFirstChartPermissionByParentId(parentId int) (item
 	err = o.Raw(sql, parentId).QueryRow(&item)
 	err = o.Raw(sql, parentId).QueryRow(&item)
 	return
 	return
 }
 }
+
+// GetChartPermissionById 主键获取品种
+func GetChartPermissionById(permissionId int) (item *ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM chart_permission WHERE chart_permission_id = ?`
+	err = o.Raw(sql, permissionId).QueryRow(&item)
+	return
+}
+
+// GetSecondaryChartPermissions 获取二级权限列表
+func GetSecondaryChartPermissions() (list []*ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM chart_permission WHERE product_id = ? AND parent_id > 0 AND enabled = 1 ORDER BY parent_id ASC, sort ASC, created_time ASC`
+	_, err = o.Raw(sql, FiccProductId).QueryRows(&list)
+	return
+}
+
+type SimpleChartPermission struct {
+	ChartPermissionId   int                      `description:"品种ID"`
+	ChartPermissionName string                   `description:"品种名称"`
+	Sort                int                      `description:"排序"`
+	Children            []*SimpleChartPermission `description:"子分类"`
+}
+
+func FormatChartPermission2Simple(origin *ChartPermission) (item *SimpleChartPermission) {
+	if origin == nil {
+		return
+	}
+	item = new(SimpleChartPermission)
+	item.ChartPermissionId = origin.ChartPermissionId
+	item.ChartPermissionName = origin.PermissionName
+	item.Sort = origin.Sort
+	return
+}
+
+// GetChartPermissionsByProductId 获取权限列表
+func GetChartPermissionsByProductId() (list []*ChartPermission, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `SELECT * FROM chart_permission WHERE product_id = ? AND enabled = 1 ORDER BY parent_id ASC, sort ASC, created_time ASC`
+	_, err = o.Raw(sql, FiccProductId).QueryRows(&list)
+	return
+}

+ 285 - 0
models/data_manage/base_from_bloomberg_index.go

@@ -0,0 +1,285 @@
+package data_manage
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+	"strings"
+	"time"
+)
+
+// BaseFromBloombergIndex 彭博原始指标表
+type BaseFromBloombergIndex struct {
+	BaseFromBloombergIndexId int       `orm:"column(base_from_bloomberg_index_id);pk"`
+	IndexCode                string    `description:"指标编码"`
+	IndexName                string    `description:"指标名称"`
+	Unit                     string    `description:"单位"`
+	Source                   int       `description:"数据来源"`
+	Frequency                string    `description:"频度"`
+	StartDate                time.Time `description:"开始日期"`
+	EndDate                  time.Time `description:"结束日期"`
+	Describe                 string    `description:"指标描述"`
+	Sort                     int       `description:"排序"`
+	IsStop                   int       `description:"是否停更:0-否;1-停更"`
+	EdbExist                 int       `description:"指标库是否已添加:0-否;1-是"`
+	TerminalCode             string    `description:"所属终端编码"`
+	FilePath                 string    `description:"文件存储路径"`
+	CreateTime               time.Time `description:"创建时间"`
+	ModifyTime               time.Time `description:"修改时间"`
+}
+
+var BaseFromBloombergIndexCols = struct {
+	BaseFromBloombergIndexId string
+	IndexCode                string
+	IndexName                string
+	Unit                     string
+	Source                   string
+	Frequency                string
+	StartDate                string
+	EndDate                  string
+	Describe                 string
+	Sort                     string
+	IsStop                   string
+	EdbExist                 string
+	TerminalCode             string
+	FilePath                 string
+	CreateTime               string
+	ModifyTime               string
+}{
+	BaseFromBloombergIndexId: "base_from_bloomberg_index_id",
+	IndexCode:                "index_code",
+	IndexName:                "index_name",
+	Unit:                     "unit",
+	Source:                   "source",
+	Frequency:                "frequency",
+	StartDate:                "start_date",
+	EndDate:                  "end_date",
+	Describe:                 "describe",
+	Sort:                     "sort",
+	IsStop:                   "is_stop",
+	EdbExist:                 "edb_exist",
+	TerminalCode:             "terminal_code",
+	FilePath:                 "file_path",
+	CreateTime:               "create_time",
+	ModifyTime:               "modify_time",
+}
+
+func (m *BaseFromBloombergIndex) TableName() string {
+	return "base_from_bloomberg_index"
+}
+
+func (m *BaseFromBloombergIndex) PrimaryId() string {
+	return BaseFromBloombergIndexCols.BaseFromBloombergIndexId
+}
+
+func (m *BaseFromBloombergIndex) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.BaseFromBloombergIndexId = int(id)
+	return
+}
+
+func (m *BaseFromBloombergIndex) CreateMulti(items []*BaseFromBloombergIndex) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *BaseFromBloombergIndex) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *BaseFromBloombergIndex) Del() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.BaseFromBloombergIndexId).Exec()
+	return
+}
+
+func (m *BaseFromBloombergIndex) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *BaseFromBloombergIndex) GetItemById(id int) (item *BaseFromBloombergIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *BaseFromBloombergIndex) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *BaseFromBloombergIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *BaseFromBloombergIndex) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *BaseFromBloombergIndex) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, limit int) (items []*BaseFromBloombergIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	if limit > 0 {
+		sql += fmt.Sprintf(` LIMIT %d`, limit)
+	}
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *BaseFromBloombergIndex) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*BaseFromBloombergIndex, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+// BaseFromBloombergIndexItem 彭博原始指标信息
+type BaseFromBloombergIndexItem struct {
+	BaseFromBloombergIndexId int
+	IndexCode                string `description:"指标编码"`
+	IndexName                string `description:"指标名称"`
+	Unit                     string `description:"单位"`
+	Source                   int    `description:"数据来源"`
+	Frequency                string `description:"频度"`
+	StartDate                string `description:"开始日期"`
+	EndDate                  string `description:"结束日期"`
+	Describe                 string `description:"指标描述"`
+	Sort                     int    `description:"排序"`
+	IsStop                   int    `description:"是否停更:0-否;1-停更"`
+	EdbExist                 int    `description:"指标库是否已添加:0-否;1-是"`
+	CreateTime               string `description:"创建时间"`
+	ModifyTime               string `description:"修改时间"`
+	EdbInfoId                int    `description:"指标库ID"`
+	EdbUniqueCode            string `description:"指标库唯一编码"`
+	EdbClassifyId            int    `description:"指标库分类ID"`
+}
+
+func FormatBaseFromBloombergIndex2Item(origin *BaseFromBloombergIndex) (item *BaseFromBloombergIndexItem) {
+	if origin == nil {
+		return
+	}
+	item = new(BaseFromBloombergIndexItem)
+	item.BaseFromBloombergIndexId = origin.BaseFromBloombergIndexId
+	item.IndexCode = origin.IndexCode
+	item.IndexName = origin.IndexName
+	item.Unit = origin.Unit
+	item.Source = origin.Source
+	item.Frequency = origin.Frequency
+	item.StartDate = utils.TimeTransferString(utils.FormatDate, origin.StartDate)
+	item.EndDate = utils.TimeTransferString(utils.FormatDate, origin.EndDate)
+	item.Describe = origin.Describe
+	item.Sort = origin.Sort
+	item.IsStop = origin.IsStop
+	//item.EdbExist = origin.EdbExist
+	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
+	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
+	return
+}
+
+// BloombergSourceListReq 指标列表筛选
+type BloombergSourceListReq struct {
+	PageSize     int    `form:"PageSize"`
+	CurrentIndex int    `form:"CurrentIndex"`
+	Frequency    string `form:"Frequency" description:"频度"`
+	Keywords     string `form:"Keywords" description:"指标ID/指标名称"`
+	ListAll      bool   `form:"ListAll" description:"列表全选"`
+	SortField    int    `form:"SortField" description:"排序字段: 0-默认; 1-开始时间; 2-最新时间; 3-更新时间"`
+	SortRule     int    `form:"SortRule" description:"排序方式: 0-默认; 1-正序; 2-倒序"`
+}
+
+// BloombergSourceListResp 指标列表响应体
+type BloombergSourceListResp struct {
+	List   []*BaseFromBloombergIndexItem
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+// UpdateEdbExist 标记已添加指标库
+func (m *BaseFromBloombergIndex) UpdateEdbExist(indexCode string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`UPDATE %s SET %s = ? WHERE %s = ? LIMIT 1`, m.TableName(), BaseFromBloombergIndexCols.EdbExist, BaseFromBloombergIndexCols.IndexCode)
+	_, err = o.Raw(sql, 1, indexCode).Exec()
+	return
+}
+
+// BloombergSourceBatchAddCheckReq Bloomberg批量添加校验
+type BloombergSourceBatchAddCheckReq struct {
+	BloombergSourceListReq
+	IndexCodes []string `form:"IndexCodes" description:"全选为false时, 该数组为选中; 全选为true时, 该数组为不选的指标"`
+}
+
+// --------------------------------------------- 以下为测试用 ---------------------------------------------
+
+// BaseFromBloombergData 彭博原始指标表
+//type BaseFromBloombergData struct {
+//	BaseFromBloombergDataId  int       `orm:"column(base_from_bloomberg_data_id);pk"`
+//	BaseFromBloombergIndexId int       `description:"指标ID"`
+//	IndexCode                string    `description:"指标编码"`
+//	DataTime                 time.Time `description:"数据日期"`
+//	Value                    float64   `description:"数据值"`
+//	CreateTime               time.Time `description:"创建时间"`
+//	ModifyTime               time.Time `description:"修改时间"`
+//	DataTimestamp            int       `description:"数据日期时间戳"`
+//}
+//
+//func (m *BaseFromBloombergData) TableName() string {
+//	return "base_from_bloomberg_data"
+//}
+//
+//func (m *BaseFromBloombergData) Create() (err error) {
+//	o := orm.NewOrmUsingDB("data")
+//	id, err := o.Insert(m)
+//	if err != nil {
+//		return
+//	}
+//	m.BaseFromBloombergDataId = int(id)
+//	return
+//}
+//
+//func (m *BaseFromBloombergData) CreateMulti(items []*BaseFromBloombergData) (err error) {
+//	if len(items) == 0 {
+//		return
+//	}
+//	o := orm.NewOrmUsingDB("data")
+//	_, err = o.InsertMulti(len(items), items)
+//	return
+//}

+ 1 - 1
models/data_manage/chart_info.go

@@ -84,7 +84,7 @@ func GetChartInfoAll(sourceList []int) (items []*ChartClassifyItems, err error)
 	}
 	}
 
 
 	o := orm.NewOrmUsingDB("data")
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT chart_info_id,chart_classify_id,chart_name AS chart_classify_name,
+	sql := ` SELECT chart_info_id,chart_classify_id,chart_name AS chart_classify_name,chart_name_en AS chart_classify_name_en,
              unique_code,sys_user_id,sys_user_real_name,date_type,start_date,end_date,chart_type,calendar,season_start_date,season_end_date,source
              unique_code,sys_user_id,sys_user_real_name,date_type,start_date,end_date,chart_type,calendar,season_start_date,season_end_date,source
             FROM chart_info WHERE source in (` + utils.GetOrmInReplace(num) + `)  ORDER BY sort asc,chart_info_id ASC `
             FROM chart_info WHERE source in (` + utils.GetOrmInReplace(num) + `)  ORDER BY sort asc,chart_info_id ASC `
 	_, err = o.Raw(sql, sourceList).QueryRows(&items)
 	_, err = o.Raw(sql, sourceList).QueryRows(&items)

+ 23 - 3
models/data_manage/edb_info.go

@@ -1653,7 +1653,9 @@ type MoveEdbChartList struct {
 	DataId         string `description:"指标/图表唯一id"`
 	DataId         string `description:"指标/图表唯一id"`
 	Code           string `description:"指标code"`
 	Code           string `description:"指标code"`
 	Name           string `description:"指标/图表名称"`
 	Name           string `description:"指标/图表名称"`
+	NameEn         string `description:"指标/图表名称"`
 	ClassifyName   string `description:"分类名称"`
 	ClassifyName   string `description:"分类名称"`
+	ClassifyNameEn string `description:"分类名称"`
 	CreateUserId   int    `description:"创建人id"`
 	CreateUserId   int    `description:"创建人id"`
 	CreateUserName string `description:"创建人名称"`
 	CreateUserName string `description:"创建人名称"`
 }
 }
@@ -1710,6 +1712,7 @@ type EdbAndClassify struct {
 	EdbCode            string `description:"指标code"`
 	EdbCode            string `description:"指标code"`
 	UniqueCode         string `description:"唯一code"`
 	UniqueCode         string `description:"唯一code"`
 	EdbName            string `description:"指标名称"`
 	EdbName            string `description:"指标名称"`
+	ClassifyId         int    `description:"所属分类id"`
 	FirstClassifyId    int    `description:"第1级的分类id"`
 	FirstClassifyId    int    `description:"第1级的分类id"`
 	FirstClassifyName  string `description:"第1级的分类名称"`
 	FirstClassifyName  string `description:"第1级的分类名称"`
 	SecondClassifyId   int    `description:"第2级的分类id"`
 	SecondClassifyId   int    `description:"第2级的分类id"`
@@ -1723,9 +1726,7 @@ func GetEdbInfoAndClassifyListByEdbIdList(edbIdList []int) (items []*EdbAndClass
 		return
 		return
 	}
 	}
 	o := orm.NewOrmUsingDB("data")
 	o := orm.NewOrmUsingDB("data")
-	sql := ` SELECT a.edb_info_id,a.edb_code,a.unique_code,a.edb_name,b.classify_id as second_classify_id,b.classify_name as second_classify_name,c.classify_id as first_classify_id,c.classify_name as first_classify_name FROM edb_info AS a
-			JOIN edb_classify b on a.classify_id=b.classify_id
-			JOIN edb_classify c on b.parent_id=c.classify_id
+	sql := ` SELECT a.edb_info_id,a.edb_code,a.unique_code,a.edb_name,a.classify_id FROM edb_info AS a
 			WHERE a.edb_info_id in (` + utils.GetOrmInReplace(num) + `) `
 			WHERE a.edb_info_id in (` + utils.GetOrmInReplace(num) + `) `
 
 
 	_, err = o.Raw(sql, edbIdList).QueryRows(&items)
 	_, err = o.Raw(sql, edbIdList).QueryRows(&items)
@@ -1921,3 +1922,22 @@ func GetEdbInfoCount(source int, edbCode string) (count int, err error) {
 	err = o.Raw(sql, source, edbCode).QueryRow(&count)
 	err = o.Raw(sql, source, edbCode).QueryRow(&count)
 	return
 	return
 }
 }
+
+// GetEdbInfoByNameArr 根据名称获取指标
+func GetEdbInfoByNameArr(names []string) (items []*EdbInfo, err error) {
+	if len(names) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT edb_info_id, edb_code, edb_name FROM edb_info WHERE edb_name IN (%s)`, utils.GetOrmInReplace(len(names)))
+	_, err = o.Raw(sql, names).QueryRows(&items)
+	return
+}
+
+// GetEdbCodesBySource 根据来源获取指标编码
+func GetEdbCodesBySource(source int) (items []*EdbInfo, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT edb_info_id, edb_code, unique_code, classify_id FROM edb_info WHERE source = ? `
+	_, err = o.Raw(sql, source).QueryRows(&items)
+	return
+}

+ 1 - 0
models/data_manage/predict_edb_info_calculate.go

@@ -13,6 +13,7 @@ type PredictEdbInfoCalculateSaveReq struct {
 	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
+	Extra            string           `description:"指标的额外配置"`
 }
 }
 
 
 // PredictEdbInfoCalculateBatchSaveReq  预测指标比对请求(同比、同差等)
 // PredictEdbInfoCalculateBatchSaveReq  预测指标比对请求(同比、同差等)

+ 11 - 0
models/db.go

@@ -13,6 +13,7 @@ import (
 	"eta/eta_api/models/data_manage/supply_analysis"
 	"eta/eta_api/models/data_manage/supply_analysis"
 	"eta/eta_api/models/data_stat"
 	"eta/eta_api/models/data_stat"
 	"eta/eta_api/models/eta_trial"
 	"eta/eta_api/models/eta_trial"
+	"eta/eta_api/models/fe_calendar"
 	"eta/eta_api/models/ppt_english"
 	"eta/eta_api/models/ppt_english"
 	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/report_approve"
 	"eta/eta_api/models/sandbox"
 	"eta/eta_api/models/sandbox"
@@ -194,6 +195,9 @@ func init() {
 	// 初始化数据资产权限的一些表
 	// 初始化数据资产权限的一些表
 	initDataMangePerMission()
 	initDataMangePerMission()
 
 
+	// 初始化外汇日历
+	initFeCalendar()
+
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	// 初始化部分数据表变量(直接init会有顺序问题=_=!)
 	data_manage.InitEdbSourceVar()
 	data_manage.InitEdbSourceVar()
 }
 }
@@ -595,3 +599,10 @@ func initDataMangePerMission() {
 		new(data_manage_permission.DataPermissionNoAuthRecord),              // 资产数据权限设置记录表
 		new(data_manage_permission.DataPermissionNoAuthRecord),              // 资产数据权限设置记录表
 	)
 	)
 }
 }
+
+// initFeCalendar 初始化外汇日历
+func initFeCalendar() {
+	orm.RegisterModel(
+		new(fe_calendar.FeCalendarMatter), // 事项表
+	)
+}

+ 303 - 0
models/fe_calendar/fe_calendar_matter.go

@@ -0,0 +1,303 @@
+package fe_calendar
+
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+const (
+	MatterTypeFree    = 1 // 事项类型-自定义事项
+	MatterTypeEdb     = 2 // 事项类型-基础指标
+	MatterTypePredict = 3 // 事项类型-预测指标
+)
+
+// FeCalendarMatter 外汇日历-事项表
+type FeCalendarMatter struct {
+	FeCalendarMatterId  int       `orm:"column(fe_calendar_matter_id);pk" description:"事项ID"`
+	ChartPermissionId   int       `description:"品种ID"`
+	ChartPermissionName string    `description:"品种名称"`
+	MatterMonth         string    `description:"事项年月:格式2006-01"`
+	MatterDate          time.Time `description:"事项日期"`
+	Title               string    `description:"标题"`
+	MatterType          int       `description:"事项类型:1-自定义事项;2-基础指标;3-预测指标"`
+	EdbInfoId           int       `description:"指标ID"`
+	EdbUniqueCode       string    `description:"指标唯一编码"`
+	EdbCode             string    `description:"指标编码"`
+	FontColor           string    `description:"字体颜色"`
+	FillingColor        string    `description:"填充颜色"`
+	FontBold            int       `description:"字体加粗:0-否;1-是"`
+	Sort                int       `description:"排序"`
+	SysUserId           int       `description:"创建人ID"`
+	SysUserName         string    `description:"创建人姓名"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"更新时间"`
+}
+
+var FeCalendarMatterCols = struct {
+	FeCalendarMatterId  string
+	ChartPermissionId   string
+	ChartPermissionName string
+	MatterMonth         string
+	MatterDate          string
+	Title               string
+	MatterType          string
+	EdbInfoId           string
+	EdbUniqueCode       string
+	EdbCode             string
+	FontColor           string
+	FillingColor        string
+	FontBold            string
+	Sort                string
+	SysUserId           string
+	SysUserName         string
+	CreateTime          string
+	ModifyTime          string
+}{
+	FeCalendarMatterId:  "fe_calendar_matter_id",
+	ChartPermissionId:   "chart_permission_id",
+	ChartPermissionName: "chart_permission_name",
+	MatterMonth:         "matter_month",
+	MatterDate:          "matter_date",
+	Title:               "title",
+	MatterType:          "matter_type",
+	EdbInfoId:           "edb_info_id",
+	EdbUniqueCode:       "edb_unique_code",
+	EdbCode:             "edb_code",
+	FontColor:           "font_color",
+	FillingColor:        "filling_color",
+	FontBold:            "font_bold",
+	Sort:                "sort",
+	SysUserId:           "sys_user_id",
+	SysUserName:         "sys_user_name",
+	CreateTime:          "create_time",
+	ModifyTime:          "modify_time",
+}
+
+func (m *FeCalendarMatter) TableName() string {
+	return "fe_calendar_matter"
+}
+
+func (m *FeCalendarMatter) PrimaryId() string {
+	return FeCalendarMatterCols.FeCalendarMatterId
+}
+
+func (m *FeCalendarMatter) Create() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.FeCalendarMatterId = int(id)
+	return
+}
+
+func (m *FeCalendarMatter) CreateMulti(items []*FeCalendarMatter) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *FeCalendarMatter) Update(cols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *FeCalendarMatter) Del() (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.FeCalendarMatterId).Exec()
+	return
+}
+
+func (m *FeCalendarMatter) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *FeCalendarMatter) GetItemById(id int) (item *FeCalendarMatter, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *FeCalendarMatter) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *FeCalendarMatter, err error) {
+	o := orm.NewOrmUsingDB("data")
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *FeCalendarMatter) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *FeCalendarMatter) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*FeCalendarMatter, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, FeCalendarMatterCols.CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *FeCalendarMatter) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*FeCalendarMatter, err error) {
+	o := orm.NewOrmUsingDB("data")
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := fmt.Sprintf(`ORDER BY %s DESC`, FeCalendarMatterCols.CreateTime)
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
+}
+
+type FeCalendarMatterItem struct {
+	FeCalendarMatterId  int    `description:"事项ID"`
+	ChartPermissionId   int    `description:"品种ID"`
+	ChartPermissionName string `description:"品种名称"`
+	MatterDate          string `description:"事项日期"`
+	Title               string `description:"标题"`
+	MatterType          int    `description:"事项类型:1-自定义事项;2-基础指标;3-预测指标"`
+	EdbInfoId           int    `description:"指标ID"`
+	EdbUniqueCode       string `description:"指标唯一编码"`
+	EdbCode             string `description:"指标编码"`
+	FontColor           string `description:"字体颜色"`
+	FillingColor        string `description:"填充颜色"`
+	FontBold            int    `description:"字体加粗:0-否;1-是"`
+	Sort                int    `description:"排序"`
+}
+
+func FormatFeCalendarMatter2Item(origin *FeCalendarMatter) (item *FeCalendarMatterItem) {
+	if origin == nil {
+		return
+	}
+	item = new(FeCalendarMatterItem)
+	item.FeCalendarMatterId = origin.FeCalendarMatterId
+	item.ChartPermissionId = origin.ChartPermissionId
+	item.ChartPermissionName = origin.ChartPermissionName
+	item.MatterDate = utils.TimeTransferString(utils.FormatDate, origin.MatterDate)
+	item.Title = origin.Title
+	item.MatterType = origin.MatterType
+	item.EdbInfoId = origin.EdbInfoId
+	item.EdbUniqueCode = origin.EdbUniqueCode
+	item.EdbCode = origin.EdbCode
+	item.FontColor = origin.FontColor
+	item.FillingColor = origin.FillingColor
+	item.FontBold = origin.FontBold
+	item.Sort = origin.Sort
+	return
+}
+
+// FeCalendarMatterListReq 事项列表请求体
+type FeCalendarMatterListReq struct {
+	ChartPermissionId int    `form:"ChartPermissionId" description:"品种ID"`
+	StartDate         string `form:"StartDate" description:"开始日期"`
+	EndDate           string `form:"EndDate" description:"结束日期"`
+}
+
+// FeCalendarMatterListItem 事项列表
+type FeCalendarMatterListItem struct {
+	Date    string                  `description:"日期"`
+	Matters []*FeCalendarMatterItem `description:"日期事项"`
+}
+
+// FeCalendarMatterSaveReq 保存事项请求体
+type FeCalendarMatterSaveReq struct {
+	ChartPermissionId int                         `description:"品种ID"`
+	MatterDate        string                      `description:"日期"`
+	Matters           []*FeCalendarMatterSaveItem `description:"事项"`
+}
+
+type FeCalendarMatterSaveItem struct {
+	FeCalendarMatterId int    `description:"事项ID"`
+	Title              string `description:"标题"`
+	MatterType         int    `description:"事项类型:1-自定义事项;2-基础指标;3-预测指标"`
+	EdbInfoId          int    `description:"指标ID"`
+	EdbUniqueCode      string `description:"指标唯一编码"`
+	EdbCode            string `description:"指标编码"`
+	FontColor          string `description:"字体颜色"`
+	FillingColor       string `description:"填充颜色"`
+	FontBold           int    `description:"字体加粗:0-否;1-是"`
+	Sort               int    `description:"排序"`
+}
+
+func (m *FeCalendarMatter) Save(addMatters, editMatters, removeMatters []*FeCalendarMatter, updateCols []string) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	tx, e := o.Begin()
+	if e != nil {
+		err = fmt.Errorf("begin tx err: %s", e.Error())
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+			return
+		}
+		_ = tx.Commit()
+	}()
+
+	if len(addMatters) > 0 {
+		_, e = tx.InsertMulti(len(addMatters), addMatters)
+		if e != nil {
+			err = fmt.Errorf("insert multi err: %s", e.Error())
+			return
+		}
+	}
+	if len(editMatters) > 0 {
+		for _, v := range editMatters {
+			_, e = tx.Update(v, updateCols...)
+			if e != nil {
+				err = fmt.Errorf("update err: %s", e.Error())
+				return
+			}
+		}
+	}
+	if len(removeMatters) > 0 {
+		p, e := tx.Raw(fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())).Prepare()
+		if e != nil {
+			err = fmt.Errorf("remove prepare err: %s", e.Error())
+			return
+		}
+		defer func() {
+			_ = p.Close()
+		}()
+		for _, v := range removeMatters {
+			_, e = p.Exec(v.FeCalendarMatterId)
+			if e != nil {
+				err = fmt.Errorf("remove exec err: %s", e.Error())
+				return
+			}
+		}
+	}
+	return
+}

+ 72 - 0
routers/commentsRouter.go

@@ -1915,6 +1915,42 @@ func init() {
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})
 
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"],
+        beego.ControllerComments{
+            Method: "AddCheck",
+            Router: `/bloomberg_source/add_check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"],
+        beego.ControllerComments{
+            Method: "BatchAdd",
+            Router: `/bloomberg_source/batch_add`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/bloomberg_source/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:BloombergDataController"],
+        beego.ControllerComments{
+            Method: "NameCheck",
+            Router: `/bloomberg_source/name_check`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartClassifyController"],
         beego.ControllerComments{
         beego.ControllerComments{
             Method: "AddChartClassify",
             Method: "AddChartClassify",
@@ -5479,6 +5515,42 @@ func init() {
             Filters: nil,
             Filters: nil,
             Params: nil})
             Params: nil})
 
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"],
+        beego.ControllerComments{
+            Method: "Detail",
+            Router: `/matter/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"],
+        beego.ControllerComments{
+            Method: "List",
+            Router: `/matter/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"],
+        beego.ControllerComments{
+            Method: "Save",
+            Router: `/matter/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/fe_calendar:FeCalendarMatterController"],
+        beego.ControllerComments{
+            Method: "PermissionList",
+            Router: `/permission/list`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"],
     beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/report_approve:ReportApproveController"],
         beego.ControllerComments{
         beego.ControllerComments{
             Method: "Approve",
             Method: "Approve",

+ 7 - 0
routers/router.go

@@ -23,6 +23,7 @@ import (
 	"eta/eta_api/controllers/data_stat"
 	"eta/eta_api/controllers/data_stat"
 	"eta/eta_api/controllers/english_report"
 	"eta/eta_api/controllers/english_report"
 	"eta/eta_api/controllers/eta_trial"
 	"eta/eta_api/controllers/eta_trial"
+	"eta/eta_api/controllers/fe_calendar"
 	"eta/eta_api/controllers/report_approve"
 	"eta/eta_api/controllers/report_approve"
 	"eta/eta_api/controllers/roadshow"
 	"eta/eta_api/controllers/roadshow"
 	"eta/eta_api/controllers/sandbox"
 	"eta/eta_api/controllers/sandbox"
@@ -167,6 +168,7 @@ func init() {
 				&data_manage.JiaYueEdbSourceController{},
 				&data_manage.JiaYueEdbSourceController{},
 				&data_manage.ChartThemeController{},
 				&data_manage.ChartThemeController{},
 				&data_manage_permission.DataMangePermissionController{},
 				&data_manage_permission.DataMangePermissionController{},
+				&data_manage.BloombergDataController{},
 			),
 			),
 		),
 		),
 		web.NSNamespace("/my_chart",
 		web.NSNamespace("/my_chart",
@@ -366,6 +368,11 @@ func init() {
 				&controllers.MessageController{},
 				&controllers.MessageController{},
 			),
 			),
 		),
 		),
+		web.NSNamespace("/fe_calendar",
+			web.NSInclude(
+				&fe_calendar.FeCalendarMatterController{},
+			),
+		),
 	)
 	)
 	web.AddNamespace(ns)
 	web.AddNamespace(ns)
 }
 }

+ 6 - 3
services/aiser/ai.go

@@ -11,12 +11,13 @@ import (
 	"time"
 	"time"
 )
 )
 
 
-func ChatAutoMsg(prompt string, historyChatList []aimod.HistoryChat) (result string, err error) {
+func ChatAutoMsg(prompt string, historyChatList []aimod.HistoryChat, model string) (result string, err error) {
 	chatUrl := utils.EtaAiUrl + `chat/auto_msg`
 	chatUrl := utils.EtaAiUrl + `chat/auto_msg`
 
 
 	param := make(map[string]interface{})
 	param := make(map[string]interface{})
 	param["Prompt"] = prompt
 	param["Prompt"] = prompt
 	param["HistoryChatList"] = historyChatList
 	param["HistoryChatList"] = historyChatList
+	param["model"] = model
 
 
 	postData, err := json.Marshal(param)
 	postData, err := json.Marshal(param)
 
 
@@ -66,12 +67,13 @@ func ChatAutoMsg(prompt string, historyChatList []aimod.HistoryChat) (result str
 	return result, nil
 	return result, nil
 }
 }
 
 
-func OpenAiFileUpload(fileUrl, fileName string) (result *OpenAiFileUploadResp, err error) {
+func OpenAiFileUpload(fileUrl, fileName, model string) (result *OpenAiFileUploadResp, err error) {
 	chatUrl := utils.EtaAiUrl + `chat/file/upload`
 	chatUrl := utils.EtaAiUrl + `chat/file/upload`
 
 
 	param := make(map[string]interface{})
 	param := make(map[string]interface{})
 	param["FileUrl"] = fileUrl
 	param["FileUrl"] = fileUrl
 	param["FileName"] = fileName
 	param["FileName"] = fileName
+	param["Model"] = model
 
 
 	postData, err := json.Marshal(param)
 	postData, err := json.Marshal(param)
 	if err != nil {
 	if err != nil {
@@ -116,7 +118,7 @@ func OpenAiFileUpload(fileUrl, fileName string) (result *OpenAiFileUploadResp, e
 	return resp, nil
 	return resp, nil
 }
 }
 
 
-func FileRetrieve(assistantId, threadId string, historyChatList []aimod.HistoryChat, OpenaiFileId []string) (result *OpenAiFileRetrieveResp, err error) {
+func FileRetrieve(assistantId, threadId, model string, historyChatList []aimod.HistoryChat, OpenaiFileId []string) (result *OpenAiFileRetrieveResp, err error) {
 	chatUrl := utils.EtaAiUrl + `chat/file/retrieve`
 	chatUrl := utils.EtaAiUrl + `chat/file/retrieve`
 
 
 	param := make(map[string]interface{})
 	param := make(map[string]interface{})
@@ -124,6 +126,7 @@ func FileRetrieve(assistantId, threadId string, historyChatList []aimod.HistoryC
 	param["OpenaiFileId"] = OpenaiFileId
 	param["OpenaiFileId"] = OpenaiFileId
 	param["AssistantId"] = assistantId
 	param["AssistantId"] = assistantId
 	param["ThreadId"] = threadId
 	param["ThreadId"] = threadId
+	param["Model"] = model
 
 
 	postData, err := json.Marshal(param)
 	postData, err := json.Marshal(param)
 	if err != nil {
 	if err != nil {

+ 100 - 0
services/data/base_from_bloomberg.go

@@ -0,0 +1,100 @@
+package data
+
+import (
+	"eta/eta_api/models/data_manage"
+	"eta/eta_api/utils"
+	"fmt"
+)
+
+type BloombergIndexSource2EdbReq struct {
+	EdbCode       string
+	EdbName       string
+	Frequency     string
+	Unit          string
+	ClassifyId    int
+	AdminId       int
+	AdminRealName string
+}
+
+// BloombergIndexSource2Edb 新增彭博数据源到指标库
+func BloombergIndexSource2Edb(req BloombergIndexSource2EdbReq, lang string) (edb *data_manage.EdbInfo, err error, errMsg string, skip bool) {
+	if req.EdbCode == "" {
+		err = fmt.Errorf("指标ID为空")
+		return
+	}
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("BloombergIndexSource2Edb新增失败, Err: %s", err.Error())
+			fmt.Println(tips)
+			utils.FileLog.Info(tips)
+		}
+	}()
+	source := utils.DATA_SOURCE_BLOOMBERG
+
+	// 是否已有指标数据
+	dataList, e := data_manage.GetEdbDataAllByEdbCode(req.EdbCode, source, utils.DATA_SUB_SOURCE_EDB, utils.EDB_DATA_LIMIT)
+	if e != nil {
+		err = fmt.Errorf("获取指标数据失败, Err: %s", e.Error())
+		return
+	}
+
+	// 新增指标数据
+	if len(dataList) == 0 {
+		res, e := AddEdbData(source, req.EdbCode, req.Frequency)
+		if e != nil {
+			err = fmt.Errorf("index_lib: 新增指标数据失败, Err: %s", e.Error())
+			return
+		}
+		if res == nil {
+			err = fmt.Errorf("index_lib: 新增指标数据失败, res nil")
+			return
+		}
+		if res.Ret != 200 {
+			err = fmt.Errorf("index_lib: 新增指标数据失败, Ret: %d", res.Ret)
+			return
+		}
+	}
+
+	// 是否新增过指标
+	exist, e := data_manage.GetEdbInfoByEdbCode(source, req.EdbCode)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("获取指标是否存在失败, err: %s", e.Error())
+		return
+	}
+	if exist != nil {
+		skip = true
+		return
+	}
+
+	// 开始结束时间
+	var startDate, endDate string
+	minMax, e := data_manage.GetEdbInfoMaxAndMinInfo(source, utils.DATA_SUB_SOURCE_EDB, req.EdbCode)
+	if e != nil && e.Error() != utils.ErrNoRow() {
+		err = fmt.Errorf("MinMax: 获取指标极值失败, err: %s", e.Error())
+		return
+	}
+	if minMax != nil {
+		startDate = minMax.MinDate
+		endDate = minMax.MaxDate
+	}
+
+	// 新增指标库
+	edbInfo, e, msg, _ := EdbInfoAdd(source, utils.DATA_SUB_SOURCE_EDB, req.ClassifyId, req.EdbCode, req.EdbName, req.Frequency, req.Unit, startDate, endDate, req.AdminId, req.AdminRealName, lang)
+	if e != nil {
+		errMsg = msg
+		err = fmt.Errorf("EdbInfo: 新增指标失败, err: %s", e.Error())
+		return
+	}
+	edb = edbInfo
+
+	// 标记原始指标为已添加
+	indexOb := new(data_manage.BaseFromBloombergIndex)
+	if e = indexOb.UpdateEdbExist(req.EdbCode); e != nil {
+		err = fmt.Errorf("BaseIndex: 标记已添加指标库失败, err: %s", e.Error())
+		return
+	}
+
+	// 新增es
+	go AddOrEditEdbInfoToEs(edbInfo.EdbInfoId)
+	return
+}

+ 112 - 0
services/data/cross_variety/chart.go

@@ -650,6 +650,62 @@ func AddChartInfo(req request.AddChartReq, sysUser *system.Admin, lang string) (
 		}
 		}
 	}
 	}
 
 
+	// 数据校验(品种、标签、指标)
+	{
+		// 标签m
+		var xTagInfo, yTagInfo *cross_varietyModel.ChartTag
+		{
+			tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY})
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range tagList {
+				if v.ChartTagId == req.TagX {
+					xTagInfo = v
+				} else if v.ChartTagId == req.TagY {
+					yTagInfo = v
+				}
+			}
+		}
+		if xTagInfo == nil {
+			errMsg = "找不到对应的X轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+		if yTagInfo == nil {
+			errMsg = "找不到对应的Y轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+
+		_, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList)
+		if tmpErr != nil {
+			err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(edbInfoIdList) <= 0 {
+			errMsg = "品种未配置指标"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+		if tmpErr != nil {
+			errMsg = "获取指标信息失败"
+			err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(mappingList) <= 0 {
+			errMsg = "关联指标为空"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+	}
+
 	var chartInfoId int
 	var chartInfoId int
 	// 判断图表是否存在
 	// 判断图表是否存在
 	//var condition string
 	//var condition string
@@ -849,6 +905,62 @@ func EditChartInfo(req request.EditChartReq, sysUser *system.Admin, lang string)
 		isSendEmail = false
 		isSendEmail = false
 		return
 		return
 	}
 	}
+	
+	// 数据校验(品种、标签、指标)
+	{
+		// 标签m
+		var xTagInfo, yTagInfo *cross_varietyModel.ChartTag
+		{
+			tagList, tmpErr := cross_varietyModel.GetTagListByIdList([]int{req.TagX, req.TagY})
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			for _, v := range tagList {
+				if v.ChartTagId == req.TagX {
+					xTagInfo = v
+				} else if v.ChartTagId == req.TagY {
+					yTagInfo = v
+				}
+			}
+		}
+		if xTagInfo == nil {
+			errMsg = "找不到对应的X轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+		if yTagInfo == nil {
+			errMsg = "找不到对应的Y轴标签"
+			err = errors.New(errMsg)
+			return
+		}
+
+		_, _, edbInfoIdList, tmpErr := GetXYEdbIdList(req.TagX, req.TagY, req.VarietyList)
+		if tmpErr != nil {
+			err = errors.New("获取标签配置的品种失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(edbInfoIdList) <= 0 {
+			errMsg = "品种未配置指标"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+		mappingList, tmpErr := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIdList)
+		if tmpErr != nil {
+			errMsg = "获取指标信息失败"
+			err = errors.New("获取指标信息失败,ERR:" + tmpErr.Error())
+			return
+		}
+
+		if len(mappingList) <= 0 {
+			errMsg = "关联指标为空"
+			err = errors.New(errMsg)
+			isSendEmail = false
+			return
+		}
+	}
 
 
 	//判断图表是否存在
 	//判断图表是否存在
 	//var condition string
 	//var condition string

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

@@ -257,6 +257,8 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 					Code:           v.TradeCode,
 					Code:           v.TradeCode,
 					Name:           v.SecName,
 					Name:           v.SecName,
 					ClassifyName:   v.ClassifyName,
 					ClassifyName:   v.ClassifyName,
+					NameEn:         v.SecName,
+					ClassifyNameEn: v.ClassifyName,
 					CreateUserId:   v.UserId,
 					CreateUserId:   v.UserId,
 					CreateUserName: adminMap[v.UserId],
 					CreateUserName: adminMap[v.UserId],
 				})
 				})
@@ -292,6 +294,7 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 				DataId: strconv.Itoa(v.BaseFromMysteelChemicalIndexId),
 				DataId: strconv.Itoa(v.BaseFromMysteelChemicalIndexId),
 				Code:   v.IndexCode,
 				Code:   v.IndexCode,
 				Name:   v.IndexName,
 				Name:   v.IndexName,
+				NameEn: v.IndexName,
 				//ClassifyName: v.,
 				//ClassifyName: v.,
 				CreateUserId:   v.SysUserId,
 				CreateUserId:   v.SysUserId,
 				CreateUserName: v.SysUserRealName,
 				CreateUserName: v.SysUserRealName,
@@ -299,8 +302,8 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 		}
 		}
 	case 3, 4: //ETA指标库、ETA预测指标
 	case 3, 4: //ETA指标库、ETA预测指标
 		if keyword != `` {
 		if keyword != `` {
-			condition += " AND (edb_code like ? OR edb_name like ? OR sys_user_real_name like ? ) "
-			pars = utils.GetLikeKeywordPars(pars, keyword, 3)
+			condition += " AND (edb_code like ? OR edb_name like ? OR edb_name_en like ? OR sys_user_real_name like ? ) "
+			pars = utils.GetLikeKeywordPars(pars, keyword, 4)
 		}
 		}
 		if userId > 0 {
 		if userId > 0 {
 			condition += ` AND sys_user_id = ? `
 			condition += ` AND sys_user_id = ? `
@@ -332,6 +335,7 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 				DataId: strconv.Itoa(v.EdbInfoId),
 				DataId: strconv.Itoa(v.EdbInfoId),
 				Code:   v.EdbCode,
 				Code:   v.EdbCode,
 				Name:   v.EdbName,
 				Name:   v.EdbName,
+				NameEn: v.EdbNameEn,
 				//ClassifyName: v.,
 				//ClassifyName: v.,
 				CreateUserId:   v.SysUserId,
 				CreateUserId:   v.SysUserId,
 				CreateUserName: v.SysUserRealName,
 				CreateUserName: v.SysUserRealName,
@@ -345,8 +349,8 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 
 
 		// 关键字搜索
 		// 关键字搜索
 		if keyword != `` {
 		if keyword != `` {
-			condition += " AND (chart_name like ?  OR sys_user_real_name like ? ) "
-			pars = utils.GetLikeKeywordPars(pars, keyword, 2)
+			condition += " AND (chart_name like ? or chart_name_en like ?  OR sys_user_real_name like ? ) "
+			pars = utils.GetLikeKeywordPars(pars, keyword, 3)
 		}
 		}
 		if userId > 0 {
 		if userId > 0 {
 			condition += ` AND sys_user_id = ? `
 			condition += ` AND sys_user_id = ? `
@@ -373,8 +377,10 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 			return
 			return
 		}
 		}
 		firstClassifyNameMap := make(map[int]string)
 		firstClassifyNameMap := make(map[int]string)
+		firstClassifyNameEnMap := make(map[int]string)
 		for _, v := range firstClassifyList {
 		for _, v := range firstClassifyList {
 			firstClassifyNameMap[v.ChartClassifyId] = v.ChartClassifyName
 			firstClassifyNameMap[v.ChartClassifyId] = v.ChartClassifyName
+			firstClassifyNameEnMap[v.ChartClassifyId] = v.ChartClassifyNameEn
 		}
 		}
 		secondClassList, tmpErr := data_manage.GetChartClassifyAll(1)
 		secondClassList, tmpErr := data_manage.GetChartClassifyAll(1)
 		if tmpErr != nil {
 		if tmpErr != nil {
@@ -382,12 +388,18 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 			return
 			return
 		}
 		}
 		secondClassifyNameMap := make(map[int]string)
 		secondClassifyNameMap := make(map[int]string)
+		secondClassifyNameEnMap := make(map[int]string)
 		for _, v := range secondClassList {
 		for _, v := range secondClassList {
 			firstName := firstClassifyNameMap[v.ParentId]
 			firstName := firstClassifyNameMap[v.ParentId]
+			firstNameEn := firstClassifyNameEnMap[v.ParentId]
 			if firstName != `` {
 			if firstName != `` {
 				firstName = firstName + " / "
 				firstName = firstName + " / "
 			}
 			}
+			if firstNameEn != `` {
+				firstNameEn = firstNameEn + " / "
+			}
 			secondClassifyNameMap[v.ChartClassifyId] = firstName + v.ChartClassifyName
 			secondClassifyNameMap[v.ChartClassifyId] = firstName + v.ChartClassifyName
+			secondClassifyNameEnMap[v.ChartClassifyId] = firstNameEn + v.ChartClassifyNameEn
 		}
 		}
 
 
 		for _, v := range tmpList {
 		for _, v := range tmpList {
@@ -395,6 +407,8 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 				DataId:         strconv.Itoa(v.ChartInfoId),
 				DataId:         strconv.Itoa(v.ChartInfoId),
 				Name:           v.ChartName,
 				Name:           v.ChartName,
 				ClassifyName:   secondClassifyNameMap[v.ChartClassifyId],
 				ClassifyName:   secondClassifyNameMap[v.ChartClassifyId],
+				NameEn:         v.ChartNameEn,
+				ClassifyNameEn: secondClassifyNameEnMap[v.ChartClassifyId],
 				CreateUserId:   v.SysUserId,
 				CreateUserId:   v.SysUserId,
 				CreateUserName: v.SysUserRealName,
 				CreateUserName: v.SysUserRealName,
 			})
 			})
@@ -454,6 +468,8 @@ func GetMoveEdbChartList(source, subSource, userId int, keyword, classify string
 				DataId:         strconv.Itoa(v.ExcelInfoId),
 				DataId:         strconv.Itoa(v.ExcelInfoId),
 				Name:           v.ExcelClassifyName,
 				Name:           v.ExcelClassifyName,
 				ClassifyName:   secondClassifyNameMap[v.ExcelClassifyId],
 				ClassifyName:   secondClassifyNameMap[v.ExcelClassifyId],
+				NameEn:         v.ExcelClassifyName,
+				ClassifyNameEn: secondClassifyNameMap[v.ExcelClassifyId],
 				CreateUserId:   v.SysUserId,
 				CreateUserId:   v.SysUserId,
 				CreateUserName: v.SysUserRealName,
 				CreateUserName: v.SysUserRealName,
 			})
 			})

+ 1 - 1
services/data/excel/excel_op.go

@@ -97,7 +97,7 @@ func Copy(oldExcelInfoId, excelClassifyId int, excelName string, sysUser *system
 	// 操作权限校验
 	// 操作权限校验
 	{
 	{
 		// 数据权限
 		// 数据权限
-		haveOperaAuth, tmpErr := data_manage_permission.CheckExcelPermissionByExcelInfoId(excelInfo.ExcelInfoId, excelInfo.ExcelClassifyId, excelInfo.IsJoinPermission, sysUser.AdminId)
+		haveOperaAuth, tmpErr := data_manage_permission.CheckExcelPermissionByExcelInfoId(oldExcelInfo.ExcelInfoId, oldExcelInfo.ExcelClassifyId, oldExcelInfo.IsJoinPermission, sysUser.AdminId)
 		if err != nil {
 		if err != nil {
 			errMsg = "获取ETA表格权限失败"
 			errMsg = "获取ETA表格权限失败"
 			err = errors.New("获取ETA表格权限失败,Err:" + tmpErr.Error())
 			err = errors.New("获取ETA表格权限失败,Err:" + tmpErr.Error())

+ 3 - 0
services/data/trade_analysis/trade_analysis.go

@@ -17,6 +17,7 @@ func GetClassifyName(lang string) (list trade_analysis.TradeClassifyNameListSort
 		"shanghai":  "上期所",
 		"shanghai":  "上期所",
 		"cffex":     "中金所",
 		"cffex":     "中金所",
 		"ine":       "上期能源",
 		"ine":       "上期能源",
+		"guangzhou": "广期所",
 	}
 	}
 	exchangesEn := map[string]string{
 	exchangesEn := map[string]string{
 		"郑商所":  "Zhengzhou ComEx",
 		"郑商所":  "Zhengzhou ComEx",
@@ -31,6 +32,7 @@ func GetClassifyName(lang string) (list trade_analysis.TradeClassifyNameListSort
 		"shanghai":  3,
 		"shanghai":  3,
 		"cffex":     4,
 		"cffex":     4,
 		"ine":       5,
 		"ine":       5,
+		"guangzhou": 6,
 	}
 	}
 	//查询所有交易所下的分类
 	//查询所有交易所下的分类
 	classifyExchangeList, tmpErr := trade_analysis.GetAllBaseFromTradeClassify()
 	classifyExchangeList, tmpErr := trade_analysis.GetAllBaseFromTradeClassify()
@@ -249,6 +251,7 @@ func GetPositionTopDetail(req trade_analysis.GetPositionTopReq) (ret trade_analy
 		"上期所":  "shanghai",
 		"上期所":  "shanghai",
 		"中金所":  "cffex",
 		"中金所":  "cffex",
 		"上期能源": "ine",
 		"上期能源": "ine",
+		"广期所":  "guangzhou",
 	}
 	}
 	exchange, ok := exchanges[req.Exchange]
 	exchange, ok := exchanges[req.Exchange]
 	if !ok {
 	if !ok {

+ 57 - 0
services/task.go

@@ -40,6 +40,9 @@ func Task() {
 
 
 	go AutoInsertAdminOperateRecordToDB()
 	go AutoInsertAdminOperateRecordToDB()
 
 
+	// 测试用-生成bloomberg数据
+	//go InsertBloombergIndex()
+
 	// TODO:修复权限
 	// TODO:修复权限
 	//FixEnCompanyPermission()
 	//FixEnCompanyPermission()
 	fmt.Println("task end")
 	fmt.Println("task end")
@@ -476,3 +479,57 @@ func ModifyEsEnglishReport() {
 	}
 	}
 	fmt.Println("结束")
 	fmt.Println("结束")
 }
 }
+
+//func InsertBloombergIndex() {
+//	fmt.Println("开始写入")
+//
+//	start := 100000
+//	now := time.Now()
+//	for i := 1; i <= 100; i++ {
+//		fmt.Printf("写入第%d个\n", i)
+//
+//		start += 1
+//		index := new(data_manage.BaseFromBloombergIndex)
+//		index.IndexCode = fmt.Sprintf("BLID%d", start)
+//		index.IndexName = fmt.Sprintf("模拟Bloomberg-%s", index.IndexCode)
+//		index.Unit = "无"
+//		index.Source = utils.DATA_SOURCE_BLOOMBERG
+//		index.Frequency = "日度"
+//		index.StartDate = now.AddDate(0, 0, -i)
+//		index.EndDate = now
+//		index.CreateTime = time.Now().Local()
+//		index.ModifyTime = time.Now().Local()
+//		if e := index.Create(); e != nil {
+//			fmt.Printf("新增指标失败, IndexCode: %s, err: %s", index.IndexCode, e.Error())
+//			return
+//		}
+//
+//		insertData := make([]*data_manage.BaseFromBloombergData, 0)
+//		for ii := 0; ii <= 50; ii++ {
+//			indexData := new(data_manage.BaseFromBloombergData)
+//			indexData.BaseFromBloombergIndexId = index.BaseFromBloombergIndexId
+//			indexData.IndexCode = index.IndexCode
+//			indexData.DataTime = now.AddDate(0, 0, -ii)
+//			va := GenerateRandomFloat64InRange()
+//			va += float64(ii)
+//			indexData.Value = va
+//			indexData.CreateTime = time.Now().Local()
+//			indexData.ModifyTime = time.Now().Local()
+//			indexData.DataTimestamp = int(indexData.DataTime.UnixNano() / 1e6)
+//			insertData = append(insertData, indexData)
+//		}
+//		ob := new(data_manage.BaseFromBloombergData)
+//		if e := ob.CreateMulti(insertData); e != nil {
+//			fmt.Printf("新增指标数据失败, IndexCode: %s, err: %s", index.IndexCode, e.Error())
+//			return
+//		}
+//	}
+//
+//	fmt.Println("结束写入")
+//}
+//
+//func GenerateRandomFloat64InRange() float64 {
+//	var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) // 设置随机数种子
+//
+//	return rnd.Float64()*11000 - 1000
+//}

+ 7 - 3
utils/common.go

@@ -2183,14 +2183,18 @@ func DealDateTimeZero(t time.Time, format string) (timeStr string) {
 // @return bool
 // @return bool
 // @return string
 // @return string
 func IsPercentage(input string) (bool, string) {
 func IsPercentage(input string) (bool, string) {
-	percentagePattern := `^(\d{1,2}(\.\d{1,2})?)%$`
+	percentagePattern := `^-?(\d+(\.\d+)?)%$`
 	match, _ := regexp.MatchString(percentagePattern, input)
 	match, _ := regexp.MatchString(percentagePattern, input)
 
 
 	if match {
 	if match {
-		// 提取百分比值
 		re := regexp.MustCompile(percentagePattern)
 		re := regexp.MustCompile(percentagePattern)
 		match := re.FindStringSubmatch(input)
 		match := re.FindStringSubmatch(input)
-		return true, match[1]
+		// 区分负数和正数,确保返回结果包含负号(如有)
+		sign := "-"
+		if input[0] != '-' {
+			sign = ""
+		}
+		return true, sign + match[1]
 	}
 	}
 
 
 	return false, ""
 	return false, ""

+ 1 - 0
utils/constants.go

@@ -170,6 +170,7 @@ const (
 	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
 	DATA_SOURCE_CALCULATE_RJZ                                   // 日均值计算->75
 	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->78
 	DATA_SOURCE_GFEX                                 = 78       // 广州期货交易所->78
 	DATA_SOURCE_ICPI                                 = 79       // ICPI消费价格指数->79
 	DATA_SOURCE_ICPI                                 = 79       // ICPI消费价格指数->79
+	DATA_SOURCE_BLOOMBERG                            = 83       // bloomberg彭博数据
 )
 )
 
 
 // 数据刷新频率
 // 数据刷新频率

+ 3 - 3
utils/redis/cluster_redis.go

@@ -149,12 +149,12 @@ func (rc *ClusterRedisClient) Put(key string, val interface{}, timeout time.Dura
 // @param timeout
 // @param timeout
 // @return bool
 // @return bool
 func (rc *ClusterRedisClient) SetNX(key string, val interface{}, timeout time.Duration) bool {
 func (rc *ClusterRedisClient) SetNX(key string, val interface{}, timeout time.Duration) bool {
-	result, err := rc.redisClient.SetEX(context.TODO(), key, val, timeout).Result()
-	if err != nil || result != "OK" {
+	result, err := rc.redisClient.SetNX(context.TODO(), key, val, timeout).Result()
+	if err != nil {
 		return false
 		return false
 	}
 	}
 
 
-	return true
+	return result
 }
 }
 
 
 // Delete
 // Delete

+ 3 - 3
utils/redis/standalone_redis.go

@@ -141,12 +141,12 @@ func (rc *StandaloneRedisClient) Put(key string, val interface{}, timeout time.D
 // @param timeout
 // @param timeout
 // @return bool
 // @return bool
 func (rc *StandaloneRedisClient) SetNX(key string, val interface{}, timeout time.Duration) bool {
 func (rc *StandaloneRedisClient) SetNX(key string, val interface{}, timeout time.Duration) bool {
-	result, err := rc.redisClient.SetEX(context.TODO(), key, val, timeout).Result()
-	if err != nil || result != "OK" {
+	result, err := rc.redisClient.SetNX(context.TODO(), key, val, timeout).Result()
+	if err != nil {
 		return false
 		return false
 	}
 	}
 
 
-	return true
+	return result
 }
 }
 
 
 // Delete
 // Delete