Эх сурвалжийг харах

Merge remote-tracking branch 'origin/master' into pool/xy_login

Roc 1 жил өмнө
parent
commit
8594367a23

+ 3 - 3
controllers/ai/ai.go

@@ -47,7 +47,7 @@ func (this *AiController) List() {
 		key := "CACHE_CHAT_" + strconv.Itoa(this.SysUser.AdminId)
 		cacheVal, err := utils.Rc.RedisInt(key)
 		fmt.Println("RedisString:", cacheVal, "err:", err)
-		if err != nil && err.Error() != "redigo: nil returned" {
+		if err != nil && (err.Error() != "redigo: nil returned" && err.Error() != "redis: nil") {
 			br.Msg = "获取数据失败!"
 			br.ErrMsg = "获取数据失败,Err:" + err.Error()
 			return
@@ -60,8 +60,8 @@ func (this *AiController) List() {
 		}
 
 		if putVal <= 0 {
-			br.Msg = "您今日50次问答已达上限,请明天再来!"
-			br.ErrMsg = "您今日50次问答已达上限,请明天再来!"
+			br.Msg = "您今日" + strconv.Itoa(utils.AiChatLimit) + "次问答已达上限,请明天再来!"
+			br.ErrMsg = "您今日" + strconv.Itoa(utils.AiChatLimit) + "次问答已达上限,请明天再来!"
 			return
 		}
 		lastSecond := utils.GetTodayLastSecond()

+ 435 - 0
controllers/ai/ai_file.go

@@ -0,0 +1,435 @@
+package ai
+
+import (
+	"encoding/json"
+	"eta/eta_api/controllers"
+	"eta/eta_api/models"
+	"eta/eta_api/models/aimod"
+	"eta/eta_api/services"
+	"eta/eta_api/services/aiser"
+	"eta/eta_api/utils"
+	"fmt"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type AiFileController struct {
+	controllers.BaseAuthController
+}
+
+// @Title 文件上传
+// @Description 文件上传接口
+// @Param   File   query   file  true       "文件"
+// @Param   AiChatTopicId   query   int  true       "主题id"
+// @Success 200 {object} models.ResourceResp
+// @router /file/upload [post]
+func (this *AiFileController) FileUpload() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	f, h, err := this.GetFile("File")
+	if err != nil {
+		br.Msg = "获取资源信息失败"
+		br.ErrMsg = "获取资源信息失败,Err:" + err.Error()
+		return
+	}
+
+	aiChatTopicId, _ := this.GetInt("AiChatTopicId")
+
+	uploadFileName := h.Filename //上传的文件名
+	ext := path.Ext(h.Filename)
+	dateDir := time.Now().Format("20060102")
+	uploadDir := utils.STATIC_DIR + "ai/" + dateDir
+	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
+	if err != nil {
+		br.Msg = "存储目录创建失败"
+		br.ErrMsg = "存储目录创建失败,Err:" + err.Error()
+		return
+	}
+	randStr := utils.GetRandStringNoSpecialChar(28)
+	fileName := randStr + ext
+	fpath := uploadDir + "/" + fileName
+	defer f.Close() //关闭上传文件
+	err = this.SaveToFile("File", fpath)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+	resourceUrl := ``
+	ossClient := services.NewOssClient()
+	if ossClient == nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "初始化OSS服务失败"
+		return
+	}
+	resourceUrl, err = ossClient.UploadFile(fileName, fpath, "")
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	defer func() {
+		os.Remove(fpath)
+	}()
+
+	item := new(models.Resource)
+	item.ResourceUrl = resourceUrl
+	item.ResourceType = 1
+	item.CreateTime = time.Now()
+	newId, err := models.AddResource(item)
+	if err != nil {
+		br.Msg = "资源上传失败"
+		br.ErrMsg = "资源上传失败,Err:" + err.Error()
+		return
+	}
+	//调用AI接口,上传文件
+	resp := models.ResourceResp{
+		Id:           newId,
+		ResourceUrl:  resourceUrl,
+		ResourceName: uploadFileName,
+	}
+	uploadResult, err := aiser.OpenAiFileUpload(resourceUrl, uploadFileName)
+	if err != nil {
+		br.Msg = "文件上传失败"
+		br.ErrMsg = "文件上传失败,Err:" + err.Error()
+		return
+	}
+
+	var assistantId, threadId string
+	if aiChatTopicId > 0 {
+		aiChatTopicObj := new(aimod.AiChatTopic)
+		aiChatTopicObj.AiChatTopicId = aiChatTopicId
+		topic, err := aiChatTopicObj.GetAiChatTopicById()
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "获取数据失败!"
+				br.ErrMsg = "获取数据失败,主题不存在,Err:" + err.Error()
+				return
+			}
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,GetAiChatTopicById,Err:" + err.Error()
+			return
+		}
+		assistantId = topic.AssistantId
+		threadId = topic.ThreadId
+	}
+
+	if aiChatTopicId <= 0 { //新增
+		topic := new(aimod.AiChatTopic)
+		var filenameWithSuffix string
+		filenameWithSuffix = path.Base(uploadFileName)
+		var fileSuffix string
+		fileSuffix = path.Ext(filenameWithSuffix)
+		var filenameOnly string
+		filenameOnly = strings.TrimSuffix(filenameWithSuffix, fileSuffix)
+		topic.TopicName = filenameOnly
+		topic.SysUserId = this.SysUser.AdminId
+		topic.SysUserRealName = this.SysUser.RealName
+		topic.CreateTime = time.Now()
+		topic.ModifyTime = time.Now()
+		topic.AssistantId = assistantId
+		topic.ThreadId = threadId
+		topicId, err := aimod.AddAiChatTopic(topic)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题失败,Err:" + err.Error()
+			return
+		}
+		aiChatTopicId = int(topicId)
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = aiChatTopicId
+		chatItem.Ask = uploadFileName
+		chatItem.AskUuid = utils.MD5(uploadFileName)
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		if uploadResult != nil && uploadResult.Data != nil {
+			chatItem.OpenaiFileId = uploadResult.Data.ID
+			chatItem.OpenaiFileName = uploadFileName
+		}
+		chatItem.OpenaiFilePath = resourceUrl
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+	} else {
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = aiChatTopicId
+		chatItem.Ask = uploadFileName
+		chatItem.AskUuid = utils.MD5(fileName)
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		if uploadResult != nil && uploadResult.Data != nil {
+			chatItem.OpenaiFileId = uploadResult.Data.ID
+			chatItem.OpenaiFileName = uploadFileName
+		}
+		chatItem.OpenaiFilePath = resourceUrl
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	if uploadResult != nil && uploadResult.Data != nil && uploadResult.Data.ID != "" {
+		uploadObj := new(aimod.FileUploadRecord)
+		uploadObj.AdminId = this.SysUser.AdminId
+		uploadObj.FileUrl = resourceUrl
+		uploadObj.FileName = uploadFileName
+		uploadObj.OpenaiFileId = uploadResult.Data.ID
+		uploadObj.OpenaiFileName = uploadResult.Data.FileName
+		uploadObj.OpenaiObject = uploadResult.Data.Object
+		uploadObj.OpenaiStatus = uploadResult.Data.Status
+		uploadObj.OpenaiPurpose = uploadResult.Data.Purpose
+		uploadObj.OpenaiStatusDetails = uploadResult.Data.StatusDetails
+		uploadObj.OpenaiCreatedAt = uploadResult.Data.CreatedAt
+		uploadObj.CreateTime = time.Now()
+		uploadObj.ModifyTime = time.Now()
+		_, err = uploadObj.AddFileUploadRecord()
+		if err != nil {
+			br.Msg = "上传失败"
+			br.ErrMsg = "上传失败,Err:" + err.Error()
+			return
+		}
+		resp.OpenaiFileId = uploadObj.OpenaiFileId
+	}
+	resp.AiChatTopicId = aiChatTopicId
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Success = true
+	br.Data = resp
+	return
+}
+
+// @Title 文件检索
+// @Description 文件检索接口
+// @Param	request	body aimod.FileRetrieveReq true "type json string"
+// @Success 200 {object} models.ResourceResp
+// @router /file/retrieve [post]
+func (this *AiFileController) FileRetrieve() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	var req aimod.FileRetrieveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	if req.Ask == "" {
+		br.Msg = "请输入提问内容!"
+		br.ErrMsg = "请输入提问内容"
+		return
+	}
+
+	if utils.Re == nil {
+		key := "CACHE_CHAT_" + strconv.Itoa(this.SysUser.AdminId)
+		cacheVal, err := utils.Rc.RedisInt(key)
+		fmt.Println("RedisString:", cacheVal, "err:", err)
+		if err != nil && (err.Error() != "redigo: nil returned" && err.Error() != "redis: nil") {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,Err:" + err.Error()
+			return
+		}
+		putVal := 0
+		if cacheVal <= 0 {
+			putVal = utils.AiChatLimit
+		} else {
+			putVal = cacheVal - 1
+		}
+
+		if putVal <= 0 {
+			br.Msg = "您今日" + strconv.Itoa(utils.AiChatLimit) + "次问答已达上限,请明天再来!"
+			br.ErrMsg = "您今日" + strconv.Itoa(utils.AiChatLimit) + "次问答已达上限,请明天再来!"
+			return
+		}
+		lastSecond := utils.GetTodayLastSecond()
+		utils.Rc.Put(key, putVal, lastSecond)
+	}
+
+	//根据提问,获取信息
+	askUuid := utils.MD5(req.Ask)
+	chatMode, err := aimod.GetAiChatByAsk(askUuid)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取数据失败!"
+		br.ErrMsg = "获取数据失败,GetAiChatByAsk,Err:" + err.Error()
+		return
+	}
+
+	var assistantId, threadId string
+	if req.AiChatTopicId > 0 {
+		aiChatTopicObj := new(aimod.AiChatTopic)
+		aiChatTopicObj.AiChatTopicId = req.AiChatTopicId
+		topic, err := aiChatTopicObj.GetAiChatTopicById()
+		if err != nil {
+			if err.Error() == utils.ErrNoRow() {
+				br.Msg = "获取数据失败!"
+				br.ErrMsg = "获取数据失败,主题不存在,Err:" + err.Error()
+				return
+			}
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,GetAiChatTopicById,Err:" + err.Error()
+			return
+		}
+		assistantId = topic.AssistantId
+		threadId = topic.ThreadId
+	}
+
+	resp := new(aimod.ChatResp)
+	var answer string
+	if chatMode != nil && chatMode.Answer != "" {
+		answer = chatMode.Answer
+	} else {
+		//获取主题下的所有信息
+		//AiChatTopicId
+		historyList, err := aimod.GetAiChatList(req.AiChatTopicId)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取主题历史数据失败!"
+			br.ErrMsg = "获取主题历史数据失败,Err:" + err.Error()
+			return
+		}
+
+		frList := make([]aimod.HistoryChat, 0)
+		tmpFileIdList := make([]string, 0)
+
+		// 历史消息
+		for _, v := range historyList {
+			if v.OpenaiFileId != "" {
+				tmpFileIdList = append(tmpFileIdList, v.OpenaiFileId)
+			} else {
+				historyFr := new(aimod.HistoryChat)
+				historyFr.Ask = v.Ask
+				historyFr.Answer = v.Answer
+				historyFr.OpenaiFileId = tmpFileIdList
+				frList = append(frList, *historyFr)
+				tmpFileIdList = []string{}
+			}
+		}
+		// 当前的消息
+		{
+			frItem := new(aimod.HistoryChat)
+			frItem.Ask = req.Ask
+			frItem.Answer = ""
+			frItem.OpenaiFileId = tmpFileIdList
+			frList = append(frList, *frItem)
+		}
+
+		//var assistantId,threadId string
+		fileRetrieveResp, err := aiser.FileRetrieve(assistantId, threadId, frList, req.OpenaiFileId)
+		//fileRetrieveResp, err := aiser.FileRetrieve(assistantId, threadId, frList, []string{})
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "获取数据失败,FileRetrieve,Err:" + err.Error()
+			return
+		}
+
+		if fileRetrieveResp != nil {
+			if fileRetrieveResp.Ret == 200 {
+				assistantId = fileRetrieveResp.Data.AssistantId
+				threadId = fileRetrieveResp.Data.ThreadId
+				answer = fileRetrieveResp.Data.Answer
+			} else {
+				br.Msg = "获取数据失败!"
+				br.ErrMsg = fileRetrieveResp.Msg
+				return
+			}
+		}
+	}
+
+	if req.AiChatTopicId <= 0 { //新增
+		topic := new(aimod.AiChatTopic)
+		topic.TopicName = req.Ask
+		topic.SysUserId = this.SysUser.AdminId
+		topic.SysUserRealName = this.SysUser.RealName
+		topic.CreateTime = time.Now()
+		topic.ModifyTime = time.Now()
+		topic.AssistantId = assistantId
+		topic.ThreadId = threadId
+		topicId, err := aimod.AddAiChatTopic(topic)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题失败,Err:" + err.Error()
+			return
+		}
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = int(topicId)
+		chatItem.Ask = req.Ask
+		chatItem.AskUuid = utils.MD5(req.Ask)
+		chatItem.Answer = answer
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+		req.AiChatTopicId = int(topicId)
+	} else {
+		chatItem := new(aimod.AiChat)
+		chatItem.AiChatTopicId = req.AiChatTopicId
+		chatItem.Ask = req.Ask
+		chatItem.AskUuid = utils.MD5(req.Ask)
+		chatItem.Answer = answer
+		chatItem.Model = "gpt-4-1106-preview"
+		chatItem.SysUserId = this.SysUser.AdminId
+		chatItem.SysUserRealName = this.SysUser.RealName
+		chatItem.CreateTime = time.Now()
+		chatItem.ModifyTime = time.Now()
+		_, err = aimod.AddAiChat(chatItem)
+		if err != nil {
+			br.Msg = "获取数据失败!"
+			br.ErrMsg = "生成话题记录失败,Err:" + err.Error()
+			return
+		}
+		//更新	assistantId,threadId
+		aiChatTopicObj := new(aimod.AiChatTopic)
+
+		updateParams := make(map[string]interface{})
+		updateParams["assistant_id"] = assistantId
+		updateParams["thread_id"] = threadId
+		updateParams["modify_time"] = time.Now()
+
+		whereParam := make(map[string]interface{})
+		whereParam["ai_chat_topic_id"] = req.AiChatTopicId
+
+		err = aiChatTopicObj.Update(updateParams, whereParam)
+		if err != nil {
+			br.Msg = "获取失败!"
+			br.ErrMsg = "修改助手标识失败,Err:" + err.Error()
+			return
+		}
+	}
+
+	resp.AiChatTopicId = req.AiChatTopicId
+	resp.Ask = req.Ask
+	resp.Answer = answer
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+	return
+}

+ 1 - 1
controllers/cloud_disk.go

@@ -580,7 +580,7 @@ func (this *CloudDiskController) ResourceUpload() {
 		_ = os.Remove(filePath)
 	}()
 	// 上传到阿里云
-	ossDir := "static/cloud_disk/"
+	ossDir := utils.RESOURCE_DIR + "cloud_disk/"
 
 	resourceUrl := ``
 	//上传到阿里云 和 minio

+ 7 - 2
controllers/data_manage/edb_classify.go

@@ -873,7 +873,12 @@ func (this *EdbClassifyController) SimpleList() {
 	// 如果是 子级分类,查询该子级分类的下一级分类和指标信息
 	// 增加标识判断是文件夹还是指标列表
 	parentId, _ := this.GetInt("ParentId")
-
+	isOnlyMe, _ := this.GetBool("IsOnlyMe")
+	// 如果选择了只看我的,那么只查询归属于我的账号
+	sysUserId := 0
+	if isOnlyMe {
+		sysUserId = this.SysUser.AdminId
+	}
 	rootList, err := data_manage.GetEdbClassifyByParentId(parentId, 0)
 	if err != nil && err.Error() != utils.ErrNoRow() {
 		br.Msg = "获取失败"
@@ -897,7 +902,7 @@ func (this *EdbClassifyController) SimpleList() {
 		for _, v := range confList {
 			noPermissionEdbInfoIdMap[v.EdbInfoId] = true
 		}
-		allEdbInfo, err := data_manage.GetEdbInfoByClassifyId(parentId, 0, 0)
+		allEdbInfo, err := data_manage.GetEdbInfoByClassifyId(parentId, 0, sysUserId)
 		if err != nil {
 			br.Msg = "获取指标数据失败"
 			br.ErrMsg = "获取指标数据失败,Err:" + err.Error()

+ 548 - 160
controllers/data_manage/edb_info_calculate.go

@@ -8,6 +8,7 @@ import (
 	"eta/eta_api/services/data"
 	"eta/eta_api/utils"
 	"fmt"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"net/url"
 	"strconv"
 	"strings"
@@ -163,6 +164,7 @@ func (this *ChartInfoController) CalculateSave() {
 		EdbInfoIdArr:     req.EdbInfoIdArr,
 		EmptyType:        req.EmptyType,
 		MaxEmptyType:     req.MaxEmptyType,
+		Extra:            req.Extra,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {
@@ -434,6 +436,7 @@ func (this *ChartInfoController) CalculateEdit() {
 		EdbInfoIdArr:     req.EdbInfoIdArr,
 		EmptyType:        req.EmptyType,
 		MaxEmptyType:     req.MaxEmptyType,
+		Extra:            req.Extra,
 	}
 	reqJson, err := json.Marshal(req2)
 	if err != nil {
@@ -626,6 +629,7 @@ func (this *ChartInfoController) CalculateBatchSave() {
 		//CalculateFormula: edbInfo.CalculateFormula,
 		EdbInfoIdArr: req.EdbInfoIdArr,
 		Calendar:     req.Calendar,
+		Extra:        req.Extra,
 	}
 
 	// 调用指标库去更新
@@ -832,6 +836,7 @@ func (this *ChartInfoController) CalculateBatchEdit() {
 		MoveFrequency: req.MoveFrequency,
 		EdbInfoIdArr:  req.EdbInfoIdArr,
 		Calendar:      req.Calendar,
+		Extra:         req.Extra,
 	}
 
 	// 调用指标库去更新
@@ -1583,8 +1588,8 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 		return
 	}
 
-	var reqList []data_manage.BatchEdbInfoCalculateBatchSaveReq
-	err := json.Unmarshal(this.Ctx.Input.RequestBody, &reqList)
+	var req data_manage.BatchEdbInfoCalculateBatchSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
 	if err != nil {
 		br.Msg = "参数解析异常!"
 		br.ErrMsg = "参数解析失败,Err:" + err.Error()
@@ -1595,17 +1600,83 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 		Fail:    make([]data_manage.BatchEdbInfoCalculateBatchSaveFailResp, 0),
 		Success: make([]data_manage.BatchEdbInfoCalculateBatchSaveSuccessResp, 0),
 	}
-	redisKeyList := make([]string, 0) //需要清理的缓存key列表
-	defer func() {
-		for _, redisKey := range redisKeyList {
-			utils.Rc.Delete(redisKey)
+
+	var formulaInt int
+	switch req.Source {
+	case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_CALCULATE_HBZ, utils.DATA_SOURCE_CALCULATE_HCZ, utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_CALCULATE_CJJX:
+		if req.Formula == "" {
+			br.Msg = "请输入N值"
+			return
 		}
-	}()
+		formulaInt, _ = strconv.Atoi(req.Formula)
+		if formulaInt <= 0 {
+			br.Msg = "N值输入错误,请重新输入"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZJPJ:
+		//直接拼接指标
+		//校验时间格式
+		_, err = time.ParseInLocation(utils.FormatDate, req.Formula, time.Local)
+		if err != nil {
+			br.Msg = "拼接日期有误,请重新输入"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_NHCC: //拟合残差指标
+		//指标校验
+		if len(req.EdbInfoIdArr) != 2 {
+			br.Msg = "选择的指标异常,请重新选择"
+			return
+		}
+		fromEdbInfoId := req.EdbInfoIdArr[0].EdbInfoId
+		if fromEdbInfoId <= 0 {
+			br.Msg = "请选择指标"
+			return
+		}
+		//校验时间格式
+		//数据格式:2022-11-01,2022-11-10
+		timeList := strings.Split(req.Formula, ",")
+		if len(timeList) != 2 {
+			br.Msg = "选择的指标异常,请重新选择"
+			return
+		}
+		startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+		if err != nil {
+			br.Msg = "开始日期有误,请重新输入"
+			return
+		}
+		endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+		if err != nil {
+			br.Msg = "结束日期有误,请重新输入"
+			return
+		}
+		if utils.GetTimeSubDay(startDate, endDate) < 2 {
+			br.Msg = "日期间隔不得少于两天"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZSXY: // 指数修匀
+		if req.Formula == "" {
+			br.Msg = "请填写alpha值"
+			return
+		}
+		alpha, e := strconv.ParseFloat(req.Formula, 64)
+		if e != nil {
+			br.Msg = "alpha值输入错误, 请重新输入"
+			return
+		}
+		if alpha <= 0 || alpha >= 1 {
+			br.Msg = "alpha值输入错误, 请重新输入"
+			return
+		}
+	}
 
-	for _, v := range reqList {
-		req := v.CalculateInfo
-		req.EdbName = strings.Trim(req.EdbName, " ")
-		if req.EdbName == "" {
+	if len(req.EdbList) > 100 {
+		br.Msg = "最多只能选择100个指标"
+		return
+	}
+	reqEdbList := make([]*data_manage.CalculateEdbInfoItem, 0)
+	for _, v := range req.EdbList {
+		v.EdbName = strings.Trim(v.EdbName, " ")
+		if v.EdbName == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
 				Msg:         "指标名称不能为空",
@@ -1613,7 +1684,7 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 			continue
 		}
 
-		if req.Frequency == "" {
+		if v.Frequency == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
 				Msg:         "频率不能为空",
@@ -1621,7 +1692,7 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 			continue
 		}
 
-		if req.Unit == "" {
+		if v.Unit == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
 				Msg:         "单位不能为空",
@@ -1629,7 +1700,7 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 			continue
 		}
 
-		if req.ClassifyId <= 0 {
+		if v.ClassifyId <= 0 {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
 				Msg:         "请选择分类",
@@ -1637,185 +1708,247 @@ func (this *ChartInfoController) BatchCalculateBatchSave() {
 			continue
 		}
 
-		fromEdbInfoId := req.FromEdbInfoId
+		//加入缓存机制,避免创建同一个名称的指标 start
+		redisKey := fmt.Sprint("edb_info:calculate:batch:save:", req.Source, ":", v.EdbName)
+		isExist := utils.Rc.IsExist(redisKey)
+		if isExist {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: v.CalculateId,
+				Msg:         "指标正在处理,请勿重复提交",
+			})
+			continue
+		} else {
+			//设置3分钟缓存
+			//utils.Rc.SetNX(redisKey, 1, time.Second*300)
+			//redisKeyList = append(redisKeyList, redisKey)
+		}
+		reqEdbList = append(reqEdbList, v)
+	}
 
-		var formulaInt int
-		switch req.Source {
-		case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_CALCULATE_HBZ, utils.DATA_SOURCE_CALCULATE_HCZ, utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_CALCULATE_CJJX:
-			if req.Formula == "" {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "请选择分类",
-				})
-				continue
-			}
-			formulaInt, _ = strconv.Atoi(req.Formula)
-			if formulaInt <= 0 {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "N值输入错误,请重新输入",
-				})
-				continue
-			}
-		case utils.DATA_SOURCE_CALCULATE_ZJPJ:
-			//直接拼接指标
-			//校验时间格式
-			_, err = time.ParseInLocation(utils.FormatDate, req.Formula, time.Local)
-			if err != nil {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "拼接日期有误,请重新输入",
-				})
-				continue
-			}
-		case utils.DATA_SOURCE_CALCULATE_NHCC: //拟合残差指标
-			//指标校验
-			if len(req.EdbInfoIdArr) != 2 {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "选择的指标异常,请重新选择",
-				})
-				continue
-			}
-			fromEdbInfoId = req.EdbInfoIdArr[0].EdbInfoId
-
-			//校验时间格式
-			//数据格式:2022-11-01,2022-11-10
-			timeList := strings.Split(req.Formula, ",")
-			if len(timeList) != 2 {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "选择时间有误,请重新输入",
-				})
-				continue
-			}
-			startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
-			if err != nil {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "开始日期有误,请重新输入",
-				})
-				continue
-			}
-			endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
-			if err != nil {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "结束日期有误,请重新输入",
-				})
-				continue
-			}
-			if utils.GetTimeSubDay(startDate, endDate) < 2 {
-				resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
-					CalculateId: v.CalculateId,
-					Msg:         "日期间隔不得少于两天",
-				})
-				continue
-			}
-		case utils.DATA_SOURCE_CALCULATE_ZSXY: // 指数修匀
-			if req.Formula == "" {
-				br.Msg = "请填写alpha值"
-				return
-			}
-			alpha, e := strconv.ParseFloat(req.Formula, 64)
-			if e != nil {
-				br.Msg = "alpha值输入错误, 请重新输入"
-				return
-			}
-			if alpha <= 0 || alpha >= 1 {
-				br.Msg = "alpha值输入错误, 请重新输入"
-				return
-			}
+	if len(reqEdbList) <= 0 {
+		br.Msg = "新增失败!"
+		if len(resp.Fail) > 0 {
+			br.ErrMsg = resp.Fail[0].Msg
+		} else {
+			br.Msg = "请选择指标"
+		}
+		return
+	}
+	req.AdminId = sysUser.AdminId
+	req.AdminName = sysUser.RealName
+	req.EdbList = reqEdbList
+	// 调用指标库去更新
+	reqJson, err := json.Marshal(req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	respItem, err := data.BatchSaveEdbCalculateMultiData(string(reqJson))
+	if err != nil {
+		br.Msg = "新增失败!"
+		br.ErrMsg = "新增失败,Err:" + err.Error()
+		return
+	}
+	if respItem.Ret != 200 {
+		br.Msg = respItem.Msg
+		br.ErrMsg = respItem.ErrMsg
+		return
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "批量保存成功"
+	br.Data = respItem.Data
+	br.IsAddLog = true
+}
+
+// BatchCalculateBatchEdit
+// @Title 多指标求和和多指标求平均编辑接口
+// @Description 多指标求和和多指标求平均编辑接口
+// @Param	request	body data_manage.EdbInfoCalculateBatchSaveReq true "type json string"
+// @Success Ret=200 返回指标id
+// @router /edb_info/calculate/batch/edit/batch [post]
+func (this *ChartInfoController) BatchCalculateBatchEdit() {
+	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.BatchEdbInfoCalculateBatchSaveReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+
+	resp := data_manage.BatchEdbInfoCalculateBatchSaveResp{
+		Fail:    make([]data_manage.BatchEdbInfoCalculateBatchSaveFailResp, 0),
+		Success: make([]data_manage.BatchEdbInfoCalculateBatchSaveSuccessResp, 0),
+	}
 
+	var formulaInt int
+	switch req.Source {
+	case utils.DATA_SOURCE_CALCULATE_NSZYDPJJS, utils.DATA_SOURCE_CALCULATE_HBZ, utils.DATA_SOURCE_CALCULATE_HCZ, utils.DATA_SOURCE_CALCULATE_TIME_SHIFT, utils.DATA_SOURCE_CALCULATE_CJJX:
+		if req.Formula == "" {
+			br.Msg = "请输入N值"
+			return
+		}
+		formulaInt, _ = strconv.Atoi(req.Formula)
+		if formulaInt <= 0 {
+			br.Msg = "N值输入错误,请重新输入"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZJPJ:
+		//直接拼接指标
+		//校验时间格式
+		_, err = time.ParseInLocation(utils.FormatDate, req.Formula, time.Local)
+		if err != nil {
+			br.Msg = "拼接日期有误,请重新输入"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_NHCC: //拟合残差指标
+		//指标校验
+		if len(req.EdbInfoIdArr) != 2 {
+			br.Msg = "选择的指标异常,请重新选择"
+			return
+		}
+		fromEdbInfoId := req.EdbInfoIdArr[0].EdbInfoId
 		if fromEdbInfoId <= 0 {
+			br.Msg = "请选择指标"
+			return
+		}
+		//校验时间格式
+		//数据格式:2022-11-01,2022-11-10
+		timeList := strings.Split(req.Formula, ",")
+		if len(timeList) != 2 {
+			br.Msg = "选择的指标异常,请重新选择"
+			return
+		}
+		startDate, err := time.ParseInLocation(utils.FormatDate, timeList[0], time.Local)
+		if err != nil {
+			br.Msg = "开始日期有误,请重新输入"
+			return
+		}
+		endDate, err := time.ParseInLocation(utils.FormatDate, timeList[1], time.Local)
+		if err != nil {
+			br.Msg = "结束日期有误,请重新输入"
+			return
+		}
+		if utils.GetTimeSubDay(startDate, endDate) < 2 {
+			br.Msg = "日期间隔不得少于两天"
+			return
+		}
+	case utils.DATA_SOURCE_CALCULATE_ZSXY: // 指数修匀
+		if req.Formula == "" {
+			br.Msg = "请填写alpha值"
+			return
+		}
+		alpha, e := strconv.ParseFloat(req.Formula, 64)
+		if e != nil {
+			br.Msg = "alpha值输入错误, 请重新输入"
+			return
+		}
+		if alpha <= 0 || alpha >= 1 {
+			br.Msg = "alpha值输入错误, 请重新输入"
+			return
+		}
+	}
+
+	if len(req.EdbList) > 50 {
+		br.Msg = "最多只能选择50个指标"
+		return
+	}
+	reqEdbList := make([]*data_manage.CalculateEdbInfoItem, 0)
+	for _, v := range req.EdbList {
+		if v.EdbInfoId <= 0 {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
-				Msg:         "请选择指标",
+				Msg:         "请选择要编辑的指标",
 			})
 			continue
 		}
-
-		//加入缓存机制,避免创建同一个名称的指标 start
-		redisKey := fmt.Sprint("edb_info:calculate:batch:save:", sysUser.AdminId, ":", req.Source, ":", v.CalculateId)
-		isExist := utils.Rc.IsExist(redisKey)
-		if isExist {
+		v.EdbName = strings.Trim(v.EdbName, " ")
+		if v.EdbName == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
-				Msg:         "指标正在处理,请勿重复提交",
+				Msg:         "指标名称不能为空",
 			})
 			continue
-		} else {
-			//设置3分钟缓存
-			utils.Rc.SetNX(redisKey, 1, time.Second*300)
-			redisKeyList = append(redisKeyList, redisKey)
-		}
-		//加入缓存机制,避免创建同一个名称的指标 end
-
-		req2 := &data_manage.EdbInfoCalculateBatchSaveReqByEdbLib{
-			AdminId:          sysUser.AdminId,
-			AdminName:        sysUser.RealName,
-			EdbInfoId:        req.EdbInfoId,
-			EdbName:          req.EdbName,
-			Frequency:        req.Frequency,
-			Unit:             req.Unit,
-			ClassifyId:       req.ClassifyId,
-			Formula:          req.Formula, //N数值移动平均计算、环比值、环差值
-			FromEdbInfoId:    req.FromEdbInfoId,
-			CalculateFormula: req.CalculateFormula,
-			Source:           req.Source,
-			MoveType:         req.MoveType,
-			MoveFrequency:    req.MoveFrequency,
-
-			//CalculateFormula: edbInfo.CalculateFormula,
-			EdbInfoIdArr: req.EdbInfoIdArr,
-			Calendar:     req.Calendar,
-		}
-
-		// 调用指标库去更新
-		reqJson, err := json.Marshal(req2)
-		if err != nil {
+		}
+
+		if v.Frequency == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
-				Msg:         "参数解析异常!",
-				ErrMsg:      "参数解析失败,Err:" + err.Error(),
+				Msg:         "频率不能为空",
 			})
 			continue
 		}
-		respItem, err := data.BatchSaveEdbCalculateData(string(reqJson))
-		if err != nil {
+
+		if v.Unit == "" {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
-				Msg:         "新增失败!",
-				ErrMsg:      "新增失败,Err:" + err.Error(),
+				Msg:         "单位不能为空",
 			})
 			continue
 		}
-		if respItem.Ret != 200 {
+
+		if v.ClassifyId <= 0 {
 			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
 				CalculateId: v.CalculateId,
-				Msg:         respItem.Msg,
-				ErrMsg:      respItem.ErrMsg,
+				Msg:         "请选择分类",
 			})
 			continue
 		}
 
-		result := respItem.Data
-
-		//添加es
-		data.AddOrEditEdbInfoToEs(result.EdbInfoId)
-		resp.Success = append(resp.Success, data_manage.BatchEdbInfoCalculateBatchSaveSuccessResp{
-			ClassifyId:  req.ClassifyId,
-			CalculateId: v.CalculateId,
-			EdbInfoId:   result.EdbInfoId,
-			UniqueCode:  result.UniqueCode,
-		})
+		reqEdbList = append(reqEdbList, v)
+	}
+	if len(reqEdbList) <= 0 {
+		br.Msg = "编辑失败!"
+		if len(resp.Fail) > 0 {
+			br.ErrMsg = resp.Fail[0].Msg
+		} else {
+			br.Msg = "请选择指标"
+		}
+		return
+	}
+	req.EdbList = reqEdbList
+	// 调用指标库去更新
+	reqJson, err := json.Marshal(req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	respItem, err := data.BatchEditEdbCalculateMultiData(string(reqJson))
+	if err != nil {
+		br.Msg = "编辑失败!"
+		br.ErrMsg = "编辑失败,Err:" + err.Error()
+		return
+	}
+	if respItem.Ret != 200 {
+		br.Msg = respItem.Msg
+		br.ErrMsg = respItem.ErrMsg
+		return
 	}
 
 	br.Ret = 200
 	br.Success = true
-	br.Msg = "批量保存成功"
-	br.Data = resp
+	br.Msg = "批量编辑成功"
+	br.Data = respItem.Data
 	br.IsAddLog = true
 }
 
@@ -1953,3 +2086,258 @@ func (this *ChartInfoController) CalculateComputeCorrelation() {
 	br.Msg = "计算成功"
 	br.IsAddLog = true
 }
+
+// CalculateMultiChoice
+// @Title 批量计算-加入已选指标
+// @Description 批量计算-加入已选指标
+// @Param   ClassifyIds   query   int  true       "指标库分类IDs"
+// @Param   SysUserIds   query   int  true       "创建人"
+// @Param   Keyword   query   string  false       "关键词搜索"
+// @Param   Frequency   query   string  false       "频度"
+// @Success 200 {object} data_manage.EdbInfoSearchResp
+// @router /edb_info/calculate/multi/choice [get]
+func (this *ChartInfoController) CalculateMultiChoice() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	//来源类型,1:中文,2:英文
+	frequency := this.GetString("Frequency")
+	keyword := this.GetString("Keyword")
+	sysUserIds := this.GetString("SysUserIds")
+	classifyIds := this.GetString("ClassifyIds")
+	edbInfoIds := this.GetString("EdbInfoIds")
+	selectAll, _ := this.GetBool("SelectAll")
+	notFrequency := this.GetString("NotFrequency")
+	var edbIdArr []int
+
+	if selectAll {
+		// 如果勾了列表全选,那么EdbCode传的就是排除的code
+
+		var condition string
+		var pars []interface{}
+
+		if classifyIds != "" {
+			classifyIdsArr := strings.Split(classifyIds, ",")
+			condition += ` AND classify_id IN (` + utils.GetOrmInReplace(len(classifyIdsArr)) + `) `
+			pars = append(pars, classifyIdsArr)
+		}
+
+		if frequency != "" {
+			frequencyArr := strings.Split(frequency, ",")
+			condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencyArr)) + `) `
+			pars = append(pars, frequencyArr)
+		}
+		if notFrequency != "" {
+			notFrequencyArr := strings.Split(notFrequency, ",")
+			condition += ` AND frequency NOT IN (` + utils.GetOrmInReplace(len(notFrequencyArr)) + `) `
+			pars = append(pars, notFrequencyArr)
+		}
+
+		if sysUserIds != "" {
+			sysUserIdSlice := strings.Split(sysUserIds, ",")
+			condition += ` AND sys_user_id IN (` + utils.GetOrmInReplace(len(sysUserIdSlice)) + `)`
+			pars = append(pars, sysUserIdSlice)
+		}
+
+		if keyword != "" {
+			keyWordArr := strings.Split(keyword, " ")
+
+			if len(keyWordArr) > 0 {
+				for _, v := range keyWordArr {
+					condition += ` AND CONCAT(edb_name,edb_code) LIKE ?`
+					pars = append(pars, utils.GetLikeKeyword(v))
+				}
+			}
+		}
+		edbList, e := data_manage.GetEdbInfoFilter(condition, pars)
+		if e != nil {
+			br.Msg = "获取指标列表失败"
+			br.ErrMsg = "获取指标列表失败,Err:" + e.Error()
+			return
+		}
+
+		for _, v := range edbList {
+			edbIdArr = append(edbIdArr, v.EdbInfoId)
+		}
+	} else {
+		//未勾选全选EdbCode就是需要的code
+		edbIdStrArr := strings.Split(edbInfoIds, ",")
+		for _, v := range edbIdStrArr {
+			id, e := strconv.Atoi(v)
+			if e != nil {
+				br.Msg = "获取指标列表失败"
+				br.ErrMsg = "获取指标列表失败,Err:" + e.Error()
+				return
+			}
+			edbIdArr = append(edbIdArr, id)
+		}
+	}
+
+	if len(edbIdArr) > 100 {
+		br.Msg = "最多只能选择100个指标"
+		return
+	}
+
+	if len(edbIdArr) <= 0 {
+		br.Msg = "无符合指标或指标代码错误"
+		return
+	}
+
+	list, err := data_manage.GetEdbInfoByIdList(edbIdArr)
+	if err != nil && err.Error() != utils.ErrNoRow() {
+		br.Msg = "获取指标列表失败"
+		br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+		return
+	}
+
+	searchItemList := make([]data_manage.EdbInfoBase, 0)
+
+	resp := new(data_manage.CalculateMultiChoiceResp)
+
+	for _, info := range list {
+		searchItem := data_manage.EdbInfoBase{
+			Frequency:  info.Frequency,
+			Unit:       info.Unit,
+			EdbName:    info.EdbName,
+			EdbInfoId:  info.EdbInfoId,
+			ClassifyId: info.ClassifyId,
+		}
+		searchItemList = append(searchItemList, searchItem)
+	}
+
+	resp.SearchItem = searchItemList
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// CalculateMultiSearch
+// @Title 批量计算-查询指标
+// @Description 批量计算-查询指标
+// @Param   ClassifyIds   query   int  true       "指标库分类IDs"
+// @Param   SysUserIds   query   int  true       "创建人"
+// @Param   Keyword   query   string  false       "关键词搜索"
+// @Param   Frequency   query   string  false       "频度"
+// @Success 200 {object} data_manage.EdbInfoSearchResp
+// @router /edb_info/calculate/multi/search [get]
+func (this *ChartInfoController) CalculateMultiSearch() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	//来源类型,1:中文,2:英文
+	frequency := this.GetString("Frequency")
+	keyword := this.GetString("Keyword")
+	sysUserIds := this.GetString("SysUserIds")
+	classifyIds := this.GetString("ClassifyIds")
+
+	pageSize, _ := this.GetInt("PageSize")
+	currentIndex, _ := this.GetInt("CurrentIndex")
+	notFrequency := this.GetString("NotFrequency")
+
+	var startSize int
+	if pageSize <= 0 {
+		pageSize = utils.PageSize50
+	}
+	if currentIndex <= 0 {
+		currentIndex = 1
+	}
+	startSize = utils.StartIndex(currentIndex, pageSize)
+
+	var edbIdArr []int
+
+	condition := ` AND edb_info_type = 0 `
+	var pars []interface{}
+
+	if classifyIds != "" {
+		classifyIdsArr := strings.Split(classifyIds, ",")
+		condition += ` AND classify_id IN (` + utils.GetOrmInReplace(len(classifyIdsArr)) + `) `
+		pars = append(pars, classifyIdsArr)
+	}
+
+	if frequency != "" {
+		frequencyArr := strings.Split(frequency, ",")
+		condition += ` AND frequency IN (` + utils.GetOrmInReplace(len(frequencyArr)) + `) `
+		pars = append(pars, frequencyArr)
+	}
+	if notFrequency != "" {
+		notFrequencyArr := strings.Split(notFrequency, ",")
+		condition += ` AND frequency NOT IN (` + utils.GetOrmInReplace(len(notFrequencyArr)) + `) `
+		pars = append(pars, notFrequencyArr)
+	}
+	if sysUserIds != "" {
+		sysUserIdSlice := strings.Split(sysUserIds, ",")
+		condition += ` AND sys_user_id IN (` + utils.GetOrmInReplace(len(sysUserIdSlice)) + `)`
+		pars = append(pars, sysUserIdSlice)
+	}
+
+	if keyword != "" {
+		keyWordArr := strings.Split(keyword, " ")
+
+		if len(keyWordArr) > 0 {
+			for _, v := range keyWordArr {
+				condition += ` AND CONCAT(edb_name,edb_code) LIKE ?`
+				pars = append(pars, utils.GetLikeKeyword(v))
+			}
+		}
+	}
+
+	total, e := data_manage.GetEdbInfoByConditionCount(condition, pars)
+	if e != nil {
+		br.Msg = "获取指标列表总数失败"
+		br.ErrMsg = "获取指标列表总数失败,Err:" + e.Error()
+		return
+	}
+
+	searchItemList := make([]data_manage.CalculateMultiEdbSearchItem, 0)
+	page := paging.GetPaging(currentIndex, pageSize, total)
+	resp := new(data_manage.CalculateMultiEdbSearchResp)
+
+	edbList, e := data_manage.GetEdbInfoListByCondition(condition, pars, startSize, pageSize)
+	if e != nil {
+		br.Msg = "获取指标列表失败"
+		br.ErrMsg = "获取指标列表失败,Err:" + e.Error()
+		return
+	}
+
+	for _, v := range edbList {
+		edbIdArr = append(edbIdArr, v.EdbInfoId)
+	}
+
+	if len(edbIdArr) > 0 {
+		list, err := data_manage.GetEdbInfoByIdList(edbIdArr)
+		if err != nil && err.Error() != utils.ErrNoRow() {
+			br.Msg = "获取指标列表失败"
+			br.ErrMsg = "获取指标列表失败,Err:" + err.Error()
+			return
+		}
+		for _, info := range list {
+			searchItem := data_manage.CalculateMultiEdbSearchItem{
+				Frequency:       info.Frequency,
+				Unit:            info.Unit,
+				EdbName:         info.EdbName,
+				EdbInfoId:       info.EdbInfoId,
+				ClassifyId:      info.ClassifyId,
+				SysUserRealName: info.SysUserRealName,
+				SysUserId:       info.SysUserId,
+				EndDate:         info.EndDate,
+				EndValue:        info.EndValue,
+			}
+			searchItemList = append(searchItemList, searchItem)
+		}
+	}
+
+	resp.SearchItem = searchItemList
+	resp.Paging = page
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 11 - 41
controllers/ppt_v2.go

@@ -507,17 +507,19 @@ func (this *PptV2Controller) PptUpload() {
 		br.ErrMsg = "获取PPT详情失败,Err:" + err.Error()
 		return
 	}
-
 	f, h, err := this.GetFile("file")
 	if err != nil {
 		br.Msg = "获取资源信息失败"
 		br.ErrMsg = "获取资源信息失败,Err:" + err.Error()
 		return
 	}
+	defer func() {
+		_ = f.Close()
+	}()
 	uploadFileName := h.Filename //上传的文件名
 	ext := path.Ext(h.Filename)
 	dateDir := time.Now().Format("20060102")
-	uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
+	uploadDir := utils.STATIC_DIR + "ppt/" + dateDir
 	err = os.MkdirAll(uploadDir, utils.DIR_MOD)
 	if err != nil {
 		br.Msg = "存储目录创建失败"
@@ -527,14 +529,16 @@ func (this *PptV2Controller) PptUpload() {
 	randStr := utils.GetRandStringNoSpecialChar(28)
 	fileName := randStr + ext
 	fpath := uploadDir + "/" + fileName
-	defer f.Close() //关闭上传文件
-	err = this.SaveToFile("file", fpath)
-	if err != nil {
+
+	if err = this.SaveToFile("file", fpath); err != nil {
 		br.Msg = "文件上传失败"
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		return
 	}
-	hzUploadDir := "ppt/"
+	defer func() {
+		_ = os.Remove(fpath)
+	}()
+	hzUploadDir := utils.RESOURCE_DIR + "ppt/"
 	savePptxToOssPath := hzUploadDir + time.Now().Format("200601/20060102/")
 
 	//pptName := strings.Replace(pptItem.Title, "\n", "", -1)
@@ -542,56 +546,22 @@ func (this *PptV2Controller) PptUpload() {
 	pptName := utils.GetRandStringNoSpecialChar(28)
 	savePptxToOssPath += pptName + ".pptx"
 
-	defer func() {
-		_ = os.Remove(fpath)
-	}()
-
 	//上传到阿里云 和 minio
 	pptxUrl := ``
-	//if utils.ObjectStorageClient == "minio" {
-	//	err = services.UploadFileToMinIo("", fpath, savePptxToOssPath)
-	//	if err != nil {
-	//		br.Msg = "文件上传失败"
-	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-	//		return
-	//	}
-	//	pptxUrl = utils.MinIoImghost + savePptxToOssPath
-	//} else {
-	//	err = services.UploadFileToAliyun("", fpath, savePptxToOssPath)
-	//	if err != nil {
-	//		br.Msg = "文件上传失败"
-	//		br.ErrMsg = "文件上传失败,Err:" + err.Error()
-	//		return
-	//	}
-	//	pptxUrl = utils.Imghost + savePptxToOssPath
-	//}
 	ossClient := services.NewOssClient()
 	if ossClient == nil {
 		br.Msg = "上传失败"
 		br.ErrMsg = "初始化OSS服务失败"
 		return
 	}
-	pptxUrl, err = ossClient.UploadFile("", fpath, savePptxToOssPath)
+	pptxUrl, err = ossClient.UploadFile(fileName, fpath, savePptxToOssPath)
 	if err != nil {
 		br.Msg = "文件上传失败"
 		br.ErrMsg = "文件上传失败,Err:" + err.Error()
 		return
 	}
 
-	item := &models.Resource{
-		//Id:           0,
-		ResourceUrl:  pptxUrl,
-		CreateTime:   time.Now(),
-		ResourceType: 4,
-	}
-	newId, err := models.AddResource(item)
-	if err != nil {
-		br.Msg = "资源上传失败"
-		br.ErrMsg = "资源上传失败,Err:" + err.Error()
-		return
-	}
 	resp := models.ResourceResp{
-		Id:           newId,
 		ResourceUrl:  pptxUrl,
 		ResourceName: uploadFileName,
 	}

+ 7 - 2
controllers/sys_admin.go

@@ -1236,7 +1236,8 @@ func (this *SysAdminController) ResetPass() {
 	adminInfo.Password = pwd
 	adminInfo.LastUpdatedPasswordTime = time.Now().Format(utils.FormatDateTime)
 	adminInfo.LastUpdatedTime = time.Now().Format(utils.FormatDateTime)
-	if e := adminInfo.Update([]string{"Password", "LastUpdatedPasswordTime", "LastUpdatedTime"}); e != nil {
+	adminInfo.LastLoginTime = time.Now().Format(utils.FormatDateTime)
+	if e := adminInfo.Update([]string{"Password", "LastUpdatedPasswordTime", "LastUpdatedTime", "LastLoginTime"}); e != nil {
 		br.Msg = "操作失败"
 		br.ErrMsg = "更新系统用户分组失败, Err: " + e.Error()
 		return
@@ -1250,9 +1251,13 @@ func (this *SysAdminController) ResetPass() {
 		_ = utils.Rc.LPush(utils.CACHE_SYNC_ADMIN, syncData)
 	}
 
-	// 清除系统用户列表缓存key
+	// 清除系统用户列表缓存key及异常登录缓存
 	_ = utils.Rc.Delete(utils.CACHE_KEY_ADMIN)
 	_ = utils.Rc.Delete(utils.CACHE_KEY_ADMIN_ID)
+	abnormalKey := fmt.Sprint(utils.CACHE_ABNORMAL_LOGIN, adminInfo.AdminName)
+	errPassKey := fmt.Sprint(utils.CACHE_LOGIN_ERR_PASS, adminInfo.AdminName)
+	_ = utils.Rc.Delete(abnormalKey)
+	_ = utils.Rc.Delete(errPassKey)
 
 	br.Ret = 200
 	br.Success = true

+ 8 - 1
controllers/sys_role.go

@@ -717,7 +717,14 @@ func (this *SysRoleController) SystemConfig() {
 	if osc.ConfVal == "" {
 		osc.ConfVal = "oss"
 	}
-	list = append(list, osc)
+
+	// ppt上传走后端配置
+	pptUpload := system.BusinessConf{
+		ConfKey: "PptUpdateApi",
+		ConfVal: utils.PptUpdateApi,
+	}
+
+	list = append(list, osc, pptUpload)
 
 	// 获取审批流设置
 	//confKey := "approval_flow"

+ 19 - 4
controllers/user_login.go

@@ -924,8 +924,8 @@ func (this *UserLoginController) AreaCodeList() {
 // @Title icp备案信息
 // @Description icp备案信息
 // @Success 200 Ret=200 获取成功
-// @router /icp_license [get]
-func (this *UserLoginController) ICPLicense() {
+// @router /base_info [get]
+func (this *UserLoginController) BaseInfo() {
 	br := new(models.BaseResponse).Init()
 	defer func() {
 		if br.ErrMsg == "" {
@@ -935,15 +935,30 @@ func (this *UserLoginController) ICPLicense() {
 		this.ServeJSON()
 	}()
 
+	icp, e := models.GetBusinessConfByKey("ICPLicense")
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
+		return
+	}
 
-	item, e := models.GetBusinessConfByKey("ICPLicense")
+	title, e := models.GetBusinessConfByKey("ETATitle")
 	if e != nil {
 		br.Msg = "获取失败"
 		br.ErrMsg = "获取商家配置失败, Err: " + e.Error()
 		return
 	}
+	type BaseInfoResp struct {
+		Icp      *models.BusinessConf `description:"手机号"`
+		ETATitle *models.BusinessConf `description:"邮箱"`
+	}
+
+	resp := BaseInfoResp{
+		Icp:      icp,
+		ETATitle: title,
+	}
 
-	br.Data = item
+	br.Data = resp
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "获取成功"

+ 41 - 10
models/aimod/ai.go

@@ -10,6 +10,8 @@ type AiChatTopic struct {
 	TopicName       string
 	SysUserId       int
 	SysUserRealName string
+	AssistantId     string
+	ThreadId        string
 	CreateTime      time.Time
 	ModifyTime      time.Time
 }
@@ -22,7 +24,10 @@ type AiChat struct {
 	Answer          string
 	Model           string
 	SysUserId       int
-	SysUserRealName string
+	SysUserRealName string `description:"提问人名称"`
+	OpenaiFileId    string `description:"openai返回的文件id"`
+	OpenaiFileName  string `description:"文件名称"`
+	OpenaiFilePath  string `description:"文件路径"`
 	CreateTime      time.Time
 	ModifyTime      time.Time
 }
@@ -65,6 +70,8 @@ type AiChatTopicView struct {
 	TopicName     string `description:"主题名称"`
 	CreateTime    string `description:"创建时间"`
 	ModifyTime    string `description:"修改时间"`
+	AssistantId   string
+	ThreadId      string
 }
 
 func GetAiChatTopicList(sysUserId int) (item []*AiChatTopicView, err error) {
@@ -79,13 +86,16 @@ type AiChatTopicListResp struct {
 }
 
 type AiChatView struct {
-	AiChatId      int    `description:"记录id"`
-	AiChatTopicId int    `description:"主题id"`
-	Ask           string `description:"提问"`
-	Answer        string `description:"答案"`
-	Model         string
-	CreateTime    string `description:"创建时间"`
-	ModifyTime    string `description:"修改时间"`
+	AiChatId       int    `description:"记录id"`
+	AiChatTopicId  int    `description:"主题id"`
+	Ask            string `description:"提问"`
+	Answer         string `description:"答案"`
+	Model          string
+	OpenaiFileId   string `description:"文件ID"`
+	OpenaiFileName string `description:"文件名称"`
+	OpenaiFilePath string `description:"文件路径"`
+	CreateTime     string `description:"创建时间"`
+	ModifyTime     string `description:"修改时间"`
 }
 
 func GetAiChatList(aiChatTopicId int) (item []*AiChatView, err error) {
@@ -145,7 +155,28 @@ func EditTopic(topicId int, topicName string) (err error) {
 	return err
 }
 
+func (obj *AiChatTopic) GetAiChatTopicById() (item *AiChatTopicView, err error) {
+	o := orm.NewOrmUsingDB("ai")
+	sql := ` SELECT * FROM ai_chat_topic WHERE ai_chat_topic_id=? `
+	err = o.Raw(sql, obj.AiChatTopicId).QueryRow(&item)
+	return
+}
+
 type HistoryChat struct {
-	Ask    string
-	Answer string
+	Ask          string
+	Answer       string
+	OpenaiFileId []string `description:"文件ID"`
+}
+
+// 修改
+func (obj *AiChatTopic) Update(updateParams, whereParam map[string]interface{}) (err error) {
+	to := orm.NewOrmUsingDB("ai")
+	ptrStructOrTableName := "ai_chat_topic"
+
+	qs := to.QueryTable(ptrStructOrTableName)
+	for expr, exprV := range whereParam {
+		qs = qs.Filter(expr, exprV)
+	}
+	_, err = qs.Update(updateParams)
+	return
 }

+ 7 - 0
models/aimod/ai_file.go

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

+ 29 - 0
models/aimod/file_upload_record.go

@@ -0,0 +1,29 @@
+package aimod
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type FileUploadRecord struct {
+	FileUploadRecordId  int       `orm:"column(file_upload_record_id);pk"`
+	AdminId             int       `description:"用户id"`
+	FileUrl             string    `description:"文件地址"`
+	FileName            string    `description:"文件名称"`
+	OpenaiFileId        string    `description:"openai返回的文件id"`
+	OpenaiFileName      string    `description:"openai返回的文件名称"`
+	OpenaiObject        string    `description:"openai返回的文件对象"`
+	OpenaiStatus        string    `description:"openai返回的文件状态"`
+	OpenaiPurpose       string    `description:"openai返回的提示词"`
+	OpenaiStatusDetails string    `description:"openai返回的文件状态详情"`
+	OpenaiCreatedAt     int64     `description:"openai返回的创建时间"`
+	CreateTime          time.Time `description:"创建时间"`
+	ModifyTime          time.Time `description:"修改时间"`
+}
+
+// AddAiChatTopic 新增上传文件记录
+func (obj *FileUploadRecord) AddFileUploadRecord() (lastId int64, err error) {
+	o := orm.NewOrmUsingDB("ai")
+	lastId, err = o.Insert(obj)
+	return
+}

+ 1 - 0
models/data_manage/edb_info.go

@@ -57,6 +57,7 @@ type EdbInfo struct {
 	SubSourceName    string  `description:"子数据来源名称"`
 	IndicatorCode    string  `description:"指标代码"`
 	StockCode        string  `description:"证券代码"`
+	Extra            string  `description:"指标额外配置"`
 }
 
 type EdbInfoFullClassify struct {

+ 86 - 3
models/data_manage/edb_info_calculate.go

@@ -5,6 +5,7 @@ import (
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 	"github.com/yidane/formula"
 	"strconv"
 	"strings"
@@ -20,6 +21,7 @@ type EdbInfoCalculateSaveReq struct {
 	Calendar         string           `description:"公历/农历"`
 	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string           `description:"指标的额外配置"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -77,6 +79,9 @@ type EdbInfoCalculateDetail struct {
 	LatestValue        float64   `description:"最近实际数据的值"`
 	EndValue           float64   `description:"结束日期的值(可能是插入值)"`
 	EdbType            int       `description:"指标类型:1:基础指标,2:计算指标"`
+	Frequency          string    `description:"频率"`
+	Unit               string    `description:"单位"`
+	ClassifyId         int       `description:"分类id"`
 }
 
 func GetEdbInfoCalculateDetail(edbInfoId, source int) (list []*EdbInfoCalculateDetail, err error) {
@@ -89,7 +94,7 @@ func GetEdbInfoCalculateDetail(edbInfoId, source int) (list []*EdbInfoCalculateD
 	//
 	//sql = fmt.Sprintf(sql, calculateTableName)
 
-	sql := ` SELECT a.edb_info_calculate_mapping_id,a.edb_info_id,a.source,a.source_name,a.edb_code,a.from_edb_info_id,a.from_edb_code,a.from_source,a.from_source_name,a.sort,a.create_time,a.modify_time,a.from_tag,a.move_value,b.edb_name_source as from_edb_name,b.start_date,b.end_date,b.latest_date,b.latest_value,b.edb_type FROM edb_info_calculate_mapping AS a
+	sql := ` SELECT a.edb_info_calculate_mapping_id,a.edb_info_id,a.source,a.source_name,a.edb_code,a.from_edb_info_id,a.from_edb_code,a.from_source,a.from_source_name,a.sort,a.create_time,a.modify_time,a.from_tag,a.move_value,b.edb_name_source as from_edb_name,b.start_date,b.end_date,b.latest_date,b.latest_value,b.edb_type, b.frequency, b.unit, b.classify_id FROM edb_info_calculate_mapping AS a
 			INNER JOIN edb_info AS b ON a.from_edb_info_id=b.edb_info_id
 			WHERE a.edb_info_id=? ORDER BY sort ASC `
 
@@ -111,6 +116,7 @@ type EdbInfoCalculateEditReq struct {
 	CalculateFormula string           `description:"计算公式"`
 	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string           `description:"指标的额外配置"`
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 }
 
@@ -155,6 +161,37 @@ func DeleteCalculateData(edbInfoId int) (err error) {
 	return
 }
 
+type EdbInfoBase struct {
+	EdbInfoId  int    `description:"指标id"`
+	EdbName    string `description:"指标名称"`
+	Frequency  string `description:"频度"`
+	Unit       string `description:"单位"`
+	ClassifyId int    `description:"分类id"`
+}
+
+type CalculateEdbInfoItem struct {
+	EdbInfoId     int    `description:"指标id"`
+	EdbName       string `description:"指标名称"`
+	Frequency     string `description:"频度"`
+	Unit          string `description:"单位"`
+	ClassifyId    int    `description:"分类id"`
+	CalculateId   string `description:"当前请求时,单个计算的唯一标识"`
+	FromEdbInfoId int    `description:"计算来源指标id"`
+}
+
+type EdbInfoCalculateBatchSaveMultiReq struct {
+	List             []CalculateEdbInfoItem
+	Formula          string           `description:"N值/移动天数"`
+	FromEdbInfoId    int              `description:"计算来源指标id"`
+	Source           int              `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:变频"`
+	CalculateFormula string           `description:"计算公式"`
+	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
+	MoveType         int              `description:"移动方式:1:领先(默认),2:滞后"`
+	MoveFrequency    string           `description:"移动频度:天/周/月/季/年"`
+	Extra            string           `description:"指标的额外配置"`
+	Calendar         string           `description:"公历/农历"`
+}
+
 type EdbInfoCalculateBatchSaveReq struct {
 	EdbInfoId        int              `description:"指标id"`
 	EdbName          string           `description:"指标名称"`
@@ -168,6 +205,7 @@ type EdbInfoCalculateBatchSaveReq struct {
 	EdbInfoIdArr     []EdbInfoFromTag `description:"指标信息"`
 	MoveType         int              `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency    string           `description:"移动频度:天/周/月/季/年"`
+	Extra            string           `description:"指标的额外配置"`
 	Calendar         string           `description:"公历/农历"`
 }
 
@@ -183,6 +221,7 @@ type EdbInfoCalculateBatchEditReq struct {
 	MoveType      int    `description:"移动方式:1:领先(默认),2:滞后"`
 	MoveFrequency string `description:"移动频度:天/周/月/季/年"`
 	Calendar      string `description:"公历/农历"`
+	Extra         string `description:"指标的额外配置"`
 	EdbInfoIdArr  []EdbInfoFromTag
 }
 
@@ -206,6 +245,7 @@ type EdbInfoCalculateBatchSaveReqByEdbLib struct {
 	Data             interface{}      `description:"数据列"`
 	EmptyType        int              `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
 	MaxEmptyType     int              `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string           `description:"指标的额外配置"`
 }
 
 // EdbInfoCalculateBatchEditReqByEdbLib 编辑计算指标的请求参数
@@ -223,6 +263,7 @@ type EdbInfoCalculateBatchEditReqByEdbLib struct {
 	Calendar      string `description:"公历/农历"`
 	EdbInfoIdArr  []EdbInfoFromTag
 	Data          interface{} `description:"数据列"`
+	Extra         string      `description:"指标的额外配置"`
 }
 
 func GetEdbInfoCalculateMap(edbInfoId, source int) (list []*EdbInfo, err error) {
@@ -501,8 +542,20 @@ type SaveAdjustEdbDataReq struct {
 
 // BatchEdbInfoCalculateBatchSaveReq 批量添加 计算指标
 type BatchEdbInfoCalculateBatchSaveReq struct {
-	CalculateId   string `description:"当前请求时,单个计算的唯一标识"`
-	CalculateInfo EdbInfoCalculateBatchSaveReq
+	AdminId          int                     `description:"添加人id"`
+	AdminName        string                  `description:"添加人名称"`
+	EdbList          []*CalculateEdbInfoItem //需要批量计算的指标列表
+	Formula          string                  `description:"N值/移动天数"`
+	Source           int                     `description:"来源:1:同花顺,2:wind,3:彭博,4:指标运算,5:累计值转月,6:同比值,7:同差值,8:N数值移动平均计算,12:环比值,13:环差值,14:升频"`
+	CalculateFormula string                  `description:"计算公式"`
+	EdbInfoIdArr     []EdbInfoFromTag        `description:"关联指标列表"`
+	MoveType         int                     `description:"移动方式:1:领先(默认),2:滞后"`
+	MoveFrequency    string                  `description:"移动频度:天/周/月/季/年"`
+	Calendar         string                  `description:"公历/农历"`
+	Data             interface{}             `description:"数据"`
+	EmptyType        int                     `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
+	MaxEmptyType     int                     `description:"MAX、MIN公式空值处理类型(1、等于0;2、跳过空值)"`
+	Extra            string                  `description:"指标的额外配置"`
 }
 
 // BatchEdbInfoCalculateBatchSaveResp 批量添加 计算指标 返回数据
@@ -525,3 +578,33 @@ type BatchEdbInfoCalculateBatchSaveSuccessResp struct {
 	EdbInfoId   int    `description:"指标ID"`
 	UniqueCode  string `description:"指标唯一编码"`
 }
+
+// CalculateMultiSearchReq 批量计算模块下的指标搜索
+type CalculateMultiChoiceReq struct {
+	ClassifyIds string `description:"分类ID, 用英文逗号拼接"`
+	Frequency   string `description:"频度"`
+	SysUserIds  string `description:"创建人ID,用英文逗号拼接"`
+	Keyword     string `description:"关键字"`
+	SelectAll   bool   `description:"是否全选"`
+	EdbInfoIds  string `description:"指标Id, 用英文逗号拼接"`
+}
+
+type CalculateMultiChoiceResp struct {
+	SearchItem []EdbInfoBase `description:"查询结果"`
+}
+
+type CalculateMultiEdbSearchResp struct {
+	SearchItem []CalculateMultiEdbSearchItem `description:"查询结果"`
+	Paging     *paging.PagingItem
+}
+type CalculateMultiEdbSearchItem struct {
+	EdbInfoId       int    `description:"指标id"`
+	EdbName         string `description:"指标名称"`
+	Frequency       string `description:"频度"`
+	Unit            string `description:"单位"`
+	ClassifyId      int    `description:"分类id"`
+	SysUserId       int
+	SysUserRealName string
+	EndValue        float64 `description:"数据的最新值(预测日期的最新值)"`
+	EndDate         string  `description:"终止日期"`
+}

+ 1 - 0
models/db.go

@@ -516,6 +516,7 @@ func initAi() {
 	orm.RegisterModel(
 		new(aimod.AiChatTopic),
 		new(aimod.AiChat),
+		new(aimod.FileUploadRecord),
 	)
 }
 

+ 8 - 6
models/resource.go

@@ -13,12 +13,14 @@ type Resource struct {
 }
 
 type ResourceResp struct {
-	Id           int64  `orm:"column(id);" description:"用户id"`
-	ResourceUrl  string `description:"资源地址"`
-	PlaySeconds  uint32 `description:"播放时长,单位秒"`
-	Source       string
-	CacheKey     string
-	ResourceName string `description:"资源名称"`
+	Id            int64  `orm:"column(id);" description:"用户id"`
+	ResourceUrl   string `description:"资源地址"`
+	PlaySeconds   uint32 `description:"播放时长,单位秒"`
+	Source        string
+	CacheKey      string
+	ResourceName  string `description:"资源名称"`
+	OpenaiFileId  string `description:"openai返回的文件id"`
+	AiChatTopicId int    `description:"主题id"`
 }
 
 func AddResource(item *Resource) (newId int64, err error) {

+ 54 - 9
routers/commentsRouter.go

@@ -52,6 +52,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/ai:AiFileController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/ai:AiFileController"],
+        beego.ControllerComments{
+            Method: "FileRetrieve",
+            Router: `/file/retrieve`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/ai:AiFileController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/ai:AiFileController"],
+        beego.ControllerComments{
+            Method: "FileUpload",
+            Router: `/file/upload`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/correlation:CorrelationChartClassifyController"],
         beego.ControllerComments{
             Method: "AddChartClassify",
@@ -2104,6 +2122,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "BatchCalculateBatchEdit",
+            Router: `/edb_info/calculate/batch/edit/batch`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "CalculateBatchReset",
@@ -2167,6 +2194,24 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "CalculateMultiChoice",
+            Router: `/edb_info/calculate/multi/choice`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "CalculateMultiSearch",
+            Router: `/edb_info/calculate/multi/search`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "CalculateSave",
@@ -8404,6 +8449,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
+        beego.ControllerComments{
+            Method: "BaseInfo",
+            Router: `/base_info`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
         beego.ControllerComments{
             Method: "ForgetAccountGet",
@@ -8440,15 +8494,6 @@ func init() {
             Filters: nil,
             Params: nil})
 
-    beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
-        beego.ControllerComments{
-            Method: "ICPLicense",
-            Router: `/icp_license`,
-            AllowHTTPMethods: []string{"get"},
-            MethodParams: param.Make(),
-            Filters: nil,
-            Params: nil})
-
     beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers:UserLoginController"],
         beego.ControllerComments{
             Method: "Login",

+ 1 - 0
routers/router.go

@@ -321,6 +321,7 @@ func init() {
 		web.NSNamespace("/ai",
 			web.NSInclude(
 				&ai.AiController{},
+				&ai.AiFileController{},
 			),
 		),
 		web.NSNamespace("/cross_variety", //跨品种分析

+ 135 - 0
services/aiser/ai.go

@@ -66,8 +66,143 @@ func ChatAutoMsg(prompt string, historyChatList []aimod.HistoryChat) (result str
 	return result, nil
 }
 
+func OpenAiFileUpload(fileUrl, fileName string) (result *OpenAiFileUploadResp, err error) {
+	chatUrl := utils.EtaAiUrl + `chat/file/upload`
+
+	param := make(map[string]interface{})
+	param["FileUrl"] = fileUrl
+	param["FileName"] = fileName
+
+	postData, err := json.Marshal(param)
+	if err != nil {
+		return result, err
+	}
+
+	client := &http.Client{}
+	//提交请求
+	reqest, err := http.NewRequest("POST", chatUrl, strings.NewReader(string(postData)))
+	businessCode := utils.BusinessCode
+	if businessCode == "" {
+		return nil, errors.New("未获取到商户号")
+	}
+	nonce := utils.GetRandStringNoSpecialChar(16)
+	timestamp := time.Now().Format(utils.FormatDateTimeUnSpace)
+	signature := utils.GetSign(nonce, timestamp, utils.EtaAppid, utils.EtaSecret)
+	//增加header选项
+	reqest.Header.Add("BusinessCode", businessCode)
+	reqest.Header.Add("Nonce", nonce)
+	reqest.Header.Add("Timestamp", timestamp)
+	reqest.Header.Add("Appid", utils.EtaAppid)
+	reqest.Header.Add("Signature", signature)
+	reqest.Header.Set("Content-Type", "application/json")
+
+	utils.FileLog.Info("postData:" + string(postData))
+
+	response, err := client.Do(reqest)
+	if err != nil {
+		return
+	}
+	defer response.Body.Close()
+
+	body, err := ioutil.ReadAll(response.Body)
+
+	utils.FileLog.Info("result:" + string(body))
+
+	resp := new(OpenAiFileUploadResp)
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return result, err
+	}
+	return resp, nil
+}
+
+func FileRetrieve(assistantId, threadId string, historyChatList []aimod.HistoryChat, OpenaiFileId []string) (result *OpenAiFileRetrieveResp, err error) {
+	chatUrl := utils.EtaAiUrl + `chat/file/retrieve`
+
+	param := make(map[string]interface{})
+	param["FileRetrieveList"] = historyChatList
+	param["OpenaiFileId"] = OpenaiFileId
+	param["AssistantId"] = assistantId
+	param["ThreadId"] = threadId
+
+	postData, err := json.Marshal(param)
+	if err != nil {
+		return result, err
+	}
+
+	client := &http.Client{}
+	//提交请求
+	reqest, err := http.NewRequest("POST", chatUrl, strings.NewReader(string(postData)))
+	businessCode := utils.BusinessCode
+	if businessCode == "" {
+		return nil, errors.New("未获取到商户号")
+	}
+	nonce := utils.GetRandStringNoSpecialChar(16)
+	timestamp := time.Now().Format(utils.FormatDateTimeUnSpace)
+	signature := utils.GetSign(nonce, timestamp, utils.EtaAppid, utils.EtaSecret)
+	//增加header选项
+	reqest.Header.Add("BusinessCode", businessCode)
+	reqest.Header.Add("Nonce", nonce)
+	reqest.Header.Add("Timestamp", timestamp)
+	reqest.Header.Add("Appid", utils.EtaAppid)
+	reqest.Header.Add("Signature", signature)
+	reqest.Header.Set("Content-Type", "application/json")
+
+	utils.FileLog.Info("postData:" + string(postData))
+
+	response, err := client.Do(reqest)
+	if err != nil {
+		return
+	}
+	defer response.Body.Close()
+
+	body, err := ioutil.ReadAll(response.Body)
+	if err != nil {
+		return
+	}
+
+	utils.FileLog.Info("result:" + string(body))
+
+	resp := new(OpenAiFileRetrieveResp)
+	err = json.Unmarshal(body, &resp)
+	if err != nil {
+		return result, err
+	}
+	return resp, nil
+}
+
 type ChatAutoMsgResp struct {
 	Ret  int
 	Data string
 	Msg  string
 }
+
+type OpenAiFileUploadResp struct {
+	Ret  int
+	Data *OpenAiFile
+	Msg  string
+}
+
+type OpenAiFile struct {
+	Bytes         int    `json:"bytes"`
+	CreatedAt     int64  `json:"created_at"`
+	ID            string `json:"id"`
+	FileName      string `json:"filename"`
+	Object        string `json:"object"`
+	Status        string `json:"status"`
+	Purpose       string `json:"purpose"`
+	StatusDetails string `json:"status_details"`
+}
+
+type OpenAiFileRetrieveResp struct {
+	Ret    int
+	Data   *FileRetrieveResp
+	Msg    string
+	ErrMsg string
+}
+
+type FileRetrieveResp struct {
+	AssistantId string `description:"助手ID"`
+	ThreadId    string `description:"进程id"`
+	Answer      string
+}

+ 38 - 6
services/aws_s3.go

@@ -2,6 +2,7 @@ package services
 
 import (
 	"bytes"
+	"crypto/tls"
 	"eta/eta_api/utils"
 	"fmt"
 	"github.com/aws/aws-sdk-go/aws"
@@ -9,6 +10,7 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/s3"
 	"io/ioutil"
+	"net/http"
 	"time"
 )
 
@@ -60,7 +62,12 @@ func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl st
 		}
 	}()
 
-	endpoint := utils.S3Endpoint
+	// 默认使用后端这个, 这里有两个配置的原因是
+	// 前端上传跨域问题可能会使用反向代理来解决, 这样的话同一个endpoint就会导致一端正常另一端不正常
+	endpoint := utils.S3BackEndpoint
+	if endpoint == "" {
+		endpoint = utils.S3Endpoint
+	}
 	accessKey := utils.S3AccessKeyId
 	secretKey := utils.S3AccessKeySecret
 	region := utils.S3Region
@@ -72,14 +79,31 @@ func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl st
 	if forceStyle == "false" {
 		hostStyle = false
 	}
+	disableSSL := true // 默认true, 跳过SSL
+	if utils.S3DisableSSL == "false" {
+		disableSSL = false
+	}
+	//fmt.Println("disableSSL: ", disableSSL)
 
-	// 创建AWS会话
-	sess, e := session.NewSession(&aws.Config{
+	config := &aws.Config{
 		Region:           aws.String(region),
 		Credentials:      credentials.NewStaticCredentials(accessKey, secretKey, ""),
 		Endpoint:         aws.String(endpoint),
 		S3ForcePathStyle: aws.Bool(hostStyle),
-	})
+		DisableSSL:       aws.Bool(disableSSL),
+	}
+	if disableSSL {
+		config.HTTPClient = &http.Client{
+			Transport: &http.Transport{
+				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+			},
+		}
+	}
+	//b, _ := json.Marshal(config)
+	//fmt.Println(string(b))
+
+	// 创建AWS会话
+	sess, e := session.NewSession(config)
 	if e != nil {
 		err = fmt.Errorf("new session err: %s", e.Error())
 		return
@@ -99,16 +123,24 @@ func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl st
 	if savePath == "" {
 		path = uploadDir + time.Now().Format("200601/20060102/") + fileName
 	}
-	_, e = client.PutObject(&s3.PutObjectInput{
+	putObjectInput := &s3.PutObjectInput{
 		Bucket: aws.String(bucketName),
 		Key:    aws.String(path),
 		Body:   bytes.NewReader(fileContent),
-	})
+	}
+	if utils.S3OpenAcl == "1" {
+		putObjectInput.ACL = aws.String(s3.ObjectCannedACLPublicRead)
+	}
+	fmt.Printf("put object input: %+v\n", putObjectInput)
+	_, e = client.PutObject(putObjectInput)
 	if e != nil {
 		err = fmt.Errorf("put object err: %s", e.Error())
 		return
 	}
 	resourceUrl = resourceHost + path
+	if utils.ResourceProxyUrl != "" {
+		resourceUrl = utils.ResourceProxyUrl + path
+	}
 	return
 }
 

+ 32 - 0
services/data/base_edb_lib.go

@@ -126,6 +126,18 @@ type AddPredictEdbDataResponse struct {
 	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
 }
 
+// EdbCalculateSaveMultiResponse 批量计算返回值
+type EdbCalculateSaveMultiResponse struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        data_manage.BatchEdbInfoCalculateBatchSaveResp
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-" description:"true 发送邮件,false 不发送邮件"`
+	IsAddLog    bool `json:"-" description:"true 新增操作日志,false 不新增操作日志" `
+}
+
 // SaveBasePredictEdbData 新增/编辑预测指标运算
 func SaveBasePredictEdbData(edbInfoCalculateBatchSaveReqStr string) (resp *AddPredictEdbDataResponse, err error) {
 	_, resultByte, err := postAddEdbData(edbInfoCalculateBatchSaveReqStr, "predict/save")
@@ -328,6 +340,26 @@ func BatchEditEdbCalculateData(edbInfoCalculateBatchSaveReqStr string) (resp *Ad
 	return
 }
 
+// BatchSaveEdbCalculateMultiData 批量新增 累计值转月-同比值-同差等计算新增
+func BatchSaveEdbCalculateMultiData(edbInfoCalculateBatchSaveReqStr string) (resp *EdbCalculateSaveMultiResponse, err error) {
+	_, resultByte, err := postAddEdbData(edbInfoCalculateBatchSaveReqStr, "calculate/batch/save/multi")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
+// BatchEditEdbCalculateMultiData 批量编辑 累计值转月-同比值-同差等计算新增
+func BatchEditEdbCalculateMultiData(edbInfoCalculateBatchSaveReqStr string) (resp *EdbCalculateSaveMultiResponse, err error) {
+	_, resultByte, err := postAddEdbData(edbInfoCalculateBatchSaveReqStr, "calculate/batch/edit/multi")
+	err = json.Unmarshal(resultByte, &resp)
+	if err != nil {
+		return
+	}
+	return
+}
+
 //// EditEdbCalculateData 修改计算指标数据请求
 //func EditEdbCalculateData(edbInfoCalculateBatchSaveReqStr string) (resp *models.BaseResponse, err error) {
 //	resp, _, err = postAddEdbData(edbInfoCalculateBatchSaveReqStr, "batch/save")

+ 40 - 6
services/data/excel/mixed_table.go

@@ -1062,9 +1062,10 @@ func handlerDateCalculate(dateCalculateList []string, calculateCellMap map[strin
 
 			val, tmpErr, tmpErrMsg := DateCalculatePrepare(calculateCellMap, cell.Value)
 			if tmpErr != nil {
-				errMsg = tmpErrMsg
-				err = tmpErr
-				return
+				cell.ShowValue = ""
+				config[cellPosition.Column][cellPosition.Row] = cell
+				utils.FileLog.Error(fmt.Sprintf("%s 日期计算报错:Err:%s:%s", cellKey, tmpErr, tmpErrMsg))
+				continue
 			}
 
 			cell.ShowValue = utils.FormatMixTableDataShowValue(val)
@@ -1214,21 +1215,54 @@ func handleMixCellShowStyle(showStyleList []string, calculateCellMap map[string]
 // changePointDecimalPlaces 小数点位数加减和百分比格式
 func changePointDecimalPlaces(str string, changeNum int, numberType string, isPercent bool) (newStr string) {
 	newStr = str
+	var decimalPlaces int
+	dotIndex := strings.Index(newStr, ".") // 查找小数点的位置
+	if dotIndex == -1 {
+		decimalPlaces = 0
+	} else {
+		decimalPlaces = len(newStr) - dotIndex - 1
+	}
 	// 把字符串转成浮点数
 	val, _ := strconv.ParseFloat(str, 64)
 	if isPercent {
 		if numberType == "number" { //百分数转成小数
 			val = val / 100
+			if decimalPlaces > 2 {
+				decimalPlaces += 2
+			} else if decimalPlaces == 1 {
+				decimalPlaces += 1
+			} else if decimalPlaces == 0 {
+				if len(str) == 1 {
+					decimalPlaces = 2
+				} else if len(str) == 2 {
+					if str[1] == '0' {
+						decimalPlaces = 1
+					} else {
+						decimalPlaces = 2
+					}
+				}
+			}
 			isPercent = false
 		}
 	} else {
 		if numberType == "percent" {
+			if decimalPlaces > 2 {
+				decimalPlaces -= 2
+			} else if decimalPlaces == 1 {
+				decimalPlaces = 0
+			}
 			val = val * 100
 		}
 	}
-	newStr = fmt.Sprintf("%v", val)
-	var decimalPlaces int                  // 计算小数位数
-	dotIndex := strings.Index(newStr, ".") // 查找小数点的位置
+	if decimalPlaces > 0 {
+		val, _ = decimal.NewFromFloat(val).Round(int32(decimalPlaces)).Float64()
+		newStr = strconv.FormatFloat(val, 'f', decimalPlaces, 64)
+	} else {
+		newStr = fmt.Sprintf("%v", val)
+	}
+	// 计算小数位数
+	decimalPlaces = 0
+	dotIndex = strings.Index(newStr, ".") // 查找小数点的位置
 	if dotIndex == -1 {
 		decimalPlaces = 0
 	} else {

+ 5 - 4
services/data/future_good/chart_info.go

@@ -259,7 +259,7 @@ func GetChartEdbData(chartInfoId int, startDate, endDate string, edbInfoMapping,
 		v.DataList = dataList
 	}
 
-	xEdbIdValue, yDataList, err = BarChartData(edbList[0], futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, latestDate)
+	xEdbIdValue, yDataList, err = BarChartData(edbList[0], futureGoodEdbInfoList, edbDataListMap, barChartInfoDateList, regionType, edbInfoMapping.EndDate)
 
 	xDataList = []data_manage.XData{
 		{
@@ -480,8 +480,9 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 			//	err = tmpErr
 			//	return
 			//}
-			tmpRealDateTime := findDateTime
-			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][findDateTime.Format(utils.FormatDate)]
+			//tmpRealDateTime := findDateTime	// 按照配置找到的日期
+			tmpRealDateTime := realDateTime // 实际现货的日期
+			tmpFindDataValue, tmpIsFind := edbDataMap[futureGoodMapping.FutureGoodEdbInfoId][tmpRealDateTime.Format(utils.FormatDate)]
 			yDataMap[futureGoodMapping.FutureGoodEdbInfoId] = tmpFindDataValue
 
 			findDataList = append(findDataList, tmpFindDataValue)
@@ -547,7 +548,7 @@ func BarChartData(edbInfoMapping *data_manage.ChartEdbInfoMapping, futureGoodMap
 
 		yDataList = append(yDataList, data_manage.YData{
 			Date:           yDate,
-			ConfigDate:     findDateTime,
+			ConfigDate:     realDateTime,
 			Value:          findDataList,
 			NoDataEdbList:  noDataIdList,
 			XEdbInfoIdList: xEdbInfoIdList,

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

@@ -171,7 +171,7 @@ func GetProfitChartEdbData(baseEdbInfo *data_manage.EdbInfo, zlFutureGoodEdbInfo
 		return dateList[i] < dateList[j]
 	})
 
-	_, yDataList, err = ProfitChartChartData(baseDataList, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, latestDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN)
+	_, yDataList, err = ProfitChartChartData(baseDataList, futureGoodEdbInfoDateMap, futureGoodDataListMap, chartInfoDateList, baseEdbInfo.EndDate, specialFutureGoodEdbInfoMap, formulaStr, tagEdbIdMap, dateList, maxN)
 
 	tmpXDataList, newYDataList, err := handleProfitResultData(baseEdbInfo, yDataList, earliestDateTime)
 	if err != nil {
@@ -384,7 +384,7 @@ func ProfitChartChartData(baseDataList []*data_manage.EdbDataList, futureGoodEdb
 
 		yDataList = append(yDataList, data_manage.YData{
 			Date:           yDate,
-			ConfigDate:     findDateTime,
+			ConfigDate:     realDateTime,
 			Value:          findDataList,
 			NoDataEdbList:  noDataIdList,
 			XEdbInfoIdList: xEdbInfoIdList,

+ 3 - 4
services/minio.go

@@ -4,6 +4,7 @@ import (
 	"context"
 	"errors"
 	"eta/eta_api/utils"
+	"fmt"
 	"github.com/minio/minio-go/v7"
 	"github.com/minio/minio-go/v7/pkg/credentials"
 	"log"
@@ -425,10 +426,8 @@ func (m *MinioOss) UploadFile(fileName, filePath, savePath string) (string, erro
 	}
 	bucketName := utils.MinIoBucketname
 	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
-	if errBucketExists == nil && exists {
-		log.Printf("We already own %s\n", bucketName)
-	} else {
-		log.Fatalln(err)
+	if errBucketExists != nil || !exists {
+		err = fmt.Errorf("BucketExists: %v; err: %v", exists, errBucketExists)
 		return "2", err
 	}
 

+ 18 - 0
utils/config.go

@@ -32,6 +32,8 @@ var (
 	EmailSendToUsers string // 邮件提醒人员
 	JhGnAppKey       string // 聚合短信,国内AppKey
 	JhGjAppKey       string // 聚合短信,国际AppKey
+	ResourceProxyUrl string // 代理资源地址
+	RESOURCE_DIR     string
 )
 
 // ES配置
@@ -123,6 +125,7 @@ var (
 // 对象存储客户端
 var (
 	ObjectStorageClient string // 目前有oss minio,默认oss
+	PptUpdateApi        string //ppt 通过后端接口的方式上传
 )
 
 // 阿里云配置
@@ -218,6 +221,7 @@ var (
 // S3配置
 var (
 	S3Endpoint        string
+	S3BackEndpoint    string
 	S3BucketName      string
 	S3UploadDir       string
 	S3AccessKeyId     string
@@ -227,6 +231,8 @@ var (
 	S3ForceStyle      string
 	S3EndpointPort    string
 	S3Protocol        string
+	S3DisableSSL      string
+	S3OpenAcl         string
 )
 
 func init() {
@@ -308,6 +314,13 @@ func init() {
 	// 静态文件目录
 	STATIC_DIR = config["static_dir"]
 
+	// 代理资源地址
+	ResourceProxyUrl = config["resource_proxy_url"]
+	RESOURCE_DIR = config["resource_dir"]
+	if RESOURCE_DIR == "" {
+		RESOURCE_DIR = "eta/"
+	}
+
 	// 系统内部服务地址
 	{
 		// 公共指标库相关
@@ -400,6 +413,8 @@ func init() {
 	// 对象存储客户端
 	ObjectStorageClient = config["object_storage_client"]
 
+	// ppt上传是否走后端
+	PptUpdateApi = config["ppt_update_api"]
 	// OSS相关
 	{
 		Endpoint = config["endpoint"]
@@ -492,6 +507,7 @@ func init() {
 	// S3-OSS相关
 	{
 		S3Endpoint = config["s3_endpoint"]
+		S3BackEndpoint = config["s3_back_endpoint"]
 		S3BucketName = config["s3_bucket_name"]
 		S3Host = config["s3_host"]
 		S3AccessKeyId = config["s3_access_key_id"]
@@ -501,6 +517,8 @@ func init() {
 		S3ForceStyle = config["s3_force_style"]
 		S3EndpointPort = config["s3_endpoint_port"]
 		S3Protocol = config["s3_protocol"]
+		S3DisableSSL = config["s3_disable_ssl"]
+		S3OpenAcl = config["s3_open_acl"]
 	}
 
 	// 生成长图服务地址

+ 1 - 1
utils/constants.go

@@ -319,7 +319,7 @@ var FrequencyDaysMap = map[string]int{
 }
 
 const (
-	AiChatLimit = 50
+	AiChatLimit = 500
 )
 
 // 系统来源