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

Merge branch 'refs/heads/eta_2.2.0_document_manage_0919@guomengyuan' into debug

gmy 6 сар өмнө
parent
commit
263334f09c

+ 2 - 0
controllers/base_auth.go

@@ -3,6 +3,7 @@ package controllers
 import (
 	"encoding/json"
 	"eta/eta_hub/models"
+	"eta/eta_hub/models/system"
 	"eta/eta_hub/utils"
 	"fmt"
 	"github.com/beego/beego/v2/server/web"
@@ -12,6 +13,7 @@ import (
 
 type BaseAuthController struct {
 	web.Controller
+	SysUser *system.Admin
 }
 
 func (this *BaseAuthController) Prepare() {

+ 49 - 0
controllers/outside_report_controller.go

@@ -0,0 +1,49 @@
+// @Author gmy 2024/9/24 16:05:00
+package controllers
+
+import (
+	"encoding/json"
+	"eta/eta_hub/models"
+	"eta/eta_hub/models/document_manage_model"
+	"eta/eta_hub/models/system"
+	"eta/eta_hub/services/document_manage_service"
+)
+
+type OutsideReportController struct {
+	BaseAuthController
+}
+
+// DocumentSave
+// @Title 新建文档
+// @Description 新建文档
+// @Success 200 “操作成功”
+// @router /document/save [post]
+func (this *OutsideReportController) DocumentSave() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req *document_manage_model.OutsideReportBO
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + e.Error()
+		return
+	}
+
+	userName := req.UserName
+	sysUser, err := system.GetUserByAdminName(userName)
+
+	req.SysUserId = sysUser.AdminId
+	req.SysUserName = sysUser.AdminName
+	err = document_manage_service.DocumentSave(req)
+	if err != nil {
+		br.Msg = "保存文档失败"
+		br.ErrMsg = "保存文档失败,Err:" + err.Error()
+		return
+	}
+	br.Ret = 200
+	br.Msg = "操作成功"
+	return
+}

+ 108 - 0
controllers/resource_deal_with_controller.go

@@ -0,0 +1,108 @@
+// @Author gmy 2024/9/24 17:56:00
+package controllers
+
+import (
+	"eta/eta_hub/models"
+	"eta/eta_hub/services"
+	"eta/eta_hub/utils"
+	"os"
+	"path"
+	"time"
+)
+
+type ResourceDealWithController struct {
+	BaseAuthController
+}
+
+// FileUpload
+// @Title 文件上传
+// @Description 文件上传接口
+// @Param   File   query   file  true       "文件"
+// @Param   AiChatTopicId   query   int  true       "主题id"
+// @Success 200 {object} models.ResourceResp
+// @router /file/upload [post]
+func (this *ResourceDealWithController) 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
+	}
+
+	/*fileData, e := ioutil.ReadAll(f)
+	if e != nil {
+		br.Msg = "上传失败"
+		br.ErrMsg = "读取文件失败, Err: " + e.Error()
+		return
+	}
+	pass := filetype.IsImage(fileData)
+	if !pass {
+		br.Msg = "文件格式有误"
+		br.ErrMsg = "文件格式有误"
+		return
+	}*/
+
+	uploadFileName := h.Filename //上传的文件名
+	ext := path.Ext(h.Filename)
+	dateDir := time.Now().Format("20060102")
+	uploadDir := utils.STATIC_DIR + "hongze/" + 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
+	}
+	resp := models.ResourceResp{
+		Id:           newId,
+		ResourceUrl:  resourceUrl,
+		ResourceName: uploadFileName,
+	}
+
+	br.Msg = "上传成功"
+	br.Ret = 200
+	br.Data = resp
+	return
+}

+ 206 - 213
controllers/smart_report.go

@@ -1,14 +1,7 @@
 package controllers
 
 import (
-	"encoding/json"
 	"eta/eta_hub/models"
-	"eta/eta_hub/services"
-	"eta/eta_hub/utils"
-	"fmt"
-	"github.com/rdlucklib/rdluck_tools/paging"
-	"strings"
-	"time"
 )
 
 // SmartReportController 智能研报
@@ -37,86 +30,86 @@ func (this *SmartReportController) List() {
 	br.ErrMsg = "智能研报已合并到中文研报,请使用中文研报的接口"
 	return
 
-	type SmartReportListReq struct {
-		PageSize     int `form:"PageSize"`
-		CurrentIndex int `form:"CurrentIndex"`
-	}
-	params := new(SmartReportListReq)
-	if e := this.ParseForm(params); e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "入参解析失败, Err: " + e.Error()
-		return
-	}
-
-	var condition string
-	var pars []interface{}
-	keyword := this.GetString("Keyword")
-	keyword = strings.TrimSpace(keyword)
-	if keyword != "" {
-		kw := fmt.Sprint("%", keyword, "%")
-		condition += ` AND (title LIKE ? OR author LIKE ? OR admin_real_name LIKE ?) `
-		pars = append(pars, kw, kw, kw)
-	}
-	state, _ := this.GetInt("State")
-	if state > 0 {
-		condition += ` AND state = ? `
-		pars = append(pars, state)
-	}
-	admindId, _ := this.GetInt("AdminId")
-	if admindId > 0 {
-		condition += ` AND admin_id = ? `
-		pars = append(pars, admindId)
-	}
-	classifyId, _ := this.GetInt("ClassifyId")
-	if classifyId > 0 {
-		condition += ` AND (classify_id_first = ? OR classify_id_second = ?) `
-		pars = append(pars, classifyId, classifyId)
-	}
-
-	resp := new(models.SmartReportListResp)
-	reportOB := new(models.SmartReport)
-	total, e := reportOB.GetCountByCondition(condition, pars)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取报告总数失败, Err:" + e.Error()
-		return
-	}
-	if total <= 0 {
-		page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
-		resp.Paging = page
-		br.Ret = 200
-		br.Msg = "获取成功"
-		br.Data = resp
-		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)
-
-	list, e := reportOB.GetPageItemsByCondition(condition, pars, []string{}, "", startSize, params.PageSize)
-	if e != nil {
-		br.Msg = "获取失败"
-		br.ErrMsg = "获取报告分页列表失败, Err:" + e.Error()
-		return
-	}
-	resp.List = make([]*models.SmartReportItem, 0)
-	for _, v := range list {
-		t := models.FormatSmartReport2Item(v)
-		resp.List = append(resp.List, t)
-	}
-
-	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
-	resp.Paging = page
-	br.Ret = 200
-	br.Msg = "获取成功"
-	br.Data = resp
+	//type SmartReportListReq struct {
+	//	PageSize     int `form:"PageSize"`
+	//	CurrentIndex int `form:"CurrentIndex"`
+	//}
+	//params := new(SmartReportListReq)
+	//if e := this.ParseForm(params); e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "入参解析失败, Err: " + e.Error()
+	//	return
+	//}
+	//
+	//var condition string
+	//var pars []interface{}
+	//keyword := this.GetString("Keyword")
+	//keyword = strings.TrimSpace(keyword)
+	//if keyword != "" {
+	//	kw := fmt.Sprint("%", keyword, "%")
+	//	condition += ` AND (title LIKE ? OR author LIKE ? OR admin_real_name LIKE ?) `
+	//	pars = append(pars, kw, kw, kw)
+	//}
+	//state, _ := this.GetInt("State")
+	//if state > 0 {
+	//	condition += ` AND state = ? `
+	//	pars = append(pars, state)
+	//}
+	//admindId, _ := this.GetInt("AdminId")
+	//if admindId > 0 {
+	//	condition += ` AND admin_id = ? `
+	//	pars = append(pars, admindId)
+	//}
+	//classifyId, _ := this.GetInt("ClassifyId")
+	//if classifyId > 0 {
+	//	condition += ` AND (classify_id_first = ? OR classify_id_second = ?) `
+	//	pars = append(pars, classifyId, classifyId)
+	//}
+	//
+	//resp := new(models.SmartReportListResp)
+	//reportOB := new(models.SmartReport)
+	//total, e := reportOB.GetCountByCondition(condition, pars)
+	//if e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取报告总数失败, Err:" + e.Error()
+	//	return
+	//}
+	//if total <= 0 {
+	//	page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	//	resp.Paging = page
+	//	br.Ret = 200
+	//	br.Msg = "获取成功"
+	//	br.Data = resp
+	//	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)
+	//
+	//list, e := reportOB.GetPageItemsByCondition(condition, pars, []string{}, "", startSize, params.PageSize)
+	//if e != nil {
+	//	br.Msg = "获取失败"
+	//	br.ErrMsg = "获取报告分页列表失败, Err:" + e.Error()
+	//	return
+	//}
+	//resp.List = make([]*models.SmartReportItem, 0)
+	//for _, v := range list {
+	//	t := models.FormatSmartReport2Item(v)
+	//	resp.List = append(resp.List, t)
+	//}
+	//
+	//page := paging.GetPaging(params.CurrentIndex, params.PageSize, total)
+	//resp.Paging = page
+	//br.Ret = 200
+	//br.Msg = "获取成功"
+	//br.Data = resp
 }
 
 // Detail
@@ -136,29 +129,29 @@ func (this *SmartReportController) Detail() {
 	br.ErrMsg = "智能研报已合并到中文研报,请使用中文研报的接口"
 	return
 
-	reportId, _ := this.GetInt("SmartReportId")
-	if reportId <= 0 {
-		br.Msg = "参数有误"
-		br.ErrMsg = "报告ID有误"
-		return
-	}
-
-	ob := new(models.SmartReport)
-	item, e := ob.GetItemById(reportId)
-	if e != nil {
-		if e.Error() == utils.ErrNoRow() {
-			br.Msg = "报告已被删除"
-			return
-		}
-		br.Msg = "操作失败"
-		br.ErrMsg = "获取研报失败, Err: " + e.Error()
-		return
-	}
-	resp := models.FormatSmartReport2Item(item)
-
-	br.Ret = 200
-	br.Msg = "获取成功"
-	br.Data = resp
+	//reportId, _ := this.GetInt("SmartReportId")
+	//if reportId <= 0 {
+	//	br.Msg = "参数有误"
+	//	br.ErrMsg = "报告ID有误"
+	//	return
+	//}
+	//
+	//ob := new(models.SmartReport)
+	//item, e := ob.GetItemById(reportId)
+	//if e != nil {
+	//	if e.Error() == utils.ErrNoRow() {
+	//		br.Msg = "报告已被删除"
+	//		return
+	//	}
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "获取研报失败, Err: " + e.Error()
+	//	return
+	//}
+	//resp := models.FormatSmartReport2Item(item)
+	//
+	//br.Ret = 200
+	//br.Msg = "获取成功"
+	//br.Data = resp
 }
 
 // Approve
@@ -178,107 +171,107 @@ func (this *SmartReportController) Approve() {
 	br.ErrMsg = "智能研报已合并到中文研报,请使用中文研报的接口"
 	return
 
-	var req models.SmartReportApproveReq
-	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
-	if err != nil {
-		br.Msg = "参数解析异常!"
-		br.ErrMsg = "参数解析失败,Err:" + err.Error()
-		return
-	}
-	if req.ReportId <= 0 {
-		br.Msg = "参数错误"
-		br.ErrMsg = fmt.Sprintf("参数有误, SmartReportId: %d", req.ReportId)
-		return
-	}
-
-	ob := new(models.SmartReport)
-	item, e := ob.GetItemById(req.ReportId)
-	if e != nil {
-		if e.Error() == utils.ErrNoRow() {
-			br.Msg = "报告已被删除"
-			return
-		}
-		br.Msg = "操作失败"
-		br.ErrMsg = "获取智能研报失败, Err: " + e.Error()
-		return
-	}
-	if item.State != models.ReportStateWaitApprove {
-		br.Msg = "报告状态有误"
-		br.ErrMsg = fmt.Sprintf("报告状态有误, State: %d", item.State)
-		return
-	}
-	if item.Content == "" {
-		br.Msg = "报告内容为空,请检查内容"
-		return
-	}
-
-	// 校验审批配置
-	confMap, e := models.GetBusinessConf()
-	if e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "获取审批配置失败, Err: " + e.Error()
-		return
-	}
-	if confMap[models.BusinessConfIsReportApprove] != "true" {
-		br.Msg = "未开启审批, 请开启后重新操作"
-		return
-	}
-	if confMap[models.BusinessConfReportApproveType] != models.BusinessConfReportApproveTypeOther {
-		br.Msg = "未开启第三方审批, 请开启后重新操作"
-		return
-	}
-
-	stateMap := map[bool]int{false: models.ReportStateRefused, true: models.ReportStatePass}
-	// 驳回
-	now := time.Now().Local()
-	if !req.Pass {
-		cols := []string{"State", "ModifyTime", "ApproveTime"}
-		item.State = stateMap[req.Pass]
-		item.ModifyTime = now
-		item.ApproveTime = now
-		if e = item.Update(cols); e != nil {
-			br.Msg = "审批失败"
-			br.ErrMsg = "报告审批驳回失败, Err: " + e.Error()
-			return
-		}
-	}
-
-	// 通过审批
-	if req.Pass {
-		cols := []string{"State", "ModifyTime", "ApproveTime", "PublishTime"}
-		item.State = stateMap[req.Pass]
-		item.ModifyTime = now
-		item.ApproveTime = now
-		item.PublishTime = now
-		if e = item.Update(cols); e != nil {
-			br.Msg = "审批失败"
-			br.ErrMsg = "报告审批通过失败, Err: " + e.Error()
-			return
-		}
-
-		// 写入队列
-		var queue models.Report2ImgQueueReq
-		queue.ReportType = 2
-		queue.ReportCode = item.ReportCode
-		_ = utils.Rc.LPush(utils.CACHE_CREATE_REPORT_IMGPDF_QUEUE, queue)
-
-		// 更新报告ES
-		go func() {
-			_ = services.SmartReportElasticUpsert(item.SmartReportId, models.ReportStatePublished)
-		}()
-	}
-
-	// 记录报告变更状态
-	go func() {
-		recordItem := &models.ReportStateRecord{
-			ReportId:   req.ReportId,
-			ReportType: models.ReportTypeSmart,
-			State:      item.State,
-			CreateTime: time.Now(),
-		}
-		_, _ = models.AddReportStateRecord(recordItem)
-	}()
-
-	br.Ret = 200
-	br.Msg = "审批成功"
+	//var req models.SmartReportApproveReq
+	//err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	//if err != nil {
+	//	br.Msg = "参数解析异常!"
+	//	br.ErrMsg = "参数解析失败,Err:" + err.Error()
+	//	return
+	//}
+	//if req.ReportId <= 0 {
+	//	br.Msg = "参数错误"
+	//	br.ErrMsg = fmt.Sprintf("参数有误, SmartReportId: %d", req.ReportId)
+	//	return
+	//}
+	//
+	//ob := new(models.SmartReport)
+	//item, e := ob.GetItemById(req.ReportId)
+	//if e != nil {
+	//	if e.Error() == utils.ErrNoRow() {
+	//		br.Msg = "报告已被删除"
+	//		return
+	//	}
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "获取智能研报失败, Err: " + e.Error()
+	//	return
+	//}
+	//if item.State != models.ReportStateWaitApprove {
+	//	br.Msg = "报告状态有误"
+	//	br.ErrMsg = fmt.Sprintf("报告状态有误, State: %d", item.State)
+	//	return
+	//}
+	//if item.Content == "" {
+	//	br.Msg = "报告内容为空,请检查内容"
+	//	return
+	//}
+	//
+	//// 校验审批配置
+	//confMap, e := models.GetBusinessConf()
+	//if e != nil {
+	//	br.Msg = "操作失败"
+	//	br.ErrMsg = "获取审批配置失败, Err: " + e.Error()
+	//	return
+	//}
+	//if confMap[models.BusinessConfIsReportApprove] != "true" {
+	//	br.Msg = "未开启审批, 请开启后重新操作"
+	//	return
+	//}
+	//if confMap[models.BusinessConfReportApproveType] != models.BusinessConfReportApproveTypeOther {
+	//	br.Msg = "未开启第三方审批, 请开启后重新操作"
+	//	return
+	//}
+	//
+	//stateMap := map[bool]int{false: models.ReportStateRefused, true: models.ReportStatePass}
+	//// 驳回
+	//now := time.Now().Local()
+	//if !req.Pass {
+	//	cols := []string{"State", "ModifyTime", "ApproveTime"}
+	//	item.State = stateMap[req.Pass]
+	//	item.ModifyTime = now
+	//	item.ApproveTime = now
+	//	if e = item.Update(cols); e != nil {
+	//		br.Msg = "审批失败"
+	//		br.ErrMsg = "报告审批驳回失败, Err: " + e.Error()
+	//		return
+	//	}
+	//}
+	//
+	//// 通过审批
+	//if req.Pass {
+	//	cols := []string{"State", "ModifyTime", "ApproveTime", "PublishTime"}
+	//	item.State = stateMap[req.Pass]
+	//	item.ModifyTime = now
+	//	item.ApproveTime = now
+	//	item.PublishTime = now
+	//	if e = item.Update(cols); e != nil {
+	//		br.Msg = "审批失败"
+	//		br.ErrMsg = "报告审批通过失败, Err: " + e.Error()
+	//		return
+	//	}
+	//
+	//	// 写入队列
+	//	var queue models.Report2ImgQueueReq
+	//	queue.ReportType = 2
+	//	queue.ReportCode = item.ReportCode
+	//	_ = utils.Rc.LPush(utils.CACHE_CREATE_REPORT_IMGPDF_QUEUE, queue)
+	//
+	//	// 更新报告ES
+	//	go func() {
+	//		_ = services.SmartReportElasticUpsert(item.SmartReportId, models.ReportStatePublished)
+	//	}()
+	//}
+	//
+	//// 记录报告变更状态
+	//go func() {
+	//	recordItem := &models.ReportStateRecord{
+	//		ReportId:   req.ReportId,
+	//		ReportType: models.ReportTypeSmart,
+	//		State:      item.State,
+	//		CreateTime: time.Now(),
+	//	}
+	//	_, _ = models.AddReportStateRecord(recordItem)
+	//}()
+	//
+	//br.Ret = 200
+	//br.Msg = "审批成功"
 }

+ 29 - 9
go.mod

@@ -1,11 +1,19 @@
 module eta/eta_hub
 
-go 1.19
+go 1.21
+
+toolchain go1.21.7
 
 require (
+	github.com/aliyun/alibaba-cloud-sdk-go v1.63.18
+	github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
+	github.com/aws/aws-sdk-go v1.43.21
 	github.com/beego/bee/v2 v2.0.4
 	github.com/beego/beego/v2 v2.0.7
+	github.com/go-redis/redis/v8 v8.11.5
 	github.com/go-sql-driver/mysql v1.7.1
+	github.com/h2non/filetype v1.1.3
+	github.com/minio/minio-go/v7 v7.0.77
 	github.com/olivere/elastic/v7 v7.0.32
 	github.com/qiniu/qmgo v1.1.8
 	github.com/rdlucklib/rdluck_tools v1.0.3
@@ -17,39 +25,51 @@ require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/garyburd/redigo v1.6.3 // indirect
+	github.com/dustin/go-humanize v1.0.1 // indirect
+	github.com/go-ini/ini v1.67.0 // indirect
 	github.com/go-playground/locales v0.13.0 // indirect
 	github.com/go-playground/universal-translator v0.17.0 // indirect
 	github.com/go-playground/validator/v10 v10.4.1 // indirect
+	github.com/goccy/go-json v0.10.3 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
 	github.com/golang/snappy v0.0.1 // indirect
+	github.com/google/uuid v1.6.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
-	github.com/klauspost/compress v1.13.6 // indirect
+	github.com/json-iterator/go v1.1.12 // indirect
+	github.com/klauspost/compress v1.17.9 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/leodido/go-urn v1.2.0 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
+	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.16.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/common v0.42.0 // indirect
 	github.com/prometheus/procfs v0.10.1 // indirect
 	github.com/rogpeppe/go-internal v1.12.0 // indirect
+	github.com/rs/xid v1.6.0 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect
 	github.com/xdg-go/scram v1.1.2 // indirect
 	github.com/xdg-go/stringprep v1.0.4 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
-	golang.org/x/crypto v0.17.0 // indirect
-	golang.org/x/net v0.10.0 // indirect
-	golang.org/x/sync v0.2.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/crypto v0.26.0 // indirect
+	golang.org/x/net v0.28.0 // indirect
+	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/sys v0.24.0 // indirect
+	golang.org/x/text v0.17.0 // indirect
+	golang.org/x/time v0.6.0 // indirect
 	google.golang.org/protobuf v1.30.0 // indirect
 	gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
+	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	github.com/go-redis/redis/v8 v8.11.5 // indirect
 )

+ 114 - 14
go.sum

@@ -1,12 +1,22 @@
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
 github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
+github.com/aliyun/alibaba-cloud-sdk-go v1.63.18 h1:Q36nROtbIQhLN6VZ4KJzZkISj4SWlq8pEwtqYBNz0is=
+github.com/aliyun/alibaba-cloud-sdk-go v1.63.18/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
+github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
 github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
+github.com/aws/aws-sdk-go v1.43.21 h1:E4S2eX3d2gKJyI/ISrcIrSwXwqjIvCK85gtBMt4sAPE=
+github.com/aws/aws-sdk-go v1.43.21/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
 github.com/beego/bee/v2 v2.0.4 h1:nEjPwxJ8D+cr54eWChJGoGRH7bJ7OQwbhx8rU0OQf7E=
 github.com/beego/bee/v2 v2.0.4/go.mod h1:wq0YrEmPcdNfDNpaUgiTkaW9zso7M8n0HCCShEBOzM0=
 github.com/beego/beego/v2 v2.0.7 h1:9KNnUM40tn3pbCOFfe6SJ1oOL0oTi/oBS/C/wCEdAXA=
@@ -26,21 +36,31 @@ github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h
 github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
 github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
 github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
 github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
+github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
 github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/garyburd/redigo v1.6.3 h1:HCeeRluvAgMusMomi1+6Y5dmFOdYV/JzoRrrbFlkGIc=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -61,7 +81,11 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
+github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -84,32 +108,52 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg=
+github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
+github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
 github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
 github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
@@ -117,21 +161,36 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
+github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
+github.com/minio/minio-go/v7 v7.0.77 h1:GaGghJRg9nwDVlNbwYjSDJT1rqltQkBFDsypWX1v3Bw=
+github.com/minio/minio-go/v7 v7.0.77/go.mod h1:AVM3IUN6WwKzmwBxVdjzhH8xq+f57JSbbvzqvUzR6eg=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
 github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
 github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
+github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
+github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
 github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
@@ -166,6 +225,8 @@ github.com/rdlucklib/rdluck_tools v1.0.3 h1:iOtK2QPlPQ6CL6c1htCk5VnFCHzyG6DCfJtu
 github.com/rdlucklib/rdluck_tools v1.0.3/go.mod h1:9Onw9o4w19C8KE5lxb8GyxgRBbZweRVkQSc79v38EaA=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
+github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
@@ -182,10 +243,16 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
+github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
+github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
+github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
 github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
@@ -204,14 +271,27 @@ github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29Xrm
 go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
 go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
 go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
+go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
+golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
+golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -220,9 +300,10 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
+golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -230,12 +311,13 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
-golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -244,10 +326,12 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -256,13 +340,23 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
+golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
+golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
+gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -281,10 +375,14 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -294,5 +392,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

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

+ 16 - 0
models/business_conf.go

@@ -1,6 +1,7 @@
 package models
 
 import (
+	"eta/eta_hub/utils"
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"html"
@@ -62,3 +63,18 @@ func GetBusinessConfByKey(key string) (item *BusinessConf, err error) {
 	err = o.Raw(sql, key).QueryRow(&item)
 	return
 }
+
+// InitUseMongoConf
+// @Description:
+// @author: Roc
+// @datetime 2024-07-01 13:49:09
+func InitUseMongoConf() {
+	useMongo, e := GetBusinessConfByKey("UseMongo")
+	if e != nil {
+		return
+	}
+
+	if useMongo.ConfVal == `true` {
+		utils.UseMongo = true
+	}
+}

+ 48 - 3
models/data_manage/edb_data.go

@@ -14,9 +14,12 @@ import (
 func GetEdbDataTableName(source, subSource int) (tableName string) {
 	switch source {
 	case utils.DATA_SOURCE_THS:
-		if subSource == utils.DATA_SUB_SOURCE_DATE {
+		switch subSource {
+		case utils.DATA_SUB_SOURCE_DATE:
 			tableName = "edb_data_ths_ds"
-		} else {
+		case utils.DATA_SUB_SOURCE_HIGH_FREQUENCY:
+			tableName = "edb_data_ths_hf"
+		default:
 			tableName = "edb_data_ths"
 		}
 	case utils.DATA_SOURCE_WIND:
@@ -198,9 +201,12 @@ type EdbDataItem struct {
 
 func (m *EdbData) GetItemsBySourceAndCode(source, subSource int, edbCode, startDate string, fieldArr []string, orderRule string) (items []*EdbData, err error) {
 	// 自有数据需要额外处理(从mongo获取)
-	if source == utils.DATA_SOURCE_BUSINESS {
+	if source == utils.DATA_SOURCE_BUSINESS && utils.UseMongo {
 		return m.getEdbDataListByMongo(source, subSource, edbCode, startDate, "", fieldArr, orderRule)
 	}
+	if source == utils.DATA_SOURCE_THS && subSource == utils.DATA_SUB_SOURCE_HIGH_FREQUENCY && utils.UseMongo {
+		return m.getThsHfEdbDataListByMongo(source, subSource, edbCode, startDate, "", fieldArr, orderRule)
+	}
 
 	return m.getItemsBySourceAndCodeByMysql(source, subSource, edbCode, startDate, fieldArr, orderRule)
 }
@@ -293,3 +299,42 @@ func FormatEdbData2Item(origin *EdbData) (item *EdbDataItem) {
 	item.UpdateTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
 	return
 }
+
+func (m *EdbData) getThsHfEdbDataListByMongo(source, subSource int, edbCode, startDate, endDate string, fieldArr []string, orderRule string) (list []*EdbData, err error) {
+	list = make([]*EdbData, 0)
+
+	mogDataObj := mgo.EdbDataThsHf{}
+	// 构建查询条件
+	queryConditions := bson.M{
+		"edb_code": edbCode,
+	}
+	// 数据日期
+	dateCondition, err := mgo.BuildDateCondition(startDate, endDate)
+	if err != nil {
+		return
+	}
+	if len(dateCondition) > 0 {
+		queryConditions["data_time"] = dateCondition
+	}
+
+	// 获取列表数据
+	tmpDataList, tmpErr := mogDataObj.GetAllDataList(queryConditions, []string{"data_time"})
+	if tmpErr != nil {
+		err = tmpErr
+		return
+	}
+	for k, v := range tmpDataList {
+		list = append(list, &EdbData{
+			EdbDataId:     k + 1,
+			EdbInfoId:     v.EdbInfoId,
+			EdbCode:       v.EdbCode,
+			DataTime:      v.DataTime,
+			Value:         v.Value,
+			CreateTime:    v.CreateTime,
+			ModifyTime:    v.ModifyTime,
+			DataTimestamp: v.DataTimestamp,
+		})
+	}
+
+	return
+}

+ 12 - 1
models/db.go

@@ -48,6 +48,17 @@ func init() {
 		new(report.ReportChapterPermissionMapping), // 报告章节的权限关系表
 	)
 
-	// 初始化指标来源
+	afterInitTable()
+}
+
+// afterInitTable
+// @Description: 初始化表结构的的后置操作
+// @author: Roc
+// @datetime 2024-07-01 13:31:09
+func afterInitTable() {
+	// 初始化指标来源配置
 	data_manage.InitEdbSource()
+
+	// 初始化是否启用mongo配置
+	InitUseMongoConf()
 }

+ 57 - 0
models/document_manage_model/outside_report.go

@@ -0,0 +1,57 @@
+// @Author gmy 2024/9/19 14:53:00
+package document_manage_model
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
+)
+
+type OutsideReport struct {
+	OutsideReportId  int    `orm:"column(outside_report_id);pk" description:"外部报告ID"`
+	Source           int    `orm:"column(source)" description:"来源,1:ETA系统录入;2:API接口录入;3:邮件监听录入"`
+	Title            string `orm:"column(title)" description:"报告标题"`
+	Abstract         string `orm:"column(abstract)" description:"摘要"`
+	ClassifyId       int    `orm:"column(classify_id)" description:"所属分类id"`
+	ClassifyName     string `orm:"column(classify_name)" description:"所属分类名称(整个分类链条)"`
+	Content          string `orm:"column(content)" description:"报告富文本内容"`
+	SysUserId        int    `orm:"column(sys_user_id)" description:"创建人id"`
+	SysUserName      string `orm:"column(sys_user_name)" description:"创建人姓名"`
+	EmailMessageUid  int    `orm:"column(email_message_uid)" description:"该邮件在邮箱中的唯一id"`
+	ReportUpdateTime string `orm:"column(report_update_time)" description:"报告更新时间,如果来源于邮件,那么取邮件的收件时间"`
+	ModifyTime       string `orm:"column(modify_time)" description:"最近一次修改时间"`
+	CreateTime       string `orm:"column(create_time)" description:"创建时间"`
+	ReportCode       string `orm:"column(report_code)" description:"报告唯一编码"`
+}
+
+type OutsideReportPage struct {
+	List   []OutsideReport    `description:"报告列表"`
+	Paging *paging.PagingItem `description:"分页数据"`
+}
+
+type OutsideReportBO struct {
+	OutsideReportId int    `orm:"column(outside_report_id);pk" description:"外部报告ID"`
+	Source          int    `orm:"column(source)" description:"来源,1:ETA系统录入;2:API接口录入;3:邮件监听录入"`
+	Title           string `orm:"column(title)" description:"报告标题"`
+	Abstract        string `orm:"column(abstract)" description:"摘要"`
+	ClassifyId      int    `orm:"column(classify_id)" description:"所属分类id"`
+	ClassifyName    string `orm:"column(classify_name)" description:"所属分类名称(整个分类链条)"`
+	Content         string `orm:"column(content)" description:"报告富文本内容"`
+	SysUserId       int    `orm:"column(sys_user_id)" description:"创建人id"`
+	SysUserName     string `orm:"column(sys_user_name)" description:"创建人姓名"`
+	ReportCode      string `orm:"column(report_code)" description:"报告唯一编码"`
+	AuthCode        string `orm:"column(auth_code)" description:"报告权限编码"`
+	UserName        string `description:"用户名称"`
+	AttachmentList  []*OutsideReportAttachment
+}
+
+// 在 init 函数中注册模型
+func init() {
+	orm.RegisterModel(new(OutsideReport))
+}
+
+// SaveOutsideReport 保存报告
+func SaveOutsideReport(outsideReport OutsideReport) (id int64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	id, err = o.Insert(&outsideReport)
+	return
+}

+ 26 - 0
models/document_manage_model/outside_report_attachment.go

@@ -0,0 +1,26 @@
+// @Author gmy 2024/9/19 15:13:00
+package document_manage_model
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+)
+
+type OutsideReportAttachment struct {
+	OutsideReportAttachmentId int    `orm:"column(outside_report_attachment_id);pk" description:"外部报告附件ID"`
+	OutsideReportId           int    `orm:"column(outside_report_id)" description:"报告id"`
+	Title                     string `orm:"column(title)" description:"附件名称"`
+	Url                       string `orm:"column(url)" description:"附件地址"`
+	CreateTime                string `orm:"column(create_time)" description:"附件新增时间"`
+	FileSize                  int64  `orm:"column(file_size)" description:"附件大小"`
+}
+
+// 在 init 函数中注册模型
+func init() {
+	orm.RegisterModel(new(OutsideReportAttachment))
+}
+
+// SaveOutsideReportAttachment 保存附件
+func SaveOutsideReportAttachment(attachment *OutsideReportAttachment) (int64, error) {
+	o := orm.NewOrmUsingDB("rddp")
+	return o.Insert(attachment)
+}

+ 510 - 0
models/mgo/edb_data_ths_hf.go

@@ -0,0 +1,510 @@
+package mgo
+
+import (
+	"context"
+	"errors"
+	"eta/eta_hub/utils"
+	"fmt"
+	"github.com/qiniu/qmgo"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"time"
+)
+
+// EdbDataThsHf
+// @Description: 同花顺高频集合(指标库)
+type EdbDataThsHf struct {
+	ID            primitive.ObjectID `json:"_id" bson:"_id,omitempty" `            // 文档id
+	EdbInfoId     int                `json:"edb_info_id" bson:"edb_info_id"`       // 指标ID
+	EdbCode       string             `json:"edb_code" bson:"edb_code"`             // 指标编码
+	DataTime      time.Time          `json:"data_time" bson:"data_time"`           // 数据日期
+	Value         float64            `json:"value" bson:"value"`                   // 数据值
+	CreateTime    time.Time          `json:"create_time" bson:"create_time"`       // 创建时间
+	ModifyTime    time.Time          `json:"modify_time" bson:"modify_time"`       // 修改时间
+	DataTimestamp int64              `json:"data_timestamp" bson:"data_timestamp"` // 数据日期时间戳
+}
+
+// CollectionName
+// @Description:  获取集合名称
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:36
+// @return string
+func (m *EdbDataThsHf) CollectionName() string {
+	return "edb_data_ths_hf"
+}
+
+// DataBaseName
+// @Description: 获取数据库名称
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:33
+// @return string
+func (m *EdbDataThsHf) DataBaseName() string {
+	return utils.MgoDataDbName
+}
+
+// GetCollection
+// @Description: 获取mongodb集合的句柄
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:41:33
+// @return string
+func (m *EdbDataThsHf) GetCollection() *qmgo.Collection {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	return db.Collection(m.CollectionName())
+}
+
+// GetItem
+// @Description: 根据条件获取单条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-09 10:00:49
+// @param whereParams interface{}
+// @return item *EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetItem(whereParams interface{}) (item *EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.GetItemByColl(coll, whereParams)
+}
+
+// GetItemByColl
+// @Description: 根据条件获取单条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-09 13:22:06
+// @param coll *qmgo.Collection
+// @param whereParams interface{}
+// @return item *EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetItemByColl(coll *qmgo.Collection, whereParams interface{}) (item *EdbDataThsHf, err error) {
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).One(&item)
+	if err != nil {
+		return
+	}
+
+	item.DataTime = item.DataTime.In(time.Local)
+	item.CreateTime = item.CreateTime.In(time.Local)
+	item.ModifyTime = item.ModifyTime.In(time.Local)
+
+	return
+}
+
+// GetAllDataList
+// @Description: 根据条件获取所有数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 13:42:19
+// @param whereParams interface{}
+// @param sort []string
+// @return result []EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetAllDataList(whereParams interface{}, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetLimitDataList
+// @Description: 根据条件获取指定数量数据列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-06 17:08:32
+// @param whereParams interface{}
+// @param size int64
+// @param sort []string
+// @return result []*BaseFromBusinessData
+// @return err error
+func (m *EdbDataThsHf) GetLimitDataList(whereParams interface{}, size int64, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).Limit(size).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetPageDataList
+// @Description: 根据条件获取分页数据列表
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-07 10:21:07
+// @param whereParams interface{}
+// @param startSize int64
+// @param size int64
+// @param sort []string
+// @return result []*EdbDataThsHf
+// @return err error
+func (m *EdbDataThsHf) GetPageDataList(whereParams interface{}, startSize, size int64, sort []string) (result []*EdbDataThsHf, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Find(ctx, whereParams).Sort(sort...).Skip(startSize).Limit(size).All(&result)
+	if err != nil {
+		return
+	}
+
+	for _, v := range result {
+		v.DataTime = v.DataTime.In(time.Local)
+		v.CreateTime = v.CreateTime.In(time.Local)
+		v.ModifyTime = v.ModifyTime.In(time.Local)
+	}
+
+	return
+}
+
+// GetCountDataList
+// @Description:  根据条件获取数据列表总数
+// @author: Roc
+// @receiver m
+// @datetime 2024-05-07 10:29:00
+// @param whereParams interface{}
+// @return count int64
+// @return err error
+func (m *EdbDataThsHf) GetCountDataList(whereParams interface{}) (count int64, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	count, err = coll.Find(ctx, whereParams).Count()
+
+	return
+}
+
+// InsertDataByColl
+// @Description: 写入单条数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param addData interface{}
+// @return err error
+func (m *EdbDataThsHf) InsertDataByColl(coll *qmgo.Collection, addData interface{}) (err error) {
+	ctx := context.TODO()
+	_, err = coll.InsertOne(ctx, addData)
+	if err != nil {
+		fmt.Println("InsertDataByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// BatchInsertData
+// @Description: 批量写入数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param bulk int 每次请求保存的数据量
+// @param dataList []interface{}
+// @return err error
+func (m *EdbDataThsHf) BatchInsertData(bulk int, dataList []interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.BatchInsertDataByColl(coll, bulk, dataList)
+}
+
+// BatchInsertDataByColl
+// @Description: 批量写入数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 14:22:18
+// @param coll *qmgo.Collection
+// @param bulk int 每次请求保存的数据量
+// @param dataList []interface{}
+// @return err error
+func (m *EdbDataThsHf) BatchInsertDataByColl(coll *qmgo.Collection, bulk int, dataList []interface{}) (err error) {
+	ctx := context.TODO()
+	dataNum := len(dataList)
+	if dataNum <= 0 {
+		return
+	}
+
+	// 不设置每次保存切片数量大小,或者实际数据量小于设置的切片数量大小,那么就直接保存吧
+	if bulk <= 0 || dataNum <= bulk {
+		_, err = coll.InsertMany(ctx, dataList)
+		if err != nil {
+			fmt.Println("BatchInsertData:Err:" + err.Error())
+			return
+		}
+		return
+	}
+
+	// 分批保存
+	i := 0
+	tmpAddDataList := make([]interface{}, 0)
+	for _, v := range dataList {
+		tmpAddDataList = append(tmpAddDataList, v)
+		i++
+		if i >= bulk {
+			_, err = coll.InsertMany(ctx, tmpAddDataList)
+			if err != nil {
+				fmt.Println("BatchInsertData:Err:" + err.Error())
+				return
+			}
+			i = 0
+			tmpAddDataList = make([]interface{}, 0)
+		}
+	}
+
+	if len(tmpAddDataList) > 0 {
+		_, err = coll.InsertMany(ctx, tmpAddDataList)
+		if err != nil {
+			fmt.Println("BatchInsertData:Err:" + err.Error())
+			return
+		}
+	}
+
+	return
+}
+
+// UpdateData
+// @Description: 单条数据修改
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 15:01:51
+// @param whereParams interface{}
+// @param updateParams interface{}
+// @return err error
+func (m *EdbDataThsHf) UpdateData(whereParams, updateParams interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.UpdateDataByColl(coll, whereParams, updateParams)
+}
+
+// UpdateDataByColl
+// @Description: 单条数据修改(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-26 15:01:51
+// @param whereParams interface{}
+// @param updateParams interface{}
+// @return err error
+func (m *EdbDataThsHf) UpdateDataByColl(coll *qmgo.Collection, whereParams, updateParams interface{}) (err error) {
+	ctx := context.TODO()
+	err = coll.UpdateOne(ctx, whereParams, updateParams)
+	if err != nil {
+		fmt.Println("UpdateDataByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// RemoveMany
+// @Description: 根据条件删除多条数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 13:17:02
+// @param whereParams interface{}
+// @return err error
+func (m *EdbDataThsHf) RemoveMany(whereParams interface{}) (err error) {
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+
+	return m.RemoveManyByColl(coll, whereParams)
+}
+
+// RemoveManyByColl
+// @Description: 根据条件删除多条数据(外部传入集合)
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 13:18:42
+// @param coll *qmgo.Collection
+// @param whereParams interface{}
+// @return err error
+func (m *EdbDataThsHf) RemoveManyByColl(coll *qmgo.Collection, whereParams interface{}) (err error) {
+	ctx := context.TODO()
+	_, err = coll.RemoveAll(ctx, whereParams)
+	if err != nil {
+		fmt.Println("RemoveManyByColl:Err:" + err.Error())
+		return
+	}
+
+	return
+}
+
+// HandleData
+// @Description: 事务处理数据
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 10:39:01
+// @param addDataList []AddEdbDataThsHf
+// @param updateDataList []EdbDataThsHf
+// @return result interface{}
+// @return err error
+func (m *EdbDataThsHf) HandleData(addDataList, updateDataList []EdbDataThsHf) (result interface{}, err error) {
+
+	ctx := context.TODO()
+
+	callback := func(sessCtx context.Context) (interface{}, error) {
+		// 重要:确保事务中的每一个操作,都使用传入的sessCtx参数
+
+		db := utils.MgoDataCli.Database(m.DataBaseName())
+		coll := db.Collection(m.CollectionName())
+
+		// 插入数据
+		if len(addDataList) > 0 {
+			_, err = coll.InsertMany(sessCtx, addDataList)
+			if err != nil {
+				return nil, err
+			}
+		}
+
+		// 修改
+
+		if len(updateDataList) > 0 {
+			for _, v := range updateDataList {
+				err = coll.UpdateOne(ctx, bson.M{"_id": v.ID}, bson.M{"$set": bson.M{"value": v.Value, "modify_time": v.ModifyTime}})
+				if err != nil {
+					fmt.Println("BatchInsertData:Err:" + err.Error())
+					return nil, err
+				}
+			}
+		}
+
+		return nil, nil
+	}
+	result, err = utils.MgoDataCli.DoTransaction(ctx, callback)
+
+	return
+}
+
+// EdbInfoMaxAndMinInfo 指标最新数据记录结构体
+//type EdbInfoMaxAndMinInfo struct {
+//	MinDate     time.Time `description:"最小日期" bson:"min_date"`
+//	MaxDate     time.Time `description:"最大日期" bson:"max_date"`
+//	MinValue    float64   `description:"最小值" bson:"min_value"`
+//	MaxValue    float64   `description:"最大值" bson:"max_value"`
+//	LatestValue float64   `description:"最新值" bson:"latest_value"`
+//	LatestDate  time.Time `description:"实际数据最新日期" bson:"latest_date"`
+//	EndValue    float64   `description:"最新值" bson:"end_value"`
+//}
+
+// GetEdbInfoMaxAndMinInfo
+// @Description: 获取当前指标的最大最小值
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 17:15:39
+// @param whereParams interface{}
+// @return result EdbInfoMaxAndMinInfo
+// @return err error
+func (m *EdbDataThsHf) GetEdbInfoMaxAndMinInfo(whereParams interface{}) (result EdbInfoMaxAndMinInfo, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+	err = coll.Aggregate(ctx, whereParams).One(&result)
+	if err != nil {
+		return
+	}
+	result.MinDate = result.MinDate.In(time.Local)
+	result.MaxDate = result.MaxDate.In(time.Local)
+	result.LatestDate = result.LatestDate.In(time.Local)
+
+	return
+}
+
+// LatestValue 指标最新数据记录结构体
+//type LatestValue struct {
+//	Value float64 `description:"值" bson:"value"`
+//}
+
+// GetLatestValue
+// @Description: 获取当前指标的最新数据记录
+// @author: Roc
+// @receiver m
+// @datetime 2024-04-30 17:16:15
+// @param whereParams interface{}
+// @param selectParam interface{}
+// @return latestValue LatestValue
+// @return err error
+func (m *EdbDataThsHf) GetLatestValue(whereParams, selectParam interface{}) (latestValue LatestValue, err error) {
+	if utils.MgoDataCli == nil {
+		err = errors.New("mongodb连接失败")
+		return
+	}
+	db := utils.MgoDataCli.Database(m.DataBaseName())
+	coll := db.Collection(m.CollectionName())
+	ctx := context.TODO()
+	if err != nil {
+		fmt.Println("MgoGetColl Err:", err.Error())
+		return
+	}
+
+	//var result interface{}
+	//err = coll.Find(ctx, whereParams).Select(selectParam).One(&result)
+	err = coll.Find(ctx, whereParams).Select(selectParam).One(&latestValue)
+	return
+}

+ 69 - 0
models/resource.go

@@ -0,0 +1,69 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type Resource struct {
+	Id           int       `orm:"column(id);" description:"资源id"`
+	ResourceUrl  string    `description:"资源地址"`
+	CreateTime   time.Time `description:"创建时间"`
+	ResourceType int       `description:"资源类型,1:图片,2:音频,3:视频 ,4:ppt"`
+}
+
+type ResourceResp struct {
+	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) {
+	o := orm.NewOrmUsingDB("rddp")
+
+	sql := "INSERT INTO resource(resource_url,create_time,resource_type) VALUES(?,?,?)"
+	res, err := o.Raw(sql, item.ResourceUrl, item.CreateTime, item.ResourceType).Exec()
+	if err != nil {
+		return 0, err
+	}
+	newId, err = res.LastInsertId()
+	if err != nil {
+		return 0, err
+	}
+
+	return newId, err
+}
+
+func GetResourceById(id string) (item *Resource, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := "SELECT * FROM resource WHERE id=? "
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+type ResourceBase64Resp struct {
+	Image string `description:"图片,base64字符串"`
+}
+
+type PptResourceResp struct {
+	Id          int64    `orm:"column(id);" description:"用户id"`
+	ResourceUrl []string `description:"资源地址"`
+	PlaySeconds uint32   `description:"播放时长,单位秒"`
+}
+
+type ImageSvgToPngResp struct {
+	Data struct {
+		ResourceURL string `json:"ResourceUrl"`
+	} `json:"Data"`
+	ErrCode     string `json:"ErrCode"`
+	ErrMsg      string `json:"ErrMsg"`
+	IsSendEmail bool   `json:"IsSendEmail"`
+	Msg         string `json:"Msg"`
+	Ret         int64  `json:"Ret"`
+	Success     bool   `json:"Success"`
+}

+ 14 - 0
models/system/sys_user.go

@@ -1,6 +1,7 @@
 package system
 
 import (
+	"eta/eta_hub/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -98,6 +99,19 @@ func GetSysUserByAdminName(adminName string) (item *AdminItem, err error) {
 	return
 }
 
+// GetUserByAdminName 根据系统用户名获取用户信息
+func GetUserByAdminName(adminName string) (item *AdminItem, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM admin WHERE admin_name = ? LIMIT 1`
+	err = o.Raw(sql, adminName).QueryRow(&item)
+
+	if err != nil && err.Error() == utils.ErrNoRow() {
+		return nil, nil
+	}
+
+	return item, err
+}
+
 type UserCheckResp struct {
 	IsUser    bool
 	AdminInfo *AdminItem

+ 18 - 0
routers/commentsRouter.go

@@ -223,6 +223,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_hub/controllers:OutsideReportController"] = append(beego.GlobalControllerRouter["eta/eta_hub/controllers:OutsideReportController"],
+        beego.ControllerComments{
+            Method: "DocumentSave",
+            Router: `/document/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_hub/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_hub/controllers:ReportController"],
         beego.ControllerComments{
             Method: "Approve",
@@ -268,6 +277,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_hub/controllers:ResourceDealWithController"] = append(beego.GlobalControllerRouter["eta/eta_hub/controllers:ResourceDealWithController"],
+        beego.ControllerComments{
+            Method: "FileUpload",
+            Router: `/file/upload`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_hub/controllers:SmartReportController"] = append(beego.GlobalControllerRouter["eta/eta_hub/controllers:SmartReportController"],
         beego.ControllerComments{
             Method: "Approve",

+ 10 - 0
routers/router.go

@@ -73,6 +73,16 @@ func init() {
 				&controllers.SysAdminController{},
 			),
 		),
+		web.NSNamespace("/document_manage",
+			web.NSInclude(
+				&controllers.OutsideReportController{},
+			),
+		),
+		web.NSNamespace("/resource_deal_with",
+			web.NSInclude(
+				&controllers.ResourceDealWithController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 162 - 0
services/aws_s3.go

@@ -0,0 +1,162 @@
+package services
+
+import (
+	"bytes"
+	"crypto/tls"
+	"eta/eta_hub/utils"
+	"fmt"
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/credentials"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/s3"
+	"io/ioutil"
+	"net/http"
+	"time"
+)
+
+type OssClient interface {
+	UploadFile(string, string, string) (string, error)
+	GetUploadToken() (OssToken, error)
+}
+
+func NewOssClient() OssClient {
+	switch utils.ObjectStorageClient {
+	case utils.STORAGESOURCE_MINIO_NAME:
+		return new(MinioOss)
+	case utils.STORAGESOURCE_S3_NAME:
+		return new(S3Oss)
+	default:
+		// 默认使用阿里云OSS
+		return new(AliOss)
+	}
+}
+
+// OssToken 此处为了兼容前端那边所以有重复的
+type OssToken struct {
+	AccessKeyId string
+	SecretKeyId string
+	RegionId    string
+	Bucketname  string
+	Endpoint    string
+	ImgHost     string
+	UseSSL      string
+	Port        string
+	//AccessKeyId     string
+	AccessKeySecret string
+	SecurityToken   string
+	ExpiredTime     string
+	//RegionId        string
+	//Bucketname      string
+	//Endpoint        string
+	Imghost      string
+	S3ForceStyle bool
+	S3Protocol   string
+}
+
+type S3Oss struct{}
+
+func (m *S3Oss) UploadFile(fileName, localFile, savePath string) (resourceUrl string, err error) {
+	defer func() {
+		if err != nil {
+			fmt.Println(err.Error())
+		}
+	}()
+
+	// 默认使用后端这个, 这里有两个配置的原因是
+	// 前端上传跨域问题可能会使用反向代理来解决, 这样的话同一个endpoint就会导致一端正常另一端不正常
+	endpoint := utils.S3BackEndpoint
+	if endpoint == "" {
+		endpoint = utils.S3Endpoint
+	}
+	accessKey := utils.S3AccessKeyId
+	secretKey := utils.S3AccessKeySecret
+	region := utils.S3Region
+	bucketName := utils.S3BucketName
+	uploadDir := utils.S3UploadDir
+	resourceHost := utils.S3Host
+	forceStyle := utils.S3ForceStyle
+	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
+	if forceStyle == "false" {
+		hostStyle = false
+	}
+	disableSSL := true // 默认true, 跳过SSL
+	if utils.S3DisableSSL == "false" {
+		disableSSL = false
+	}
+	//fmt.Println("disableSSL: ", disableSSL)
+
+	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
+	}
+
+	// 创建S3服务客户端
+	client := s3.New(sess)
+
+	// 读取文件内容
+	fileContent, e := ioutil.ReadFile(localFile)
+	if e != nil {
+		err = fmt.Errorf("read file err: %s", e.Error())
+		return
+	}
+
+	path := savePath
+	if savePath == "" {
+		path = uploadDir + time.Now().Format("200601/20060102/") + fileName
+	}
+	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
+}
+
+func (m *S3Oss) GetUploadToken() (token OssToken, err error) {
+	token.Endpoint = utils.S3Endpoint
+	token.AccessKeyId = utils.S3AccessKeyId
+	token.AccessKeySecret = utils.S3AccessKeySecret
+	token.RegionId = utils.S3Region
+	token.Bucketname = utils.S3BucketName
+	token.ImgHost = utils.S3Host
+	token.Port = utils.S3EndpointPort
+	hostStyle := true // 默认true, 使用`endpoint/bucket_name`这种HOST格式
+	if utils.S3ForceStyle == "false" {
+		hostStyle = false
+	}
+	token.S3ForceStyle = hostStyle
+	token.S3Protocol = utils.S3Protocol
+	return
+}

+ 50 - 0
services/document_manage_service/document_manage_service.go

@@ -0,0 +1,50 @@
+// @Author gmy 2024/9/19 16:45:00
+package document_manage_service
+
+import (
+	"eta/eta_hub/models/document_manage_model"
+	"eta/eta_hub/utils"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/google/uuid"
+)
+
+func DocumentSave(outsideReport *document_manage_model.OutsideReportBO) error {
+	logs.Info("DocumentSave")
+
+	// 保存报告
+	report := document_manage_model.OutsideReport{
+		Source:           outsideReport.Source,
+		Title:            outsideReport.Title,
+		Abstract:         outsideReport.Abstract,
+		ClassifyId:       outsideReport.ClassifyId,
+		ClassifyName:     outsideReport.ClassifyName,
+		Content:          outsideReport.Content,
+		SysUserId:        outsideReport.SysUserId,
+		SysUserName:      outsideReport.SysUserName,
+		ReportUpdateTime: utils.GetCurrentTime(),
+		ModifyTime:       utils.GetCurrentTime(),
+		CreateTime:       utils.GetCurrentTime(),
+		ReportCode:       uuid.New().String(),
+	}
+	id, err := document_manage_model.SaveOutsideReport(report)
+	if err != nil {
+		return err
+	}
+
+	// 保存附件
+	attachmentList := outsideReport.AttachmentList
+	if len(attachmentList) > 0 {
+		for _, attachment := range attachmentList {
+			if attachment.Title == "" || attachment.Url == "" {
+				continue
+			}
+			attachment.OutsideReportId = int(id)
+			attachment.CreateTime = utils.GetCurrentTime()
+			_, err := document_manage_model.SaveOutsideReportAttachment(attachment)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return err
+}

+ 461 - 0
services/minio.go

@@ -0,0 +1,461 @@
+package services
+
+import (
+	"context"
+	"errors"
+	"eta/eta_hub/utils"
+	"fmt"
+	"github.com/minio/minio-go/v7"
+	"github.com/minio/minio-go/v7/pkg/credentials"
+	"log"
+	"time"
+)
+
+//func GetMinIOSTSToken() (item *Token, err error) {
+//	// MinIO服务的访问信息
+//	item = new(Token)
+//	//useSSL := false
+//	//if utils.MinIoUseSSL == "true" {
+//	//	useSSL = true
+//	//}
+//	// 创建MinIO客户端
+//	//minioClient, err := minio.New(utils.MinIoEndpoint, &minio.Options{
+//	//	Creds:  credentials.NewStaticV4(utils.MinIoAccessKeyId, utils.MinIoAccessKeySecret, ""),
+//	//	Secure: useSSL,
+//	//})
+//	//if err != nil {
+//	//	return nil, err
+//	//}
+//	// 设置STS凭证请求参数
+//	//policy := `{
+//	//    "Version": "2012-10-17",
+//	//    "Statement": [
+//	//        {
+//	//            "Sid": "",
+//	//            "Effect": "Allow",
+//	//            "Principal": {"AWS": "arn:aws:iam::1234567890:root"},
+//	//            "Action": "s3:GetObject",
+//	//            "Resource": "arn:aws:s3:::<YourBucketName>/*"
+//	//        }
+//	//    ]
+//	//}`
+//	//expiry := time.Hour * 24 // STS凭证的过期时间
+//	//获取STS凭证
+//	//stsCredentials, err := minioClient.PresignedPutObject(context.Background(), "etastatic", "myobject", expiry)
+//	//if err != nil {
+//	//	return
+//	//}
+//	item.AccessKeyId = utils.MinIoAccessKeyId
+//	item.SecretKeyId = utils.MinIoAccessKeySecret
+//	item.Endpoint = utils.MinIoEndpoint
+//	item.ImgHost = utils.MinIoImghost
+//	item.Bucketname = utils.MinIoBucketname
+//	item.UseSSL = utils.MinIoUseSSL
+//	item.RegionId = utils.MinIoRegion
+//	item.Port = utils.MinIoPort
+//	return
+//}
+
+//type Token struct {
+//	AccessKeyId string
+//	SecretKeyId string
+//	RegionId    string
+//	Bucketname  string
+//	Endpoint    string
+//	ImgHost     string
+//	UseSSL      string
+//	Port        string
+//}
+
+//func UploadMinIo() {
+//	ctx := context.Background()
+//	endpoint := "8.136.199.33:9000/"
+//	accessKeyID := "LfQ8uiJiLP7vLxjRrmNW"
+//	secretAccessKey := "IszGVHsNicJMQxHC46cYFtbrOiapo0ynwOIJ6c2R"
+//	useSSL := false
+//
+//	// Initialize minio client object.
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//	}
+//
+//	// Make a new bucket called mymusic.
+//	bucketName := "etastatic"
+//	location := "/"
+//
+//	err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: location})
+//	if err != nil {
+//		// Check to see if we already own this bucket (which happens if you run this twice)
+//		exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//		if errBucketExists == nil && exists {
+//			log.Printf("We already own %s\n", bucketName)
+//		} else {
+//			log.Fatalln(err)
+//		}
+//	} else {
+//		log.Printf("Successfully created %s\n", bucketName)
+//	}
+//	//buckets, err := minioClient.ListBuckets(ctx)
+//	//for _, bucket := range buckets {
+//	//	fmt.Println(bucket)
+//	//}
+//	// Upload the zip file
+//	objectName := "1111.xlsx"
+//	filePath := "/Users/xi/Desktop/1111.xlsx"
+//	contentType := "application/xlsx"
+//
+//	// Upload the zip file with FPutObject
+//	info, err := minioClient.FPutObject(ctx, bucketName, objectName, filePath, minio.PutObjectOptions{ContentType: contentType})
+//	if err != nil {
+//		log.Fatalln(err)
+//	}
+//
+//	log.Printf("Successfully uploaded %s of size %d\n", objectName, info.Size)
+//}
+
+// UploadImgToMinIo 图片上传
+//func UploadImgToMinIo(fileName, filePath string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	path := utils.MinIoUploadDir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
+
+// UploadAudioToMinIo 音频上传
+//func UploadAudioToMinIo(fileName, filePath string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//
+//	path := utils.MinIoUpload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
+
+// UploadVideoToMinIo 视频上传
+//func UploadVideoToMinIo(filename, filePath, savePath string) error {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return errors.New("MinIo信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filePath)
+//	}()
+//
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return err
+//	}
+//
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
+
+// UploadFileToMinIo 上传文件
+//func UploadFileToMinIo(filename, filePath, savePath string) error {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return errors.New("MinIo信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filePath)
+//	}()
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, savePath, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
+
+// UploadMinIoToDir 上传至hzchart
+//func UploadMinIoToDir(filename, filePath, uploadDir, fileDir string) (string, error) {
+//	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+//		return "0", errors.New("MinIo信息未配置")
+//	}
+//	ctx := context.Background()
+//	endpoint := utils.MinIoEndpoint
+//	accessKeyID := utils.MinIoAccessKeyId
+//	secretAccessKey := utils.MinIoAccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.MinIoBucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	if uploadDir == "" {
+//		uploadDir = utils.MinIoUploadDir
+//	}
+//	if fileDir == "" {
+//		fileDir = time.Now().Format("200601/20060102/")
+//	}
+//	path := uploadDir + fileDir
+//	path += filename
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//	path = utils.MinIoImghost + path
+//	return path, err
+//}
+
+//func UploadImgToMinIoTest(fileName, filePath string) (string, error) {
+//	ctx := context.Background()
+//	endpoint := utils.Endpoint
+//	accessKeyID := utils.AccessKeyId
+//	secretAccessKey := utils.AccessKeySecret
+//	useSSL := false
+//	if utils.MinIoUseSSL == "true" {
+//		useSSL = true
+//	}
+//	minioClient, err := minio.New(endpoint, &minio.Options{
+//		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+//		Secure: useSSL,
+//	})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "1", err
+//	}
+//	bucketName := utils.Bucketname
+//	// Check to see if we already own this bucket (which happens if you run this twice)
+//
+//	buckets, e := minioClient.ListBuckets(ctx)
+//	if e != nil {
+//		fmt.Println("ListBuckets: ", e.Error())
+//		return "", e
+//	}
+//	for k := range buckets {
+//		fmt.Println(k)
+//	}
+//
+//	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+//	fmt.Println("exists: ", exists)
+//	fmt.Println("errBucketExists: ", errBucketExists)
+//	if errBucketExists == nil && exists {
+//		log.Printf("We already own %s\n", bucketName)
+//	} else {
+//		log.Fatalln(err)
+//		return "2", err
+//	}
+//	path := utils.UploadDir + time.Now().Format("200601/20060102/")
+//	path += fileName
+//	// Upload the zip file with FPutObject
+//	//contentType := "application/xlsx"
+//	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+//	if err != nil {
+//		log.Fatalln(err)
+//		return "3", err
+//	}
+//
+//	path = utils.Imghost + path
+//	return path, err
+//}
+
+type MinioOss struct{}
+
+// UploadFile 上传文件
+func (m *MinioOss) UploadFile(fileName, filePath, savePath string) (string, error) {
+	if utils.MinIoAccessKeyId == `` || utils.MinIoAccessKeySecret == `` {
+		return "0", errors.New("MinIo信息未配置")
+	}
+
+	ctx := context.Background()
+	// 此处兼容一下前后端endpoint不一致的情况, 前端用minio_endpoint后端用minio_back_endpoint, minio_back_endpoint为空则都取前者
+	endpoint := utils.MinIoEndpoint
+	if utils.MinIoBackEndpoint != "" {
+		endpoint = utils.MinIoBackEndpoint
+	}
+	accessKeyID := utils.MinIoAccessKeyId
+	secretAccessKey := utils.MinIoAccessKeySecret
+	useSSL := false
+	if utils.MinIoUseSSL == "true" {
+		useSSL = true
+	}
+	minioClient, err := minio.New(endpoint, &minio.Options{
+		Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
+		Secure: useSSL,
+	})
+	if err != nil {
+		log.Fatalln(err)
+		return "1", err
+	}
+	bucketName := utils.MinIoBucketname
+	exists, errBucketExists := minioClient.BucketExists(ctx, bucketName)
+	if errBucketExists != nil || !exists {
+		err = fmt.Errorf("BucketExists: %v; err: %v", exists, errBucketExists)
+		return "2", err
+	}
+
+	path := savePath
+	if savePath == "" {
+		path = utils.MinIoUploadDir + time.Now().Format("200601/20060102/") + fileName
+	}
+	_, err = minioClient.FPutObject(ctx, bucketName, path, filePath, minio.PutObjectOptions{})
+	if err != nil {
+		log.Fatalln(err)
+		return "3", err
+	}
+	resourceUrl := utils.MinIoImghost + path
+	return resourceUrl, err
+}
+
+func (m *MinioOss) GetUploadToken() (token OssToken, err error) {
+	token.AccessKeyId = utils.MinIoAccessKeyId
+	token.SecretKeyId = utils.MinIoAccessKeySecret
+	token.Endpoint = utils.MinIoEndpoint
+	token.ImgHost = utils.MinIoImghost
+	token.Bucketname = utils.MinIoBucketname
+	token.UseSSL = utils.MinIoUseSSL
+	token.RegionId = utils.MinIoRegion
+	token.Port = utils.MinIoPort
+	return
+}

+ 296 - 0
services/oss.go

@@ -0,0 +1,296 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_hub/services/alarm_msg"
+	"eta/eta_hub/utils"
+	"fmt"
+	"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
+	"github.com/aliyun/aliyun-oss-go-sdk/oss"
+	"time"
+)
+
+// UploadAliyunV2 图片上传到阿里云
+//func UploadAliyunV2(filename, filepath string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	path := utils.UploadDir + time.Now().Format("200601/20060102/")
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
+
+// UploadAudioAliyun 音频上传到阿里云
+//func UploadAudioAliyun(filename, filepath string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
+
+// UploadVideoAliyun 视频上传到阿里云
+//func UploadVideoAliyun(filename, filepath, savePath string) error {
+//	if utils.AccessKeyId == `` {
+//		return errors.New("阿里云信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filepath)
+//	}()
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	err = bucket.PutObjectFromFile(savePath, filepath)
+//	if err != nil {
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
+
+// UploadFileToAliyun 上传文件到阿里云
+//func UploadFileToAliyun(filename, filepath, savePath string) error {
+//	if utils.AccessKeyId == `` {
+//		return errors.New("阿里云信息未配置")
+//	}
+//	defer func() {
+//		os.Remove(filepath)
+//	}()
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return err
+//	}
+//	//path := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
+//	//path += filename
+//	err = bucket.PutObjectFromFile(savePath, filepath)
+//	if err != nil {
+//		return err
+//	}
+//	//path = utils.Imghost + path
+//	//return path,err
+//	return err
+//}
+
+type STSToken struct {
+	AccessKeyId     string
+	AccessKeySecret string
+	SecurityToken   string
+	ExpiredTime     string
+	RegionId        string
+	Bucketname      string
+	Endpoint        string
+	Imghost         string
+}
+
+// GetOssSTSToken 获取STSToken
+func GetOssSTSToken() (item *STSToken, err error) {
+	defer func() {
+		if err != nil {
+			utils.FileLog.Info(err.Error())
+			go alarm_msg.SendAlarmMsg("获取STSToken失败, ErrMsg: "+err.Error(), 3)
+		}
+	}()
+	item = new(STSToken)
+	// 获取缓存中的Token
+	recent, _ := utils.Rc.RedisString(utils.STSTokenCacheKey)
+	if recent != "" {
+		lastToken := new(STSToken)
+		if e := json.Unmarshal([]byte(recent), &lastToken); e != nil {
+			err = errors.New("GetOssSTSToken lastToken Unmarshal Err: " + e.Error())
+			return
+		}
+		// 未防止正在上传大文件时Token过期, 将判定的过期时间提前10分钟
+		afterTime := time.Now().Local().Add(10 * time.Minute)
+		expired, e := time.ParseInLocation(utils.FormatDateTime, lastToken.ExpiredTime, time.Local)
+		if e != nil {
+			err = errors.New("GetOssSTSToken expiredTime Parse Err: " + e.Error())
+			return
+		}
+		if expired.After(afterTime) {
+			item.AccessKeyId = lastToken.AccessKeyId
+			item.AccessKeySecret = lastToken.AccessKeySecret
+			item.SecurityToken = lastToken.SecurityToken
+			item.ExpiredTime = lastToken.ExpiredTime
+			item.RegionId = utils.RegionId
+			item.Bucketname = utils.Bucketname
+			item.Endpoint = utils.Imghost
+			item.Imghost = utils.Imghost
+			return
+		}
+	}
+	// 已过期则获取新的token
+	newToken, e := NewSTSToken()
+	if e != nil {
+		err = errors.New("GetOssSTSToken NewSTSToken Err: " + e.Error())
+		return
+	}
+	newTokenJson, e := json.Marshal(newToken)
+	if e != nil {
+		err = errors.New("GetOssSTSToken NewToken JSON Err: " + e.Error())
+		return
+	}
+	// 覆盖缓存
+	if e := utils.Rc.Put(utils.STSTokenCacheKey, newTokenJson, time.Hour); e != nil {
+		err = errors.New("GetOssSTSToken SetRedis Err: " + e.Error())
+		return
+	}
+	item = newToken
+	return
+}
+
+// NewSTSToken 获取一个新的STSToken
+func NewSTSToken() (item *STSToken, err error) {
+	defer func() {
+		if err != nil {
+			utils.FileLog.Info(err.Error())
+		}
+	}()
+	item = new(STSToken)
+	client, e := sts.NewClientWithAccessKey("cn-shanghai", utils.RAMAccessKeyId, utils.RAMAccessKeySecret)
+	if e != nil {
+		err = errors.New("NewSTSToken NewClient Err: " + e.Error())
+		return
+	}
+	request := sts.CreateAssumeRoleRequest()
+	request.Scheme = utils.AliStsScheme
+	request.RegionId = utils.RegionId
+	request.RoleArn = utils.RoleArn
+	now := time.Now().Format(utils.FormatDateTimeUnSpace)
+	request.RoleSessionName = utils.RoleSessionName + now
+	request.DurationSeconds = "3600"
+	request.ConnectTimeout = 300 * time.Second
+	request.ReadTimeout = 300 * time.Second
+
+	response, e := client.AssumeRole(request)
+	if e != nil {
+		err = errors.New("NewSTSToken AssumeRole Err: " + e.Error())
+		return
+	}
+	if response != nil {
+		item.AccessKeyId = response.Credentials.AccessKeyId
+		item.AccessKeySecret = response.Credentials.AccessKeySecret
+		item.SecurityToken = response.Credentials.SecurityToken
+		t, _ := time.Parse(time.RFC3339, response.Credentials.Expiration)
+		expiration := t.In(time.Local)
+		item.ExpiredTime = expiration.Format(utils.FormatDateTime)
+		item.RegionId = utils.RegionId
+		item.Bucketname = utils.Bucketname
+		item.Endpoint = utils.Imghost
+		item.Imghost = utils.Imghost
+	}
+	return
+}
+
+// UploadAliyunToDir 上传至hzchart
+//func UploadAliyunToDir(filename, filepath, uploadDir, fileDir string) (string, error) {
+//	if utils.AccessKeyId == `` {
+//		return "0", errors.New("阿里云信息未配置")
+//	}
+//	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+//	if err != nil {
+//		return "1", err
+//	}
+//	bucket, err := client.Bucket(utils.Bucketname)
+//	if err != nil {
+//		return "2", err
+//	}
+//	if uploadDir == "" {
+//		uploadDir = utils.UploadDir
+//	}
+//	if fileDir == "" {
+//		fileDir = time.Now().Format("200601/20060102/")
+//	}
+//	path := uploadDir + fileDir
+//	path += filename
+//	err = bucket.PutObjectFromFile(path, filepath)
+//	if err != nil {
+//		return "3", err
+//	}
+//	path = utils.Imghost + path
+//	return path, err
+//}
+
+type AliOss struct{}
+
+// UploadFile 上传文件
+func (m *AliOss) UploadFile(fileName, filePath, savePath string) (string, error) {
+	if utils.AccessKeyId == `` {
+		return "0", errors.New("阿里云信息未配置")
+	}
+	client, err := oss.New(utils.Endpoint, utils.AccessKeyId, utils.AccessKeySecret)
+	if err != nil {
+		return "1", err
+	}
+	bucket, err := client.Bucket(utils.Bucketname)
+	if err != nil {
+		return "2", err
+	}
+
+	path := savePath
+	if savePath == "" {
+		path = utils.UploadDir + time.Now().Format("200601/20060102/") + fileName
+	}
+	err = bucket.PutObjectFromFile(path, filePath)
+	if err != nil {
+		return "3", err
+	}
+	resourceUrl := utils.Imghost + path
+	return resourceUrl, err
+}
+
+func (m *AliOss) GetUploadToken() (token OssToken, err error) {
+	stsToken, e := GetOssSTSToken()
+	if e != nil {
+		err = fmt.Errorf("GetOssSTSToken err: %s", e.Error())
+		return
+	}
+	token.AccessKeyId = stsToken.AccessKeyId
+	token.AccessKeySecret = stsToken.AccessKeySecret
+	token.SecurityToken = stsToken.SecurityToken
+	token.ExpiredTime = stsToken.ExpiredTime
+	token.RegionId = stsToken.RegionId
+	token.Bucketname = stsToken.Bucketname
+	token.Endpoint = stsToken.Endpoint
+	token.Imghost = stsToken.Imghost
+	return
+}

+ 5 - 0
utils/common.go

@@ -1187,3 +1187,8 @@ func DateConvMysqlConvMongo(dateCon string) string {
 	}
 	return cond
 }
+
+// GetCurrentTime 获取当前时间 格式为 2024-08-07 15:29:58
+func GetCurrentTime() string {
+	return time.Now().Format("2006-01-02 15:04:05")
+}

+ 144 - 15
utils/config.go

@@ -63,6 +63,76 @@ var (
 	EDB_LIB_Md5_KEY     string
 )
 
+var (
+	UseMongo bool // 是否使用mongo
+)
+
+// 基础配置
+var (
+	STATIC_DIR string
+
+	ResourceProxyUrl string // 代理资源地址
+)
+
+// 对象存储客户端
+var (
+	ObjectStorageClient string
+)
+
+// MinIo配置
+var (
+	MinIoBucketname       string
+	MinIoEndpoint         string
+	MinIoBackEndpoint     string
+	MinIoImghost          string
+	MinIoUploadDir        string
+	MinIoUpload_Audio_Dir string
+	MinIoAccessKeyId      string
+	MinIoAccessKeySecret  string
+	MinIoUseSSL           string
+	MinIoPort             string
+	MinIoRegion           string
+)
+
+// 阿里云oss前端上传用
+var (
+	AliStsScheme       string
+	RegionId           string
+	RoleArn            string
+	RoleSessionName    string
+	RAMAccessKeyId     string
+	RAMAccessKeySecret string
+	STSTokenCacheKey   string
+)
+
+// 阿里云配置
+var (
+	Bucketname       string
+	Endpoint         string
+	Imghost          string
+	UploadDir        string
+	Upload_Audio_Dir string
+	AccessKeyId      string
+	AccessKeySecret  string
+)
+
+// S3配置
+var (
+	S3Endpoint        string
+	S3BackEndpoint    string
+	S3BucketName      string
+	S3UploadDir       string
+	S3AccessKeyId     string
+	S3AccessKeySecret string
+	S3Host            string
+	S3Region          string
+	S3ForceStyle      string
+	S3EndpointPort    string
+	S3Protocol        string
+	S3DisableSSL      string
+	S3OpenAcl         string
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -96,24 +166,19 @@ func init() {
 	// mongodb数据库连接配置
 	MgoUrlData = config["mgo_url_data"]
 
-	REDIS_CACHE = config["beego_cache"]
-	if len(REDIS_CACHE) <= 0 {
-		panic(any("redis链接参数没有配置"))
-	}
-	//Rc, Re = cache.NewCache(REDIS_CACHE) //初始化缓存
-	//if Re != nil {
-	//	fmt.Println(Re)
-	//	panic(any(Re))
+	//REDIS_CACHE = config["beego_cache"]
+	//if len(REDIS_CACHE) <= 0 {
+	//	panic(any("redis链接参数没有配置"))
 	//}
 
 	// 初始化缓存
-	redisClient, err := initRedis(config["redis_type"], config["beego_cache"])
-	if err != nil {
-		fmt.Println("redis链接异常:", err)
-		panic(any(Re))
-	}
-
-	Rc = redisClient
+	//redisClient, err := initRedis(config["redis_type"], config["beego_cache"])
+	//if err != nil {
+	//	fmt.Println("redis链接异常:", err)
+	//	panic(any(Re))
+	//}
+	//
+	//Rc = redisClient
 
 	//商家编码
 	BusinessCode = config["business_code"]
@@ -166,4 +231,68 @@ func init() {
 		EDB_LIB_Md5_KEY = config["edb_lib_md5_key"]
 	}
 
+	// 基础配置
+	{
+		STATIC_DIR = config["static_dir"]
+
+		// 代理资源地址
+		ResourceProxyUrl = config["resource_proxy_url"]
+	}
+
+	// 对象存储客户端
+	ObjectStorageClient = config["object_storage_client"]
+
+	// MinIo相关
+	{
+		MinIoEndpoint = config["minio_endpoint"]
+		MinIoBackEndpoint = config["minio_back_endpoint"]
+		MinIoBucketname = config["minio_bucket_name"]
+		MinIoImghost = config["minio_img_host"]
+		MinIoUploadDir = config["minio_upload_dir"]
+		MinIoUpload_Audio_Dir = config["minio_upload_audio_dir"]
+		MinIoAccessKeyId = config["minio_access_key_id"]
+		MinIoAccessKeySecret = config["minio_access_key_secret"]
+		MinIoUseSSL = config["minio_use_ssl"]
+		MinIoPort = config["minio_port"]
+		MinIoRegion = config["minio_region"]
+	}
+
+	// OSS相关(前端使用)
+	{
+		AliStsScheme = config["ali_sts_scheme"]
+		RegionId = config["region_id"]
+		RoleArn = config["role_arn"]
+		RoleSessionName = config["role_session_name"]
+		RAMAccessKeyId = config["ram_access_key_id"]
+		RAMAccessKeySecret = config["ram_access_key_secret"]
+		STSTokenCacheKey = config["sts_token_cache_key"]
+	}
+
+	// OSS相关
+	{
+		Endpoint = config["endpoint"]
+		Bucketname = config["bucket_name"]
+		Imghost = config["img_host"]
+		UploadDir = config["upload_dir"]
+		Upload_Audio_Dir = config["upload_audio_dir"]
+		AccessKeyId = config["access_key_id"]
+		AccessKeySecret = config["access_key_secret"]
+	}
+
+	// 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"]
+		S3AccessKeySecret = config["s3_access_key_secret"]
+		S3UploadDir = config["s3_upload_dir"]
+		S3Region = config["s3_region"]
+		S3ForceStyle = config["s3_force_style"]
+		S3EndpointPort = config["s3_endpoint_port"]
+		S3Protocol = config["s3_protocol"]
+		S3DisableSSL = config["s3_disable_ssl"]
+		S3OpenAcl = config["s3_open_acl"]
+	}
 }

+ 14 - 2
utils/constants.go

@@ -1,5 +1,7 @@
 package utils
 
+import "io/fs"
+
 const (
 	Md5Key = "Ks@h64WJ#tcVgG8$&WlNfqvLAtMgpxWN"
 )
@@ -161,6 +163,16 @@ const (
 
 // 子数据来源渠道
 const (
-	DATA_SUB_SOURCE_EDB  = iota //经济数据库
-	DATA_SUB_SOURCE_DATE        //日期序列
+	DATA_SUB_SOURCE_EDB            = iota //经济数据库
+	DATA_SUB_SOURCE_DATE                  //日期序列
+	DATA_SUB_SOURCE_HIGH_FREQUENCY        //高频数据
+)
+
+// DIR_MOD 目录创建权限
+const DIR_MOD fs.FileMode = 0766
+
+const (
+	STORAGESOURCE_OSS_NAME   = "oss"
+	STORAGESOURCE_MINIO_NAME = "minio"
+	STORAGESOURCE_S3_NAME    = "s3"
 )