浏览代码

Merge branch 'master' into feature/forum3_chart_classify

xyxie 6 天之前
父节点
当前提交
2722be7013

+ 60 - 0
controllers/data_manage/chart_common.go

@@ -11,6 +11,7 @@ import (
 	"eta/eta_mobile/models"
 	"eta/eta_mobile/models/data_manage"
 	"eta/eta_mobile/models/system"
+	"eta/eta_mobile/services"
 	"eta/eta_mobile/services/data"
 	"eta/eta_mobile/services/data/excel"
 	"eta/eta_mobile/utils"
@@ -228,3 +229,62 @@ func getBalanceChartInfoDetailFromUniqueCode(chartInfo *data_manage.ChartInfoVie
 
 	return
 }
+
+// GeneralChartToken
+// @Title 根据图表唯一code生成token
+// @Description 根据编码获取图表详情接口
+// @Param   UniqueCode   query   string  true       "图表/表格唯一编码"
+// @Param   Source   query   string  true       "来源,枚举值:chart、table"
+// @Success 200 {object} data_manage.ChartInfoDetailFromUniqueCodeResp
+// @router /chart_info/common/general_token [get]
+func (this *ChartInfoController) GeneralChartToken() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
+	uniqueCode := this.GetString("UniqueCode")
+	if uniqueCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,uniqueCode is empty"
+		return
+	}
+	source := this.GetString("Source", "chart")
+
+	businessConf, err := models.GetBusinessConfByKey(models.BusinessConfIsOpenChartExpired)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取配置失败,Err:" + err.Error()
+		return
+	}
+
+	var token string
+	if businessConf.ConfVal == `true` {
+		// 缓存key
+		sourceType := source
+		if source == `table` {
+			sourceType = source
+		}
+		token, err = services.GeneralChartToken(sourceType, uniqueCode, 30*time.Minute)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取失败"
+			return
+		}
+	}
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = token
+
+	return
+}

+ 93 - 4
controllers/english_report/report.go

@@ -64,6 +64,8 @@ func (this *EnglishReportController) Add() {
 
 	var contentSub string
 	if req.Content != "" {
+		req.Content = services.HandleReportContent(req.Content, "del", nil)
+
 		content, e := services.FilterReportContentBr(req.Content)
 		if e != nil {
 			br.Msg = "内容去除前后空格失败"
@@ -181,6 +183,7 @@ func (this *EnglishReportController) Edit() {
 	}
 	var contentSub string
 	if req.Content != "" {
+		req.Content = services.HandleReportContent(req.Content, "del", nil)
 		content, e := services.FilterReportContentBr(req.Content)
 		if e != nil {
 			br.Msg = "内容去除前后空格失败"
@@ -298,6 +301,17 @@ func (this *EnglishReportController) Detail() {
 	item.Content = html.UnescapeString(item.Content)
 	item.ContentSub = html.UnescapeString(item.ContentSub)
 
+	businessConf, err := models.GetBusinessConfByKey(models.BusinessConfIsOpenChartExpired)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取配置失败,Err:" + err.Error()
+		return
+	}
+	if businessConf.ConfVal == `true` {
+		tokenMap := make(map[string]string)
+		item.Content = services.HandleReportContent(item.Content, "add", tokenMap)
+	}
+
 	classifyNameMap := make(map[int]*models.EnglishClassifyFullName)
 	if item.ClassifyIdSecond > 0 {
 		nameList, tErr := models.GetEnglishClassifyFullNameByIds([]int{item.ClassifyIdSecond})
@@ -682,8 +696,9 @@ func (this *EnglishReportController) PublishReport() {
 			}()
 
 			// 生成报告pdf和长图
-			if req.ReportUrl != "" {
-				go services.Report2pdfAndJpeg(req.ReportUrl, report.Id, 2)
+			pdfUrl := services.GetGeneralEnglishReportPdfUrl(report.Id, report.ReportCode)
+			if pdfUrl != "" {
+				go services.Report2pdfAndJpeg(pdfUrl, report.Id, 2)
 			}
 		} else {
 			// 从无审批切换为有审批, 状态重置
@@ -785,8 +800,9 @@ func (this *EnglishReportController) PrePublishReport() {
 	}
 
 	// 生成报告pdf和长图
-	if req.ReportUrl != "" {
-		go services.Report2pdfAndJpeg(req.ReportUrl, report.Id, 2)
+	pdfUrl := services.GetGeneralEnglishReportPdfUrl(report.Id, report.ReportCode)
+	if pdfUrl != "" {
+		go services.Report2pdfAndJpeg(pdfUrl, report.Id, 2)
 	}
 
 	br.Ret = 200
@@ -945,6 +961,7 @@ func (this *EnglishReportController) SaveReportContent() {
 	}
 
 	if noChangeFlag != 1 {
+		req.Content = services.HandleReportContent(req.Content, "del", nil)
 		content := req.Content
 		if content == "" {
 			content = this.GetString("Content")
@@ -1020,6 +1037,18 @@ func (this *EnglishReportController) ClassifyIdDetail() {
 		item.Content = html.UnescapeString(item.Content)
 		item.ContentSub = html.UnescapeString(item.ContentSub)
 
+		businessConf, err := models.GetBusinessConfByKey(models.BusinessConfIsOpenChartExpired)
+		if err != nil {
+			br.Msg = "获取失败"
+			br.ErrMsg = "获取配置失败,Err:" + err.Error()
+			return
+		}
+
+		if businessConf.ConfVal == `true` {
+			tokenMap := make(map[string]string)
+			item.Content = services.HandleReportContent(item.Content, "add", tokenMap)
+		}
+
 		classifyNameMap := make(map[int]*models.EnglishClassifyFullName)
 		if item.ClassifyIdSecond > 0 {
 			nameList, tErr := models.GetEnglishClassifyFullNameByIds([]int{item.ClassifyIdSecond})
@@ -1421,3 +1450,63 @@ func (this *EnglishReportController) CancelApprove() {
 	br.Success = true
 	br.Msg = "操作成功"
 }
+
+// @Title 获取报告分享链接
+// @Description 获取报告分享链接
+// @Param   ReportId   query   int  true       "报告id"
+// @Success 200 {object} models.EnglishReportDetailView
+// @router /share_url [get]
+func (this *EnglishReportController) GetShareUrl() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+	/*var req models.ReportDetailReq
+	err := json.Unmarshal(this.Ctx.Input.RequestBody, &req)
+	if err != nil {
+		br.Msg = "参数解析异常!"
+		br.ErrMsg = "参数解析失败,Err:" + err.Error()
+		return
+	}
+	if req.ReportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}*/
+	reportId, err := this.GetInt("ReportId")
+	if err != nil {
+		br.Msg = "获取参数失败!"
+		br.ErrMsg = "获取参数失败,Err:" + err.Error()
+		return
+	}
+	if reportId <= 0 {
+		br.Msg = "参数错误"
+		return
+	}
+	item, err := models.GetEnglishReportById(reportId)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	token, err := services.GetEnglishReportToken(reportId, item.ReportCode)
+	if err != nil {
+		if err.Error() == utils.ErrNoRow() {
+			br.Msg = "报告已被删除"
+			return
+		}
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取失败,Err:" + err.Error()
+		return
+	}
+
+	br.Data = token
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 81 - 3
controllers/report.go

@@ -8,9 +8,6 @@ import (
 	"eta/eta_mobile/services/data"
 	"eta/eta_mobile/utils"
 	"fmt"
-	"github.com/beego/beego/v2/server/web"
-	"github.com/h2non/filetype"
-	"github.com/tealeg/xlsx"
 	"html"
 	"io"
 	"os"
@@ -19,6 +16,10 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/server/web"
+	"github.com/h2non/filetype"
+	"github.com/tealeg/xlsx"
 )
 
 // ReportController 报告
@@ -1986,3 +1987,80 @@ func (this *ReportController) CheckDayWeekReportChapterVideo() {
 	br.Msg = "保存成功"
 	br.Data = typeNameArr
 }
+
+// ShareGenerate
+// @Title 获取复制链接
+// @Description 获取复制链接
+// @Param	request	body models.ReportShartLinkReq true "type json string"
+// @Success 200 Ret=200 操作成功
+// @router /share/generate [post]
+func (this *ReportController) ShareGenerate() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	var req models.ReportShartUrlReq
+	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
+		br.Msg = "参数有误"
+		br.ErrMsg = "参数解析失败, Err: " + e.Error()
+		return
+	}
+	var title string
+	reportItem, _ := models.GetReportByReportId(req.ReportId)
+	if reportItem != nil && reportItem.Title != "" {
+		title = reportItem.Title
+	}
+
+	link, err := services.GetReportShareUrlToken(req, this.SysUser.AdminId)
+	if err != nil || link == "" {
+		br.Msg = "复制链接失败"
+		br.ErrMsg = "获取复制链接失败, Err: " + err.Error()
+		return
+	}
+
+	resp := new(models.ReportShartUrlResp)
+	resp.UrlToken = fmt.Sprint(link, " ", title)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// ShareTransform
+// @Title 获取原始链接
+// @Description 获取原始链接
+// @Param	Token   query   string  true    "复制链接的token"
+// @Success 200 Ret=200 操作成功
+// @router /share/link [get]
+func (this *ReportCommonController) ShareTransform() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	token := this.GetString("Token")
+	tokenArr := strings.Split(token, " ")
+	if len(tokenArr) > 0 {
+		token = tokenArr[0]
+	}
+
+	link, msg, err := services.TransfromToOriginUrl(token)
+	if err != nil {
+		if msg == "" {
+			msg = "获取失败"
+		}
+		br.Msg = msg
+		br.ErrMsg = "获取复制链接失败, Err: " + err.Error()
+		return
+	}
+
+	this.Ctx.Redirect(302, link)
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+}

+ 18 - 0
controllers/report_chapter.go

@@ -363,6 +363,7 @@ func (this *ReportController) EditDayWeekChapter() {
 	// 更新章节及指标
 	contentSub := ""
 	if req.Content != "" {
+		req.Content = services.HandleReportContent(req.Content, "del", nil)
 		e := utils.ContentXssCheck(req.Content)
 		if e != nil {
 			br.Msg = "存在非法标签"
@@ -405,6 +406,10 @@ func (this *ReportController) EditDayWeekChapter() {
 	reportChapterInfo.LastModifyAdminId = sysUser.AdminId
 	reportChapterInfo.LastModifyAdminName = sysUser.RealName
 	reportChapterInfo.ContentModifyTime = time.Now()
+
+	if req.ContentStruct != `` {
+		req.ContentStruct = services.HandleReportContentStruct(req.ContentStruct, "del", nil)
+	}
 	reportChapterInfo.ContentStruct = html.EscapeString(req.ContentStruct)
 
 	updateCols = append(updateCols, "Author", "Content", "ContentSub", "IsEdit", "ModifyTime")
@@ -776,6 +781,19 @@ func (this *ReportController) GetDayWeekChapter() {
 	chapterItem.ContentSub = html.UnescapeString(chapterItem.ContentSub)
 	chapterItem.ContentStruct = html.UnescapeString(chapterItem.ContentStruct)
 
+	businessConf, err := models.GetBusinessConfByKey(models.BusinessConfIsOpenChartExpired)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取配置失败,Err:" + err.Error()
+		return
+	}
+
+	if businessConf.ConfVal == `true` {
+		tokenMap := make(map[string]string)
+		chapterItem.Content = services.HandleReportContent(chapterItem.Content, "add", tokenMap)
+		chapterItem.ContentStruct = services.HandleReportContentStruct(chapterItem.ContentStruct, "add", tokenMap)
+	}
+
 	// 授权用户列表map
 	chapterGrantIdList := make([]int, 0)
 	// 关联品种id列表map

+ 30 - 1
controllers/report_v2.go

@@ -391,6 +391,7 @@ func (this *ReportController) Add() {
 
 	var contentSub string
 	if req.Content != "" {
+		req.Content = services.HandleReportContent(req.Content, "del", nil)
 		e := utils.ContentXssCheck(req.Content)
 		if e != nil {
 			br.Msg = "存在非法标签"
@@ -412,6 +413,10 @@ func (this *ReportController) Add() {
 		}
 	}
 
+	if req.ContentStruct != `` {
+		req.ContentStruct = services.HandleReportContentStruct(req.ContentStruct, "del", nil)
+	}
+
 	// 报告期数
 	maxStage, err := models.GetReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird)
 	if err != nil {
@@ -587,6 +592,8 @@ func (this *ReportController) Edit() {
 		return
 	}
 
+	req.Content = services.HandleReportContent(req.Content, "del", nil)
+	req.ContentStruct = services.HandleReportContentStruct(req.ContentStruct, "del", nil)
 	// 编辑报告信息
 	err, errMsg := services.EditReport(reportInfo, req, sysUser)
 	if err != nil {
@@ -698,6 +705,24 @@ func (this *ReportController) Detail() {
 		item.EndStyle = endResource.Style
 	}
 
+	businessConf, err := models.GetBusinessConfByKey(models.BusinessConfIsOpenChartExpired)
+	if err != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取配置失败,Err:" + err.Error()
+		return
+	}
+
+	if businessConf.ConfVal == `true` {
+		tokenMap := make(map[string]string)
+		item.Content = services.HandleReportContent(item.Content, "add", tokenMap)
+		item.ContentStruct = services.HandleReportContentStruct(item.ContentStruct, "add", tokenMap)
+		for _, v := range chapterList {
+			v.Content = services.HandleReportContent(v.Content, "add", tokenMap)
+			v.ContentStruct = services.HandleReportContentStruct(v.ContentStruct, "add", tokenMap)
+		}
+
+	}
+
 	resp := &models.ReportDetailView{
 		ReportDetail: item,
 		ChapterList:  chapterList,
@@ -775,6 +800,8 @@ func (this *ReportController) SaveReportContent() {
 		if content == "" {
 			content = this.GetString("Content")
 		}
+		content = services.HandleReportContent(content, "del", nil)
+
 		if content != "" {
 			e := utils.ContentXssCheck(req.Content)
 			if e != nil {
@@ -790,6 +817,8 @@ func (this *ReportController) SaveReportContent() {
 			}
 			content = contentClean
 
+			req.ContentStruct = services.HandleReportContentStruct(req.ContentStruct, "del", nil)
+
 			contentSub, err := services.GetReportContentSub(content)
 			if err != nil {
 				go alarm_msg.SendAlarmMsg("解析 ContentSub 失败,Err:"+err.Error(), 3)
@@ -1443,7 +1472,7 @@ func (this *ReportController) PrePublishReport() {
 
 	// 生成报告pdf和长图
 	{
-		reportPdfUrl := services.GetGeneralPdfUrl(reportDetail.ReportCode, reportDetail.ReportLayout)
+		reportPdfUrl := services.GetGeneralPdfUrl(reportDetail.Id, reportDetail.ReportCode, reportDetail.ReportLayout)
 		go services.Report2pdfAndJpeg(reportPdfUrl, reportDetail.Id, 1)
 	}
 

+ 4 - 3
go.mod

@@ -23,8 +23,10 @@ require (
 	github.com/go-xorm/xorm v0.7.9
 	github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b
 	github.com/gorilla/websocket v1.5.1
+	github.com/h2non/filetype v1.1.3
 	github.com/jung-kurt/gofpdf v1.16.2
 	github.com/kgiannakakis/mp3duration v0.0.0-20191013070830-d834f8d5ed53
+	github.com/microcosm-cc/bluemonday v1.0.27
 	github.com/minio/minio-go/v7 v7.0.69
 	github.com/mojocn/base64Captcha v1.3.6
 	github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19
@@ -33,6 +35,7 @@ require (
 	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/shopspring/decimal v1.3.1
 	github.com/silenceper/wechat/v2 v2.1.6
+	github.com/spaolacci/murmur3 v1.1.0
 	github.com/tealeg/xlsx v1.0.5
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/asr v1.0.897
 	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.897
@@ -40,6 +43,7 @@ require (
 	github.com/xuri/excelize/v2 v2.8.1
 	github.com/yidane/formula v0.0.0-20220322063702-c9da84ba3476
 	go.mongodb.org/mongo-driver v1.15.0
+	golang.org/x/net v0.26.0
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 )
 
@@ -75,7 +79,6 @@ require (
 	github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
-	github.com/h2non/filetype v1.1.3 // 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
@@ -85,7 +88,6 @@ require (
 	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/microcosm-cc/bluemonday v1.0.27 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/minio/sha256-simd v1.0.1 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -117,7 +119,6 @@ require (
 	github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
 	golang.org/x/crypto v0.24.0 // indirect
 	golang.org/x/image v0.14.0 // indirect
-	golang.org/x/net v0.26.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
 	golang.org/x/sys v0.21.0 // indirect
 	golang.org/x/text v0.16.0 // indirect

+ 2 - 9
go.sum

@@ -412,6 +412,8 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
 github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
 github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
@@ -501,8 +503,6 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
-golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
 golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -553,8 +553,6 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
 golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
 golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -570,8 +568,6 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 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.1.0/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -607,8 +603,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
 golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -630,7 +624,6 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=

+ 21 - 2
models/business_conf.go

@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	"html"
+	"strconv"
 	"strings"
 	"time"
 )
@@ -51,8 +52,15 @@ const (
 	BusinessConfTencentApiSecretKey          = "TencentApiSecretKey"          // 腾讯云API-密钥对
 	BusinessConfTencentApiRecTaskCallbackUrl = "TencentApiRecTaskCallbackUrl" // 腾讯云API-语音识别回调地址
 	BusinessConfSmsJhgjVariable              = "SmsJhgjVariable"              // 聚合国际短信变量
-	BusinessConfEsIndexNameExcel             = "EsIndexNameExcel"             // ES索引名称-表格
-	BusinessConfEsIndexNameDataSource        = "EsIndexNameDataSource"        // ES索引名称-数据源
+
+	BusinessConfEdbStopRefreshRule = "EdbStopRefreshRule" // 是否停止指标刷新规则
+	BusinessConfReport2ImgUrl      = "Report2ImgUrl"      // 报告转长图地址(用于兼容内外网环境的)
+	BusinessConfReportViewUrl      = "ReportViewUrl"      // 报告详情地址     // 报告详情地址
+
+	BusinessConfEsIndexNameExcel       = "EsIndexNameExcel"       // ES索引名称-表格
+	BusinessConfEsIndexNameDataSource  = "EsIndexNameDataSource"  // 聚合国际短信变量
+	BusinessConfIsOpenChartExpired     = "IsOpenChartExpired"     // 是否开启图表有效期鉴权/报告禁止复制
+	BusinessConfReportChartExpiredTime = "ReportChartExpiredTime" // 图表有效期鉴权时间,单位:分钟
 )
 
 const (
@@ -255,4 +263,15 @@ func InitBusinessConf() {
 	if BusinessConfMap[BusinessConfEsIndexNameDataSource] != "" {
 		utils.EsDataSourceIndexName = BusinessConfMap[BusinessConfEsIndexNameDataSource]
 	}
+
+	// 图表有效期的过期时间
+	if BusinessConfMap[BusinessConfReportChartExpiredTime] != "" {
+		reportChartExpiredTime, _ := strconv.Atoi(BusinessConfMap[BusinessConfReportChartExpiredTime])
+		if reportChartExpiredTime <= 0 {
+			reportChartExpiredTime = 30
+		}
+		utils.BusinessConfReportChartExpiredTime = time.Duration(reportChartExpiredTime) * time.Minute
+	} else {
+		utils.BusinessConfReportChartExpiredTime = 30 * time.Minute
+	}
 }

+ 20 - 0
models/english_report.go

@@ -47,6 +47,8 @@ type EnglishReport struct {
 	ApproveId          int       `description:"审批ID"`
 	DetailImgUrl       string    `description:"报告详情长图地址"`
 	DetailPdfUrl       string    `description:"报告详情PDF地址"`
+	DetailImgUrlMobile string    `description:"报告详情长图地址-手机端"`
+	DetailPdfUrlMobile string    `description:"报告详情PDF地址-手机端"`
 	EmailHasFail       int       `description:"是否存在邮件发送失败的记录: 0-否; 1-是"`
 }
 
@@ -276,6 +278,8 @@ type EnglishReportList struct {
 	ApproveTime        string    `description:"审批时间"`
 	DetailImgUrl       string    `description:"报告详情长图地址"`
 	DetailPdfUrl       string    `description:"报告详情PDF地址"`
+	DetailImgUrlMobile string    `description:"报告详情长图地址-手机端"`
+	DetailPdfUrlMobile string    `description:"报告详情PDF地址-手机端"`
 }
 
 type EnglishReportListResp struct {
@@ -937,6 +941,20 @@ func ModifyEnglishReportImgUrl(reportId int, detailImgUrl string) (err error) {
 	return
 }
 
+func ModifyEnglishReportPdfUrlMobile(reportId int, detailPdfUrlMobile string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE english_report SET detail_pdf_url_mobile=? WHERE id=? `
+	_, err = o.Raw(sql, detailPdfUrlMobile, reportId).Exec()
+	return
+}
+
+func ModifyEnglishReportImgUrlMobile(reportId int, detailImgUrlMobile string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE english_report SET detail_img_url_mobile=? WHERE id=? `
+	_, err = o.Raw(sql, detailImgUrlMobile, reportId).Exec()
+	return
+}
+
 // UpdatePdfUrlEnglishReportById 清空pdf相关字段
 func UpdatePdfUrlEnglishReportById(reportId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -989,5 +1007,7 @@ func FormatEnglishReport2ListItem(origin *EnglishReport) (item *EnglishReportLis
 	item.ApproveTime = utils.TimeTransferString(utils.FormatDateTime, origin.ApproveTime)
 	item.DetailImgUrl = origin.DetailImgUrl
 	item.DetailPdfUrl = origin.DetailPdfUrl
+	item.DetailImgUrlMobile = origin.DetailImgUrlMobile
+	item.DetailPdfUrlMobile = origin.DetailPdfUrlMobile
 	return
 }

+ 1 - 0
models/ppt_english/ppt_english.go

@@ -25,6 +25,7 @@ type PptEnglish struct {
 	IsShare       int8      `description:"是否分享,0:不分享,1:分享"`
 	PublishTime   time.Time `description:"发布时间"`
 	CoverContent  string    `description:"PPT内容-JSON"`
+	TitleSetting  string    `description:"PPT标题设置"`
 }
 
 type PptEnglishItem struct {

+ 39 - 1
models/ppt_english/ppt_english_group_mapping.go

@@ -9,7 +9,7 @@ import (
 type PptEnglishGroupMapping struct {
 	GroupPptId      int64     `orm:"column(group_ppt_id);pk;auto" description:"自增序号"`
 	GroupId         int64     `description:"ppt目录ID"`
-	PptSort         int64     `description:"Ppt的排序"`
+	PptSort         float64   `description:"Ppt的排序"`
 	PptId           int64     `description:"ppt ID"`
 	CreateTime      time.Time `orm:"auto_now_add;type(datetime)" description:"创建时间"`
 	ModifyTime      time.Time `orm:"auto_now;type(datetime)" description:"修改时间"`
@@ -41,6 +41,14 @@ func GetPptMappingListByGroupId(groupId int64) (list []*PptEnglishGroupMapping,
 	return
 }
 
+// GetPptMappingListByGroupIdDesc 查询目录下,ppt列表, 降序排列
+func GetPptMappingListByGroupIdDesc(groupId int64) (list []*PptEnglishGroupMapping, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_english_group_mapping where group_id=? order by ppt_sort desc, group_ppt_id desc `
+	_, err = o.Raw(sql, groupId).QueryRows(&list)
+	return
+}
+
 // GetPptMappingListByGroupIds 根据分组ID查找
 func GetPptMappingListByGroupIds(groupIds []int64) (list []*PptEnglishGroupMapping, err error) {
 	_, err = orm.NewOrmUsingDB("rddp").
@@ -151,3 +159,33 @@ func GetPublicGroupPptByPptIds(pptIds []string) (list []*PptEnglishGroupMapping,
 	_, err = o.Raw(sql).QueryRows(&list)
 	return
 }
+
+// GetMaxSortByGroupId
+// @Description: 根据分组id获取最大排序
+// @author: Roc
+// @datetime 2025-03-07 18:22:56
+// @param groupPptId int64
+// @return pptSort float64
+// @return err error
+func GetMaxSortByEnglishGroupId(groupPptId int64) (pptSort float64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select MAX(ppt_sort) AS count from ppt_english_group_mapping where group_id=?`
+	err = o.Raw(sql, groupPptId).QueryRow(&pptSort)
+
+	return
+}
+
+// GetMinSortByGroupId
+// @Description: 根据分组id获取最大排序
+// @author: Roc
+// @datetime 2025-03-07 18:22:56
+// @param groupPptId int64
+// @return pptSort float64
+// @return err error
+func GetMinSortByEnglishGroupId(groupPptId int64) (pptSort float64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select MIN(ppt_sort) AS count from ppt_english_group_mapping where group_id=?`
+	err = o.Raw(sql, groupPptId).QueryRow(&pptSort)
+
+	return
+}

+ 33 - 2
models/ppt_v2_group_mapping.go

@@ -9,7 +9,7 @@ import (
 type PptV2GroupMapping struct {
 	GroupPptId      int64     `orm:"column(group_ppt_id);pk;auto" description:"自增序号"`
 	GroupId         int64     `description:"ppt目录ID"`
-	PptSort         int64     `description:"Ppt的排序"`
+	PptSort         float64   `description:"Ppt的排序"`
 	PptId           int64     `description:"ppt ID"`
 	CreateTime      time.Time `orm:"auto_now_add;type(datetime)" description:"创建时间"`
 	ModifyTime      time.Time `orm:"auto_now;type(datetime)" description:"修改时间"`
@@ -36,7 +36,8 @@ func GetPptMappingCountByGroupId(groupId int64) (total int64, err error) {
 // GetPptMappingListByGroupId 查询目录下,ppt列表
 func GetPptMappingListByGroupId(groupId int64) (list []*PptV2GroupMapping, err error) {
 	o := orm.NewOrmUsingDB("rddp")
-	sql := `select group_ppt_id, group_id, ppt_id, ppt_sort, admin_id, admin_real_name, create_time from ppt_v2_group_mapping where group_id=? order by ppt_sort asc, group_ppt_id asc `
+	sql := `select a.group_ppt_id, a.group_id, a.ppt_id, a.ppt_sort, a.admin_id, a.admin_real_name, a.create_time from ppt_v2_group_mapping AS a
+            JOIN ppt_v2 b on a.ppt_id = b.ppt_id where a.group_id=? order by a.ppt_sort desc, b.modify_time desc `
 	_, err = o.Raw(sql, groupId).QueryRows(&list)
 	return
 }
@@ -151,3 +152,33 @@ func GetPublicGroupPptByPptIds(pptIds []string) (list []*PptV2GroupMapping, err
 	_, err = o.Raw(sql).QueryRows(&list)
 	return
 }
+
+// GetMaxSortByGroupId
+// @Description: 根据分组id获取最大排序
+// @author: Roc
+// @datetime 2025-03-07 18:22:56
+// @param groupPptId int64
+// @return pptSort float64
+// @return err error
+func GetMaxSortByGroupId(groupPptId int64) (pptSort float64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select MAX(ppt_sort) AS count from ppt_v2_group_mapping where group_id=?`
+	err = o.Raw(sql, groupPptId).QueryRow(&pptSort)
+
+	return
+}
+
+// GetMinSortByGroupId
+// @Description: 根据分组id获取最大排序
+// @author: Roc
+// @datetime 2025-03-07 18:22:56
+// @param groupPptId int64
+// @return pptSort float64
+// @return err error
+func GetMinSortByGroupId(groupPptId int64) (pptSort float64, err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `select MIN(ppt_sort) AS count from ppt_v2_group_mapping where group_id=?`
+	err = o.Raw(sql, groupPptId).QueryRow(&pptSort)
+
+	return
+}

+ 30 - 2
models/report.go

@@ -4,10 +4,11 @@ import (
 	"errors"
 	"eta/eta_mobile/utils"
 	"fmt"
-	"github.com/beego/beego/v2/client/orm"
-	"github.com/rdlucklib/rdluck_tools/paging"
 	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/client/orm"
+	"github.com/rdlucklib/rdluck_tools/paging"
 )
 
 // 报告状态
@@ -66,6 +67,8 @@ type Report struct {
 	ApproveId          int       `description:"审批ID"`
 	DetailImgUrl       string    `description:"报告详情长图地址"`
 	DetailPdfUrl       string    `description:"报告详情PDF地址"`
+	DetailImgUrlMobile string    `description:"报告详情长图地址-手机端"`
+	DetailPdfUrlMobile string    `description:"报告详情PDF地址-手机端"`
 
 	ContentStruct       string    `description:"内容组件"`
 	LastModifyAdminId   int       `description:"最后更新人ID"`
@@ -131,6 +134,8 @@ type ReportList struct {
 	ApproveTime        string                    `description:"审批时间"`
 	DetailImgUrl       string                    `description:"报告详情长图地址"`
 	DetailPdfUrl       string                    `description:"报告详情PDF地址"`
+	DetailImgUrlMobile string                    `description:"报告详情长图地址-手机端"`
+	DetailPdfUrlMobile string                    `description:"报告详情PDF地址-手机端"`
 
 	CollaborateType     int8      `description:"协作方式,1:个人,2:多人协作。默认:1"`
 	ReportLayout        int8      `description:"报告布局,1:常规布局,2:智能布局。默认:1"`
@@ -1432,6 +1437,20 @@ func ModifyReportImgUrl(reportId int, detailImgUrl string) (err error) {
 	return
 }
 
+func ModifyReportPdfUrlMobile(reportId int, detailPdfUrlMobile string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE report SET detail_pdf_url_mobile=? WHERE id=? `
+	_, err = o.Raw(sql, detailPdfUrlMobile, reportId).Exec()
+	return
+}
+
+func ModifyReportImgUrlMobile(reportId int, detailImgUrlMobile string) (err error) {
+	o := orm.NewOrmUsingDB("rddp")
+	sql := `UPDATE report SET detail_img_url_mobile=? WHERE id=? `
+	_, err = o.Raw(sql, detailImgUrlMobile, reportId).Exec()
+	return
+}
+
 // UpdatePdfUrlReportById 清空pdf相关字段
 func UpdatePdfUrlReportById(reportId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
@@ -1883,3 +1902,12 @@ b.abstract,b.admin_id,b.admin_real_name,b.last_modify_admin_id,b.last_modify_adm
 	_, err = o.Raw(sql, params...).QueryRows(&items)
 	return items, err
 }
+
+type ReportShartUrlReq struct {
+	Url      string `description:"分享链接"`
+	ReportId int    `description:"报告ID"`
+}
+
+type ReportShartUrlResp struct {
+	UrlToken string `description:"分享链接token"`
+}

+ 3 - 2
models/smart_report/smart_report.go

@@ -51,6 +51,8 @@ type SmartReport struct {
 	MsgSendTime         time.Time `description:"模版消息发送时间"`
 	DetailImgUrl        string    `description:"报告详情长图地址"`
 	DetailPdfUrl        string    `description:"报告详情PDF地址"`
+	DetailImgUrlMobile  string    `description:"报告详情长图地址-手机端"`
+	DetailPdfUrlMobile  string    `description:"报告详情PDF地址-手机端"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"修改时间"`
 	HeadImg             string    `description:"报告头图地址"`
@@ -419,11 +421,10 @@ func UpdateSmartReportsStateBySecondIds(oldState, newState int, secondIds []int)
 	return
 }
 
-
 // UpdatePdfUrlSmartReportById 清空pdf相关字段
 func UpdatePdfUrlSmartReportById(reportId int) (err error) {
 	o := orm.NewOrmUsingDB("rddp")
 	sql := `UPDATE smart_report SET detail_img_url = '',detail_pdf_url='',modify_time=NOW() WHERE smart_report_id = ? `
 	_, err = o.Raw(sql, reportId).Exec()
 	return
-}
+}

+ 27 - 0
routers/commentsRouter.go

@@ -2068,6 +2068,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
+        beego.ControllerComments{
+            Method: "GeneralChartToken",
+            Router: `/chart_info/common/general_token`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers/data_manage:ChartInfoController"],
         beego.ControllerComments{
             Method: "ChartInfoConvertDetail",
@@ -5524,6 +5533,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportCommonController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportCommonController"],
+        beego.ControllerComments{
+            Method: "ShareTransform",
+            Router: `/share/link`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"],
         beego.ControllerComments{
             Method: "CheckDayWeekReportChapterVideo",
@@ -5947,6 +5965,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"],
+        beego.ControllerComments{
+            Method: "ShareGenerate",
+            Router: `/share/generate`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"] = append(beego.GlobalControllerRouter["eta/eta_mobile/controllers:ReportController"],
         beego.ControllerComments{
             Method: "ThsSendTemplateMsg",

+ 4 - 0
routers/router.go

@@ -33,6 +33,8 @@ import (
 	"eta/eta_mobile/controllers/smart_report"
 	"eta/eta_mobile/controllers/speech_recognition"
 	"eta/eta_mobile/controllers/trade_analysis"
+	"eta/eta_mobile/services"
+
 	"github.com/beego/beego/v2/server/web"
 	"github.com/beego/beego/v2/server/web/filter/cors"
 )
@@ -46,6 +48,8 @@ func init() {
 		ExposeHeaders:    []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
 		AllowCredentials: true,
 	}))
+
+	web.InsertFilter("/v1/share/*", web.BeforeRouter, services.FilterShareUrl())
 	ns := web.NewNamespace("/v1",
 		web.NSNamespace("/ppt",
 			web.NSInclude(

+ 46 - 66
services/data/chart_info.go

@@ -619,7 +619,16 @@ func GetEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
 	// 指标对应的所有数据
 	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
-
+	// 设置季节性图的左右轴
+	seasonXStartDateWithYear := ""
+	seasonXEndDateWithYear := ""
+	// 如果是季节性图则进入特殊排序
+	if chartType == 2 {
+		// 根据设置的左右轴,对mappingList进行排序,1左轴排在前面,0右轴排在前面
+		sort.Slice(mappingList, func(i, j int) bool {
+			return mappingList[i].IsAxis > mappingList[j].IsAxis
+		})
+	}
 	for _, v := range mappingList {
 		//fmt.Println("v:", v.EdbInfoId)
 		item := new(data_manage.ChartEdbInfoMapping)
@@ -817,77 +826,37 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
 						return
 					}
-					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
 					if tErr != nil {
 						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 						return
 					}
 					item.DataList = quarterDataList
+					seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+					seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 				}
 
 			} else {
-				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
 				if tErr != nil {
 					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 					return
 				}
 				item.DataList = quarterDataList
+				seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+				seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 			}
 		} else if chartType == 2 && item.IsAxis == 0 {
-			// 右轴数据处理
-			xStartDate := "01-01"
-
-			jumpYear := 0
-			var seasonExtra data_manage.SeasonExtraItem
-			if seasonExtraConfig != "" {
-				err = json.Unmarshal([]byte(seasonExtraConfig), &seasonExtra)
-				if err != nil {
-					return
-				}
-			}
-
-			if seasonExtra.XStartDate != "" {
-				xStartDate = seasonExtra.XStartDate
-				jumpYear = seasonExtra.JumpYear
-			}
-
-			length := len(dataList)
-			if length == 0 {
-				return
-			}
-			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
-			if tmpErr != nil {
-				//item.DataList = dataList
-				item.IsNullData = true
-				edbList = append(edbList, item)
-				continue
-				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
-				return
-			}
-
-			var rightAxisDate time.Time
-			if jumpYear == 1 {
-				latestDate = latestDate.AddDate(-1, 0, 0)
-			}
-			latestDateStr := fmt.Sprintf("%d-%s", latestDate.Year(), xStartDate)
-			rightAxisDate, err = time.Parse(utils.FormatDate, latestDateStr)
-			if err != nil {
-				return
-			}
-
-			nowYear := time.Now().Year()
 			newDataList := make([]*data_manage.EdbDataList, 0)
+			seasonXStartDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXStartDateWithYear)
+			seasonXEndDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXEndDateWithYear)
 			for _, v := range dataList {
 				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
 				if e != nil {
 					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
 					return
 				}
-				dataTimeT, _ := time.Parse(utils.FormatDate, v.DataTime)
-				year := dataTimeT.Year()
-				newItemDate := dataTimeT.AddDate(nowYear-year, 0, 0)
-				v.DataTimestamp = newItemDate.UnixNano() / 1e6
-				if dataTime.Equal(rightAxisDate) || dataTime.After(rightAxisDate) {
+				if (dataTime.After(seasonXStartDateWithYearT) && dataTime.Before(seasonXEndDateWithYearT)) || dataTime.Equal(seasonXStartDateWithYearT) || dataTime.Equal(seasonXEndDateWithYearT) {
 					newDataList = append(newDataList, v)
 				}
 			}
@@ -904,7 +873,7 @@ func getEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate
 }
 
 // GetSeasonEdbInfoDataListByXDate 季节性图的指标数据根据横轴展示
-func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latestDate time.Time, seasonExtraConfig string) (quarterDataListSort data_manage.QuarterDataList, err error) {
+func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latestDate time.Time, seasonExtraConfig string) (quarterDataListSort data_manage.QuarterDataList, xStartDateWithYear string, xEndDateWithYear string, err error) {
 	xStartDate := "01-01"
 	xEndDate := "12-31"
 	jumpYear := 0
@@ -954,7 +923,7 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 		return
 	}
 	endYear := lastDateT.Year()
-	nowYear := time.Now().Year()
+	nowYear := endYear
 	chartLegendMaxYear := 0
 	dataMap := make(map[string]data_manage.QuarterXDateItem, 0)
 
@@ -1005,6 +974,8 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 		dataMap[name] = item
 		chartLegendMap[name] = idx
 		idx++
+		xStartDateWithYear = startStr
+		xEndDateWithYear = endStr
 		fmt.Println("年份" + showName + "日期" + startStr + " " + endStr)
 		if lastDateT.Before(endT) {
 			//如果最新的日期在起始日之前,则跳出循环
@@ -1101,7 +1072,7 @@ func GetSeasonEdbInfoDataListByXDate(dataList []*data_manage.EdbDataList, latest
 }
 
 // GetSeasonEdbInfoDataListByXDateNong 季节性图的指标数据根据横轴选择农历时展示
-func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, latestDate time.Time, seasonExtraConfig string, calendarPreYear int) (quarterDataListSort data_manage.QuarterDataList, err error) {
+func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, latestDate time.Time, seasonExtraConfig string, calendarPreYear int) (quarterDataListSort data_manage.QuarterDataList,  xStartDateWithYear string, xEndDateWithYear string, err error) {
 	xStartDate := "01-01"
 	xEndDate := "12-31"
 	jumpYear := 0
@@ -1153,7 +1124,7 @@ func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, late
 		return
 	}
 	endYear := lastDateT.Year()
-	nowYear := time.Now().Year()
+	nowYear := endYear
 	chartLegendMaxYear := 0
 	dataMap := make(map[string]data_manage.QuarterXDateItem, 0)
 
@@ -1206,6 +1177,8 @@ func GetSeasonEdbInfoDataListByXDateNong(result *data_manage.EdbDataResult, late
 		endTmpT = endT
 		chartLegendMap[showName] = idx
 		idx++
+		xStartDateWithYear = startStr
+		xEndDateWithYear = endStr
 		if lastDateT.Before(endT) {
 			//如果最新的日期在起始日之前,则跳出循环
 			break
@@ -3278,6 +3251,15 @@ func GetChartConvertEdbData(chartInfoId, chartType int, calendar, startDate, end
 func getEdbConvertDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string, isAxis int) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
 	// 指标对应的所有数据
 	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
+	seasonXStartDateWithYear := ""
+	seasonXEndDateWithYear := ""
+	// 如果是季节性图则进入特殊排序
+	if chartType == 2 {
+		// 根据设置的左右轴,对mappingList进行排序,1左轴排在前面,0右轴排在前面
+		sort.Slice(mappingList, func(i, j int) bool {
+			return mappingList[i].IsAxis > mappingList[j].IsAxis
+		})
+	}
 
 	for _, v := range mappingList {
 		//fmt.Println("v:", v.EdbInfoId)
@@ -3469,41 +3451,39 @@ func getEdbConvertDataMapList(chartInfoId, chartType int, calendar, startDate, e
 						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
 						return
 					}
-					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
 					if tErr != nil {
 						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 						return
 					}
 					item.DataList = quarterDataList
+					seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+					seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 				}
 
 			} else {
-				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
 				if tErr != nil {
 					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 					return
 				}
 				item.DataList = quarterDataList
+				seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+				seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 			}
 		} else if chartType == 2 && isAxis == 0 {
 			// 右轴数据处理,只要最新一年
-			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
-			if tmpErr != nil {
-				//item.DataList = dataList
-				item.IsNullData = true
-				edbList = append(edbList, item)
-				continue
-				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
-				return
-			}
 			newDataList := make([]*data_manage.EdbDataList, 0)
+			seasonXStartDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXStartDateWithYear)
+			seasonXEndDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXEndDateWithYear)
 			for _, v := range dataList {
 				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
 				if e != nil {
 					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
 					return
 				}
-				if dataTime.Year() == latestDate.Year() {
+				// 如果数据时间在横轴的开始日期和结束日期之间,则加入到数据列表中
+				if (dataTime.After(seasonXStartDateWithYearT) && dataTime.Before(seasonXEndDateWithYearT)) || dataTime.Equal(seasonXStartDateWithYearT) || dataTime.Equal(seasonXEndDateWithYearT) {
 					newDataList = append(newDataList, v)
 				}
 			}

+ 19 - 50
services/data/chart_info_excel_balance.go

@@ -210,7 +210,15 @@ func GetBalanceExcelChartDetail(chartInfo *data_manage.ChartInfoView, mappingLis
 func GetBalanceExcelEdbDataMapList(chartInfoId, chartType int, calendar, startDate, endDate string, mappingList []*data_manage.ChartEdbInfoMapping, seasonExtraConfig string, dataListMap map[int][]*data_manage.EdbDataList) (edbDataListMap map[int][]*data_manage.EdbDataList, edbList []*data_manage.ChartEdbInfoMapping, err error) {
 	// 指标对应的所有数据
 	edbDataListMap = make(map[int][]*data_manage.EdbDataList)
-
+	seasonXStartDateWithYear := ""
+	seasonXEndDateWithYear := ""
+	// 如果是季节性图则进入特殊排序
+	if chartType == 2 {
+		// 根据设置的左右轴,对mappingList进行排序,1左轴排在前面,0右轴排在前面
+		sort.Slice(mappingList, func(i, j int) bool {
+			return mappingList[i].IsAxis > mappingList[j].IsAxis
+		})
+	}
 	for _, v := range mappingList {
 		//fmt.Println("v:", v.EdbInfoId)
 		item := new(data_manage.ChartEdbInfoMapping)
@@ -401,77 +409,38 @@ func GetBalanceExcelEdbDataMapList(chartInfoId, chartType int, calendar, startDa
 						err = errors.New("获取农历数据失败,Err:" + tmpErr.Error())
 						return
 					}
-					quarterDataList, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
+					quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDateNong(result, latestDate, seasonExtraConfig, calendarPreYear)
 					if tErr != nil {
 						err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 						return
 					}
 					item.DataList = quarterDataList
+					seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+					seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 				}
 
 			} else {
-				quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+				quarterDataList, seasonXStartDateWithYearTmp, seasonXEndDateWithYearTmp, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
 				if tErr != nil {
 					err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 					return
 				}
 				item.DataList = quarterDataList
+				seasonXStartDateWithYear = seasonXStartDateWithYearTmp
+				seasonXEndDateWithYear = seasonXEndDateWithYearTmp
 			}
 		} else if chartType == 2 && item.IsAxis == 0 {
-			// 右轴数据处理
-			xStartDate := "01-01"
-
-			jumpYear := 0
-			var seasonExtra data_manage.SeasonExtraItem
-			if seasonExtraConfig != "" {
-				err = json.Unmarshal([]byte(seasonExtraConfig), &seasonExtra)
-				if err != nil {
-					return
-				}
-			}
-
-			if seasonExtra.XStartDate != "" {
-				xStartDate = seasonExtra.XStartDate
-				jumpYear = seasonExtra.JumpYear
-			}
-
-			length := len(dataList)
-			if length == 0 {
-				return
-			}
-			latestDate, tmpErr := time.Parse(utils.FormatDate, v.LatestDate)
-			if tmpErr != nil {
-				//item.DataList = dataList
-				item.IsNullData = true
-				edbList = append(edbList, item)
-				continue
-				err = errors.New(fmt.Sprint("获取最后实际数据的日期失败,Err:" + tmpErr.Error() + ";LatestDate:" + v.LatestDate))
-				return
-			}
-
-			var rightAxisDate time.Time
-			if jumpYear == 1 {
-				latestDate = latestDate.AddDate(-1, 0, 0)
-				latestDateStr := fmt.Sprintf("%d-%s", latestDate.Year(), xStartDate)
-				rightAxisDate, err = time.Parse(utils.FormatDate, latestDateStr)
-				if err != nil {
-					return
-				}
-			}
-
-			nowYear := time.Now().Year()
 			newDataList := make([]*data_manage.EdbDataList, 0)
+			seasonXStartDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXStartDateWithYear)
+			seasonXEndDateWithYearT, _ := time.Parse(utils.FormatDate, seasonXEndDateWithYear)
 			for _, v := range dataList {
 				dataTime, e := time.Parse(utils.FormatDate, v.DataTime)
 				if e != nil {
 					err = errors.New("季节性图处理右轴指标数据转换日期失败,Err:" + e.Error())
 					return
 				}
-				dataTimeT, _ := time.Parse(utils.FormatDate, v.DataTime)
-				year := dataTimeT.Year()
-				newItemDate := dataTimeT.AddDate(nowYear-year, 0, 0)
-				v.DataTimestamp = newItemDate.UnixNano() / 1e6
-				if dataTime.Equal(rightAxisDate) || dataTime.After(rightAxisDate) {
+				// 如果数据时间在横轴的开始日期和结束日期之间,则加入到数据列表中
+				if (dataTime.After(seasonXStartDateWithYearT) && dataTime.Before(seasonXEndDateWithYearT)) || dataTime.Equal(seasonXStartDateWithYearT) || dataTime.Equal(seasonXEndDateWithYearT) {
 					newDataList = append(newDataList, v)
 				}
 			}

+ 1 - 1
services/data/chart_theme.go

@@ -255,7 +255,7 @@ func getThemePreviewEdbDataMapList(chartType int, calendar, startDate, endDate s
 				continue
 			}
 
-			quarterDataList, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
+			quarterDataList, _, _, tErr := GetSeasonEdbInfoDataListByXDate(dataList, latestDate, seasonExtraConfig)
 			if tErr != nil {
 				err = errors.New("获取季节性图表数据失败,Err:" + tErr.Error())
 				return

+ 42 - 0
services/english_report.go

@@ -964,3 +964,45 @@ func UpdateEnglishCompanyEnabledByCompanyId(companyId int) (err error) {
 	}
 	return
 }
+
+// GetEnglishReportToken
+// @Description: 获取token
+// @author: Roc
+// @datetime 2025-03-18 10:35:11
+// @param reportId int
+// @param reportCode string
+// @return token string
+// @return err error
+func GetEnglishReportToken(reportId int, reportCode string) (token string, err error) {
+	// 图表授权token
+	token = utils.MD5(fmt.Sprint(reportCode, time.Now().UnixNano()/1e6))
+	err = generalReportAuthToken(token, `en:`, reportId)
+
+	return
+}
+
+func GetGeneralEnglishReportPdfUrl(reportId int, reportCode string) (pdfUrl string) {
+	// 优先取Report2ImgUrl(用于兼容内外网环境的), 没有的话取报告详情地址
+	var reportUrl string
+	conf, _ := models.GetBusinessConfByKey(models.BusinessConfReport2ImgUrl)
+	if conf != nil && conf.ConfVal != "" {
+		reportUrl = conf.ConfVal
+	}
+	if reportUrl == "" {
+		conf, e := models.GetBusinessConfByKey(models.BusinessConfReportViewUrl)
+		if e != nil {
+			return
+		}
+		reportUrl = conf.ConfVal
+	}
+
+	token := utils.MD5(fmt.Sprint(pdfUrl, time.Now().UnixNano()/1e6))
+	e := generalReportAuthToken(token, `en:`, reportId)
+	if e == nil {
+		pdfUrl = fmt.Sprintf("%s&authToken=%s", pdfUrl, token)
+	}
+
+	pdfUrl = fmt.Sprintf("%s/reportshare_pdf_en?code=%s&authToken=%s", reportUrl, reportCode, token)
+
+	return
+}

+ 74 - 47
services/ppt/ppt_english_group.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_mobile/models/system"
 	"eta/eta_mobile/utils"
 	"fmt"
+	"github.com/shopspring/decimal"
 	"sort"
 	"strconv"
 	"strings"
@@ -60,11 +61,23 @@ func AddGroupPptEnglishMapping(pptId int64, groupId int64, adminId int, adminRea
 		err = errors.New("目录查询出错:" + err.Error())
 		return
 	}
+
+	// 获取当前目录下最大的排序
+	pptSort, err := ppt_english.GetMaxSortByEnglishGroupId(groupId)
+	if err != nil {
+		err = errors.New("查询最大排序出错:" + err.Error())
+		return
+	}
+	newSort, _ := decimal.NewFromFloat(pptSort).Add(decimal.NewFromInt(1)).Float64()
+
 	bindInfo := &ppt_english.PptEnglishGroupMapping{
 		GroupId:       groupId,
 		PptId:         pptId,
 		AdminId:       adminId,
 		AdminRealName: adminRealName,
+		PptSort:       newSort,
+		CreateTime:    time.Now(),
+		ModifyTime:    time.Now(),
 	}
 
 	newId, err = ppt_english.AddPptGroupMapping(bindInfo)
@@ -74,12 +87,13 @@ func AddGroupPptEnglishMapping(pptId int64, groupId int64, adminId int, adminRea
 	}
 
 	bindInfo.GroupPptId = newId
-	bindInfo.PptSort = newId
-	err = bindInfo.Update([]string{"ppt_sort"})
-	if err != nil {
-		err = errors.New("更新排序失败:" + err.Error())
-		return
-	}
+	//bindInfo.PptSort = newId
+	//err = bindInfo.Update([]string{"ppt_sort"})
+	//if err != nil {
+	//	err = errors.New("更新排序失败:" + err.Error())
+	//	return
+	//}
+
 	return
 }
 
@@ -176,7 +190,7 @@ func CopyEnglishGroup(groupId int64, adminId int, adminRealName string) (err err
 		return
 	}
 	//查询该目录下面是否存在ppt,如果存在则批量复制ppt到新目录下
-	mappingList, err := ppt_english.GetPptMappingListByGroupId(groupId)
+	mappingList, err := ppt_english.GetPptMappingListByGroupIdDesc(groupId)
 	if err != nil {
 		err = errors.New("查询目录里的ppt列表出错:" + err.Error())
 		return
@@ -194,6 +208,11 @@ func CopyEnglishGroup(groupId int64, adminId int, adminRealName string) (err err
 		err = errors.New("查询ppt列表出错:" + err.Error())
 		return
 	}
+	pptMap := make(map[int]*ppt_english.PptEnglish)
+	for _, pptItem := range pptList {
+		pptMap[pptItem.PptId] = pptItem
+	}
+
 	pptNames, err := ppt_english.GetAllPptTitle()
 	if err != nil {
 		err = errors.New("查询ppt标题出错:" + err.Error())
@@ -201,23 +220,32 @@ func CopyEnglishGroup(groupId int64, adminId int, adminRealName string) (err err
 	}
 	//批量复制ppt,更新作者为当前账号,并返回新的pptID
 	newPptList := make([]*ppt_english.PptEnglish, 0)
-	for _, v := range pptList {
+	for _, mapping := range mappingList {
+		pptItem, ok := pptMap[int(mapping.PptId)]
+		// 不存在该ppt,那么就过滤
+		if !ok {
+			continue
+		}
+
 		tmp := &ppt_english.PptEnglish{
-			TemplateType:  v.TemplateType,
-			BackgroundImg: v.BackgroundImg,
-			Title:         generateCopyName(v.Title, 1, pptNames),
-			ReportType:    v.ReportType,
-			PptDate:       v.PptDate,
-			Content:       v.Content,
-			CoverContent:  v.CoverContent,
+			TemplateType:  pptItem.TemplateType,
+			BackgroundImg: pptItem.BackgroundImg,
+			Title:         generateCopyName(pptItem.Title, 1, pptNames),
+			ReportType:    pptItem.ReportType,
+			PptDate:       pptItem.PptDate,
+			Content:       pptItem.Content,
+			CoverContent:  pptItem.CoverContent,
 			CreateTime:    time.Now(),
 			ModifyTime:    time.Now(),
 			AdminId:       adminId,
 			AdminRealName: adminRealName,
+			TitleSetting:  pptItem.TitleSetting,
 		}
 		newPptList = append(newPptList, tmp)
 	}
-	if len(newPptList) > 0 {
+
+	pptNum := len(newPptList)
+	if pptNum > 0 {
 		err = ppt_english.AddPptEnglishMulti(newPptList)
 		if err != nil {
 			err = errors.New("复制目录里的ppt出错:" + err.Error())
@@ -225,12 +253,13 @@ func CopyEnglishGroup(groupId int64, adminId int, adminRealName string) (err err
 		}
 
 		newMappings := make([]*ppt_english.PptEnglishGroupMapping, 0)
-		for _, v := range newPptList {
+		for k, v := range newPptList {
 			tmp := &ppt_english.PptEnglishGroupMapping{
 				GroupId:       newGroupId,
 				PptId:         int64(v.PptId),
 				CreateTime:    time.Now(),
 				ModifyTime:    time.Now(),
+				PptSort:       float64(pptNum - k),
 				AdminId:       adminId,
 				AdminRealName: adminRealName,
 			}
@@ -242,15 +271,15 @@ func CopyEnglishGroup(groupId int64, adminId int, adminRealName string) (err err
 			return
 		}
 		//批量更新排序字段
-		var newGroupPptIds []int64
-		for _, v := range newMappings {
-			newGroupPptIds = append(newGroupPptIds, v.GroupPptId)
-		}
-		err = ppt_english.UpdatePptGroupMappingSortMulti(newGroupPptIds)
-		if err != nil {
-			err = errors.New("更新排序标识出错:" + err.Error())
-			return
-		}
+		//var newGroupPptIds []int64
+		//for _, v := range newMappings {
+		//	newGroupPptIds = append(newGroupPptIds, v.GroupPptId)
+		//}
+		//err = ppt_english.UpdatePptGroupMappingSortMulti(newGroupPptIds)
+		//if err != nil {
+		//	err = errors.New("更新排序标识出错:" + err.Error())
+		//	return
+		//}
 	}
 	return
 }
@@ -371,7 +400,7 @@ func GetGroupPptEnglishList(groupId int64, adminId int) (ret ppt_english.RespGro
 			return
 		}
 		groups = append(groups, groupInfo)
-		groupPptList, tErr = ppt_english.GetPptMappingListByGroupId(groupId)
+		groupPptList, tErr = ppt_english.GetPptMappingListByGroupIdDesc(groupId)
 		if tErr != nil {
 			err = errors.New("目录里的ppt查询出错:" + tErr.Error())
 			return
@@ -462,8 +491,6 @@ func MoveGroupPptEnglish(groupId, groupPptId, prevGroupPptId, nextGroupPptId int
 		return
 	}
 	var updateStr []string
-	//如果更换了目录,默认当前排序值为0
-	var currentSort, prevSort, nextSort int64
 	//判断是否更换group
 	if groupPpt.GroupId != groupId {
 		_, err = ppt_english.GetPptGroupByGroupIdAdminId(groupId, adminId)
@@ -485,7 +512,6 @@ func MoveGroupPptEnglish(groupId, groupPptId, prevGroupPptId, nextGroupPptId int
 		groupPpt.GroupId = groupId
 		updateStr = append(updateStr, "group_id")
 	}
-	currentSort = groupPpt.PptSort
 
 	var prevGroupPpt *ppt_english.PptEnglishGroupMapping
 	var nextGroupPpt *ppt_english.PptEnglishGroupMapping
@@ -499,7 +525,6 @@ func MoveGroupPptEnglish(groupId, groupPptId, prevGroupPptId, nextGroupPptId int
 			err = errors.New("目录下的ppt查询出错:" + err.Error())
 			return
 		}
-		prevSort = prevGroupPpt.PptSort
 	}
 
 	if nextGroupPptId > 0 {
@@ -512,29 +537,31 @@ func MoveGroupPptEnglish(groupId, groupPptId, prevGroupPptId, nextGroupPptId int
 			err = errors.New("目录下的ppt查询出错:" + err.Error())
 			return
 		}
-		nextSort = nextGroupPpt.PptSort
 	}
 
-	updateStr = append(updateStr, "ppt_sort")
-
-	//移到两个排序值中间操作
-	if prevSort >= currentSort {
-		//往下移动
-		err = ppt_english.MoveDownGroupPptBySort(groupId, prevSort, currentSort)
-		if err != nil {
-			err = errors.New("向下移动ppt出错:" + err.Error())
+	pptSort := groupPpt.PptSort
+	if prevGroupPpt != nil && prevGroupPpt.PptId > 0 && nextGroupPpt != nil && nextGroupPpt.PptId > 0 { // 两个之间
+		pptSort, _ = decimal.NewFromFloat(prevGroupPpt.PptSort).Add(decimal.NewFromFloat(nextGroupPpt.PptSort)).Div(decimal.NewFromInt(2)).Float64()
+	} else if prevGroupPpt != nil && prevGroupPpt.PptId > 0 {
+		// 最下面
+		maxSort, tmpErr := ppt_english.GetMinSortByEnglishGroupId(prevGroupPpt.GroupId)
+		if tmpErr != nil {
+			err = errors.New("获取最小排序失败:" + tmpErr.Error())
 			return
 		}
-		groupPpt.PptSort = prevSort
-	} else if nextSort <= currentSort && nextSort != 0 {
-		//往上移动
-		err = ppt_english.MoveUpGroupPptBySort(groupId, nextSort, currentSort)
-		if err != nil {
-			err = errors.New("向上移动ppt出错:" + err.Error())
+		pptSort, _ = decimal.NewFromFloat(maxSort).Sub(decimal.NewFromInt(1)).Float64()
+	} else if nextGroupPpt != nil && nextGroupPpt.PptId > 0 {
+		// 最上面
+		minSort, tmpErr := ppt_english.GetMaxSortByEnglishGroupId(nextGroupPpt.GroupId)
+		if tmpErr != nil {
+			err = errors.New("获取最小排序失败:" + tmpErr.Error())
 			return
 		}
-		groupPpt.PptSort = nextSort
+		pptSort, _ = decimal.NewFromFloat(minSort).Add(decimal.NewFromInt(1)).Float64()
 	}
+
+	groupPpt.PptSort = pptSort
+	updateStr = append(updateStr, "ppt_sort")
 	//更新当前排序
 	err = groupPpt.Update(updateStr)
 	if err != nil {

+ 89 - 185
services/ppt/ppt_group.go

@@ -7,6 +7,7 @@ import (
 	"eta/eta_mobile/models/system"
 	"eta/eta_mobile/utils"
 	"fmt"
+	"github.com/shopspring/decimal"
 	"sort"
 	"strconv"
 	"strings"
@@ -224,11 +225,23 @@ func AddGroupPptMapping(pptId int64, groupId int64, adminId int, adminRealName s
 		err = errors.New("目录查询出错:" + err.Error())
 		return
 	}
+
+	// 获取当前目录下最大的排序
+	pptSort, err := models.GetMaxSortByGroupId(groupId)
+	if err != nil {
+		err = errors.New("查询最大排序出错:" + err.Error())
+		return
+	}
+	newSort, _ := decimal.NewFromFloat(pptSort).Add(decimal.NewFromInt(1)).Float64()
+
 	bindInfo := &models.PptV2GroupMapping{
 		GroupId:       groupId,
 		PptId:         pptId,
 		AdminId:       adminId,
 		AdminRealName: adminRealName,
+		CreateTime:    time.Now(),
+		ModifyTime:    time.Now(),
+		PptSort:       newSort,
 	}
 
 	newId, err = models.AddPptGroupMapping(bindInfo)
@@ -238,12 +251,12 @@ func AddGroupPptMapping(pptId int64, groupId int64, adminId int, adminRealName s
 	}
 
 	bindInfo.GroupPptId = newId
-	bindInfo.PptSort = newId
-	err = bindInfo.Update([]string{"ppt_sort"})
-	if err != nil {
-		err = errors.New("更新排序失败:" + err.Error())
-		return
-	}
+	//bindInfo.PptSort = newId
+	//err = bindInfo.Update([]string{"ppt_sort"})
+	//if err != nil {
+	//	err = errors.New("更新排序失败:" + err.Error())
+	//	return
+	//}
 	return
 }
 
@@ -358,6 +371,11 @@ func CopyGroup(groupId int64, adminId int, adminRealName string) (err error) {
 		err = errors.New("查询ppt列表出错:" + err.Error())
 		return
 	}
+	pptMap := make(map[int]*models.PptV2)
+	for _, pptItem := range pptList {
+		pptMap[pptItem.PptId] = pptItem
+	}
+
 	pptNames, err := models.GetAllPptTitle()
 	if err != nil {
 		err = errors.New("查询ppt标题出错:" + err.Error())
@@ -365,29 +383,35 @@ func CopyGroup(groupId int64, adminId int, adminRealName string) (err error) {
 	}
 	//批量复制ppt,更新作者为当前账号,并返回新的pptID
 	newPptList := make([]*models.PptV2, 0)
-	for _, v := range pptList {
-		if v.PptVersion != 2 { //只复制新版的ppt,旧版本的ppt忽略
+	for _, mapping := range mappingList {
+		pptItem, ok := pptMap[int(mapping.PptId)]
+		// 不存在该ppt,那么就过滤
+		if !ok {
+			continue
+		}
+		if pptItem.PptVersion != 2 { //只复制新版的ppt,旧版本的ppt忽略
 			continue
 		}
 		tmp := &models.PptV2{
-			TemplateType:  v.TemplateType,
-			BackgroundImg: v.BackgroundImg,
-			Title:         generateCopyName(v.Title, 1, pptNames),
-			ReportType:    v.ReportType,
-			PptDate:       v.PptDate,
-			Content:       v.Content,
-			CoverContent:  v.CoverContent,
-			PptUrl:        v.PptUrl,
-			PptxUrl:       v.PptxUrl,
+			TemplateType:  pptItem.TemplateType,
+			BackgroundImg: pptItem.BackgroundImg,
+			Title:         generateCopyName(pptItem.Title, 1, pptNames),
+			ReportType:    pptItem.ReportType,
+			PptDate:       pptItem.PptDate,
+			Content:       pptItem.Content,
+			CoverContent:  pptItem.CoverContent,
+			PptUrl:        pptItem.PptUrl,
+			PptxUrl:       pptItem.PptxUrl,
 			CreateTime:    time.Now(),
 			ModifyTime:    time.Now(),
 			AdminId:       adminId,
 			AdminRealName: adminRealName,
-			PptVersion:    v.PptVersion,
+			PptVersion:    pptItem.PptVersion,
 		}
 		newPptList = append(newPptList, tmp)
 	}
-	if len(newPptList) > 0 {
+	pptNum := len(newPptList)
+	if pptNum > 0 {
 		err = models.AddPptV2Multi(newPptList)
 		if err != nil {
 			err = errors.New("复制目录里的ppt出错:" + err.Error())
@@ -395,7 +419,7 @@ func CopyGroup(groupId int64, adminId int, adminRealName string) (err error) {
 		}
 
 		newMappings := make([]*models.PptV2GroupMapping, 0)
-		for _, v := range newPptList {
+		for k, v := range newPptList {
 			tmp := &models.PptV2GroupMapping{
 				GroupId:       newGroupId,
 				PptId:         int64(v.PptId),
@@ -403,6 +427,7 @@ func CopyGroup(groupId int64, adminId int, adminRealName string) (err error) {
 				ModifyTime:    time.Now(),
 				AdminId:       adminId,
 				AdminRealName: adminRealName,
+				PptSort:       float64(pptNum - k),
 			}
 			newMappings = append(newMappings, tmp)
 		}
@@ -412,15 +437,15 @@ func CopyGroup(groupId int64, adminId int, adminRealName string) (err error) {
 			return
 		}
 		//批量更新排序字段
-		var newGroupPptIds []int64
-		for _, v := range newMappings {
-			newGroupPptIds = append(newGroupPptIds, v.GroupPptId)
-		}
-		err = models.UpdatePptGroupMappingSortMulti(newGroupPptIds)
-		if err != nil {
-			err = errors.New("更新排序标识出错:" + err.Error())
-			return
-		}
+		//var newGroupPptIds []int64
+		//for _, v := range newMappings {
+		//	newGroupPptIds = append(newGroupPptIds, v.GroupPptId)
+		//}
+		//err = models.UpdatePptGroupMappingSortMulti(newGroupPptIds)
+		//if err != nil {
+		//	err = errors.New("更新排序标识出错:" + err.Error())
+		//	return
+		//}
 	}
 	return
 }
@@ -651,8 +676,6 @@ func MoveGroupPpt(groupId, groupPptId, prevGroupPptId, nextGroupPptId int64, adm
 		return
 	}
 	var updateStr []string
-	//如果更换了目录,默认当前排序值为0
-	var currentSort, prevSort, nextSort int64
 	//判断是否更换group
 	if groupPpt.GroupId != groupId {
 		_, err = models.GetPptGroupByGroupIdAdminId(groupId, adminId)
@@ -674,7 +697,6 @@ func MoveGroupPpt(groupId, groupPptId, prevGroupPptId, nextGroupPptId int64, adm
 		groupPpt.GroupId = groupId
 		updateStr = append(updateStr, "group_id")
 	}
-	currentSort = groupPpt.PptSort
 
 	var prevGroupPpt *models.PptV2GroupMapping
 	var nextGroupPpt *models.PptV2GroupMapping
@@ -688,7 +710,6 @@ func MoveGroupPpt(groupId, groupPptId, prevGroupPptId, nextGroupPptId int64, adm
 			err = errors.New("目录下的ppt查询出错:" + err.Error())
 			return
 		}
-		prevSort = prevGroupPpt.PptSort
 	}
 
 	if nextGroupPptId > 0 {
@@ -701,29 +722,31 @@ func MoveGroupPpt(groupId, groupPptId, prevGroupPptId, nextGroupPptId int64, adm
 			err = errors.New("目录下的ppt查询出错:" + err.Error())
 			return
 		}
-		nextSort = nextGroupPpt.PptSort
 	}
 
-	updateStr = append(updateStr, "ppt_sort")
-
-	//移到两个排序值中间操作
-	if prevSort >= currentSort {
-		//往下移动
-		err = models.MoveDownGroupPptBySort(groupId, prevSort, currentSort)
-		if err != nil {
-			err = errors.New("向下移动ppt出错:" + err.Error())
+	pptSort := groupPpt.PptSort
+	if prevGroupPpt != nil && prevGroupPpt.PptId > 0 && nextGroupPpt != nil && nextGroupPpt.PptId > 0 { // 两个之间
+		pptSort, _ = decimal.NewFromFloat(prevGroupPpt.PptSort).Add(decimal.NewFromFloat(nextGroupPpt.PptSort)).Div(decimal.NewFromInt(2)).Float64()
+	} else if prevGroupPpt != nil && prevGroupPpt.PptId > 0 {
+		// 最下面
+		maxSort, tmpErr := models.GetMinSortByGroupId(prevGroupPpt.GroupId)
+		if tmpErr != nil {
+			err = errors.New("获取最小排序失败:" + tmpErr.Error())
 			return
 		}
-		groupPpt.PptSort = prevSort
-	} else if nextSort <= currentSort && nextSort != 0 {
-		//往上移动
-		err = models.MoveUpGroupPptBySort(groupId, nextSort, currentSort)
-		if err != nil {
-			err = errors.New("向上移动ppt出错:" + err.Error())
+		pptSort, _ = decimal.NewFromFloat(maxSort).Sub(decimal.NewFromInt(1)).Float64()
+	} else if nextGroupPpt != nil && nextGroupPpt.PptId > 0 {
+		// 最上面
+		minSort, tmpErr := models.GetMaxSortByGroupId(nextGroupPpt.GroupId)
+		if tmpErr != nil {
+			err = errors.New("获取最小排序失败:" + tmpErr.Error())
 			return
 		}
-		groupPpt.PptSort = nextSort
+		pptSort, _ = decimal.NewFromFloat(minSort).Add(decimal.NewFromInt(1)).Float64()
 	}
+
+	groupPpt.PptSort = pptSort
+	updateStr = append(updateStr, "ppt_sort")
 	//更新当前排序
 	err = groupPpt.Update(updateStr)
 	if err != nil {
@@ -941,6 +964,15 @@ func CopyPpt(pptId int, groupId int64, adminId int, adminRealName string) (resp
 		err = errors.New("复制目录里的ppt出错:" + err.Error())
 		return
 	}
+
+	// 获取当前目录下最大的排序
+	pptSort, err := models.GetMaxSortByGroupId(groupId)
+	if err != nil {
+		err = errors.New("查询最大排序出错:" + err.Error())
+		return
+	}
+	newSort, _ := decimal.NewFromFloat(pptSort).Add(decimal.NewFromInt(1)).Float64()
+
 	var newMappings []*models.PptV2GroupMapping
 	newGroupPpt := &models.PptV2GroupMapping{
 		GroupId:       groupId,
@@ -949,6 +981,7 @@ func CopyPpt(pptId int, groupId int64, adminId int, adminRealName string) (resp
 		ModifyTime:    time.Now(),
 		AdminId:       adminId,
 		AdminRealName: adminRealName,
+		PptSort:       newSort,
 	}
 	newMappings = append(newMappings, newGroupPpt)
 
@@ -957,12 +990,12 @@ func CopyPpt(pptId int, groupId int64, adminId int, adminRealName string) (resp
 		err = errors.New("复制目录里的ppt出错:" + err.Error())
 		return
 	}
-	//批量更新排序字段
-	err = models.UpdatePptGroupMappingSortMulti([]int64{newGroupPpt.GroupPptId})
-	if err != nil {
-		err = errors.New("更新排序标识出错:" + err.Error())
-		return
-	}
+	////批量更新排序字段
+	//err = models.UpdatePptGroupMappingSortMulti([]int64{newGroupPpt.GroupPptId})
+	//if err != nil {
+	//	err = errors.New("更新排序标识出错:" + err.Error())
+	//	return
+	//}
 	pptPage := 0
 	// 因之前并没有存储PPT页数字段,所以此处读取PPT内容的长度
 	if newPpt.Content != "" {
@@ -1045,134 +1078,6 @@ func SearchGroupPpt(keyWord string) (ret models.RespSearchGroupPptList, err erro
 	return
 }
 
-// InitPptGroup 初始化目录分组
-func InitPptGroup() (err error) {
-	//查询所有的ppt
-	now := time.Now()
-	pptList, err := models.GetPptV2ByCondition("", []interface{}{})
-	if err != nil {
-		errors.New("查询所有的ppt出错" + err.Error())
-		return
-	}
-	pptAdminMap := make(map[int]string, 0)
-	adminPptListMap := make(map[int][]*models.PptV2)
-	oldPptAdminMap := make(map[int]string, 0)
-	oldAdminPptListMap := make(map[int][]*models.PptV2)
-	//查询所有的ppt作者
-	for _, v := range pptList {
-		if v.PptVersion == 2 {
-			if _, ok := pptAdminMap[v.AdminId]; !ok {
-				pptAdminMap[v.AdminId] = v.AdminRealName
-			}
-			adminPptListMap[v.AdminId] = append(adminPptListMap[v.AdminId], v)
-		} else {
-			if _, ok := oldPptAdminMap[v.AdminId]; !ok {
-				oldPptAdminMap[v.AdminId] = v.AdminRealName
-			}
-			oldAdminPptListMap[v.AdminId] = append(oldAdminPptListMap[v.AdminId], v)
-		}
-	}
-	//批量生成历史目录,共享目录
-	newOldGroupList := make([]*models.PptV2Group, 0)
-	//批量生成目录,共享目录
-	newGroupList := make([]*models.PptV2Group, 0)
-	if len(pptAdminMap) > 0 {
-		for k, v := range pptAdminMap {
-			tmp := &models.PptV2Group{
-				GroupName:  v + "的PPT",
-				AdminId:    k,
-				IsShare:    1,
-				CreateTime: now,
-				ModifyTime: now,
-				ShareTime:  now,
-			}
-			newGroupList = append(newGroupList, tmp)
-		}
-		//批量把对应的ppt放到目录当中
-		err = models.AddPptGroupMulti(newGroupList)
-		if err != nil {
-			err = errors.New("创建目录出错:" + err.Error())
-			return
-		}
-	}
-	if len(oldPptAdminMap) > 0 {
-		for k, v := range oldPptAdminMap {
-			tmp := &models.PptV2Group{
-				GroupName:  v + "的历史PPT",
-				AdminId:    k,
-				IsShare:    1,
-				CreateTime: now,
-				ModifyTime: now,
-				ShareTime:  now,
-			}
-			newOldGroupList = append(newOldGroupList, tmp)
-		}
-		//批量把对应的ppt放到目录当中
-		err = models.AddPptGroupMulti(newOldGroupList)
-		if err != nil {
-			err = errors.New("创建目录出错:" + err.Error())
-			return
-		}
-	}
-	//批量更新排序字段
-	var newGroupIds []int64
-	var newMappings []*models.PptV2GroupMapping
-	for _, v := range newGroupList {
-		newGroupIds = append(newGroupIds, v.GroupId)
-		if ppts, ok := adminPptListMap[v.AdminId]; ok {
-			for _, p := range ppts {
-				tmp := &models.PptV2GroupMapping{
-					GroupId:       v.GroupId,
-					PptId:         int64(p.PptId),
-					CreateTime:    now,
-					ModifyTime:    now,
-					AdminId:       p.AdminId,
-					AdminRealName: p.AdminRealName,
-				}
-				newMappings = append(newMappings, tmp)
-			}
-		}
-	}
-	for _, v := range newOldGroupList {
-		newGroupIds = append(newGroupIds, v.GroupId)
-		if oldPpts, ok1 := oldAdminPptListMap[v.AdminId]; ok1 {
-			for _, p := range oldPpts {
-				tmp := &models.PptV2GroupMapping{
-					GroupId:       v.GroupId,
-					PptId:         int64(p.PptId),
-					CreateTime:    now,
-					ModifyTime:    now,
-					AdminId:       p.AdminId,
-					AdminRealName: p.AdminRealName,
-				}
-				newMappings = append(newMappings, tmp)
-			}
-		}
-	}
-	err = models.UpdatePptGroupSortMulti(newGroupIds)
-	if err != nil {
-		err = errors.New("更新目录排序标识出错:" + err.Error())
-		return
-	}
-
-	err = models.AddPptGroupMappingMulti(newMappings)
-	if err != nil {
-		err = errors.New("创建目录里的ppt出错:" + err.Error())
-		return
-	}
-	//批量更新排序字段
-	var newGroupPptIds []int64
-	for _, v := range newMappings {
-		newGroupPptIds = append(newGroupPptIds, v.GroupPptId)
-	}
-	err = models.UpdatePptGroupMappingSortMulti(newGroupPptIds)
-	if err != nil {
-		err = errors.New("更新排序标识出错:" + err.Error())
-		return
-	}
-	return
-}
-
 // GetGroupsByAdminIdV2 查询ppt目录列表
 // @Author roc
 // @Time 2022-08-29 15:22:20
@@ -1745,7 +1650,6 @@ func GetPptList(adminId int, keyword string) (ret models.RespGroupPptList, err e
 	return
 }
 
-
 // SearchPptList PPT搜索(我的/公开PPT)
 func SearchPptList(adminId int, keyword string) (ret models.RespGroupPptList, err error) {
 	list := make([]*models.RespGroupPptListItem, 0)
@@ -1791,4 +1695,4 @@ func SearchPptList(adminId int, keyword string) (ret models.RespGroupPptList, er
 	ret.List = list
 	ret.Total = len(list)
 	return
-}
+}

+ 1 - 1
services/report_approve.go

@@ -841,7 +841,7 @@ func AfterReportApprovePass(reportType, reportId int) (err error) {
 
 		// 生成报告pdf和长图
 		{
-			reportPdfUrl := GetGeneralPdfUrl(reportInfo.ReportCode, reportInfo.ReportLayout)
+			reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
 			go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
 		}
 

+ 415 - 3
services/report_v2.go

@@ -2,6 +2,7 @@ package services
 
 import (
 	"archive/zip"
+	"encoding/json"
 	"errors"
 	"eta/eta_mobile/models"
 	"eta/eta_mobile/models/report"
@@ -11,10 +12,17 @@ import (
 	"fmt"
 	"github.com/rdlucklib/rdluck_tools/file"
 	"github.com/rdlucklib/rdluck_tools/http"
+	html2 "golang.org/x/net/html"
+	"net/url"
 	"os"
 	"path"
 	"strconv"
+	"strings"
 	"time"
+
+	"github.com/beego/beego/v2/server/web"
+	"github.com/beego/beego/v2/server/web/context"
+	"github.com/go-redis/redis/v8"
 )
 
 // AddReportAndChapter
@@ -1207,7 +1215,7 @@ func PublishReport(reportId int, reportUrl string, sysUser *system.Admin) (tips
 
 	// 生成报告pdf和长图
 	{
-		reportPdfUrl := GetGeneralPdfUrl(reportInfo.ReportCode, reportInfo.ReportLayout)
+		reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
 		go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
 	}
 
@@ -1334,7 +1342,7 @@ func PublishChapterReport(reportInfo *models.Report, reportUrl string, sysUser *
 
 	// 生成报告pdf和长图
 	{
-		reportPdfUrl := GetGeneralPdfUrl(reportInfo.ReportCode, reportInfo.ReportLayout)
+		reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
 		go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
 	}
 
@@ -1495,7 +1503,7 @@ func UpdateReportVideo(reportInfo *models.Report) {
 // @param reportCode string
 // @param reportLayout int8
 // @return pdfUrl string
-func GetGeneralPdfUrl(reportCode string, reportLayout int8) (pdfUrl string) {
+func GetGeneralPdfUrl(reportId int, reportCode string, reportLayout int8) (pdfUrl string) {
 	conf, e := models.GetBusinessConfByKey("ReportViewUrl")
 	if e != nil {
 		return
@@ -1510,5 +1518,409 @@ func GetGeneralPdfUrl(reportCode string, reportLayout int8) (pdfUrl string) {
 		pdfUrl = fmt.Sprintf("%s/reportshare_smart_pdf?code=%s", conf.ConfVal, reportCode)
 	}
 
+	if pdfUrl != "" {
+		token := utils.MD5(fmt.Sprint(pdfUrl, time.Now().UnixNano()/1e6))
+		e := generalReportAuthToken(token, ``, reportId)
+		if e == nil {
+			pdfUrl = fmt.Sprintf("%s&authToken=%s", pdfUrl, token)
+		}
+	}
+
+	return
+}
+
+// HandleReportContent
+// @Description: 处理报告内容(动态图表/表格添加授权token)
+// @author: Roc
+// @datetime 2025-01-07 10:03:15
+// @param body string
+// @return newBody string
+func HandleReportContent(body string, opType string, tokenMap map[string]string) (newBody string) {
+	if body == `` {
+		return
+	}
+	newBody = body
+
+	// 解析HTML
+	doc, err := html2.Parse(strings.NewReader(body))
+	if err != nil {
+		fmt.Println("Error parsing HTML:", err)
+		return
+	}
+
+	replaceIframeSrc(doc, opType, tokenMap)
+
+	// 输出修改后的HTML
+	var modifiedHtml strings.Builder
+	err = html2.Render(&modifiedHtml, doc)
+	if err != nil {
+		fmt.Println("Error rendering HTML:", err)
+		return
+	}
+
+	newBody = modifiedHtml.String()
+	fmt.Println(newBody)
+
+	return
+}
+
+// replaceIframeSrc 遍历HTML节点,替换iframe的src属性
+func replaceIframeSrc(n *html2.Node, opType string, tokenMap map[string]string) {
+	if n.Type == html2.ElementNode && n.Data == "iframe" {
+		for i, attr := range n.Attr {
+			if attr.Key == "src" {
+				newLink := attr.Val
+				// 处理链接
+				switch opType {
+				case `add`:
+					newLink = linkAddToken(attr.Val, tokenMap)
+				case `del`:
+					newLink = linkDelToken(attr.Val)
+				}
+				// 替换原来的链接
+				n.Attr[i].Val = newLink
+				break
+			}
+		}
+	}
+	// 递归处理子节点
+	for c := n.FirstChild; c != nil; c = c.NextSibling {
+		replaceIframeSrc(c, opType, tokenMap)
+	}
+}
+
+// linkAddToken 链接添加token
+func linkAddToken(link string, tokenMap map[string]string) string {
+	var err error
+	defer func() {
+		if err != nil {
+			utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
+		}
+	}()
+	parsedURL, err := url.Parse(link)
+	if err != nil {
+		return link
+	}
+
+	// 获取查询参数
+	queryParams := parsedURL.Query()
+
+	// 先移除authToken参数,避免莫名其妙的这个值入库了
+	queryParams.Del("authToken")
+
+	// 获取code参数
+	code := queryParams.Get("code")
+	if code == "" {
+		return link
+	}
+
+	showType := `chart`
+	if strings.Contains(parsedURL.Path, "sheetshow") {
+		showType = `excel`
+	}
+
+	// 避免报告里面一个图表/表格重复生成token
+	var token string
+	key := fmt.Sprint(showType, `:`, code)
+	if tokenMap != nil {
+		token = tokenMap[key]
+	}
+
+	// 如果之前没有token,那么就重新生成token
+	if token == `` {
+		token, err = GeneralChartToken(showType, code, 30*time.Minute)
+		if err != nil {
+			return link
+		}
+	}
+
+	if tokenMap != nil {
+		tokenMap[key] = token
+	}
+
+	// 在链接后面添加一个token值
+	queryParams.Add("authToken", token)
+
+	// 更新URL的查询参数
+	parsedURL.RawQuery = queryParams.Encode()
+
+	return parsedURL.String()
+}
+
+// linkDelToken 链接添加token
+func linkDelToken(link string) string {
+	var err error
+	defer func() {
+		if err != nil {
+			utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
+		}
+	}()
+	parsedURL, err := url.Parse(link)
+	if err != nil {
+		return link
+	}
+
+	// 获取查询参数
+	queryParams := parsedURL.Query()
+
+	// 移除authToken参数
+	queryParams.Del("authToken")
+
+	// 更新URL的查询参数
+	parsedURL.RawQuery = queryParams.Encode()
+
+	return parsedURL.String()
+}
+
+// GeneralChartToken
+// @Description: 生产图表/表格授权token
+// @author: Roc
+// @datetime 2025-01-07 10:41:36
+// @param showType string
+// @param uniqueCode string
+// @param expireTime time.Duration
+// @return token string
+// @return err error
+func GeneralChartToken(showType, uniqueCode string, expireTime time.Duration) (token string, err error) {
+	// 缓存key
+	token = utils.MD5(fmt.Sprint(showType+`:`, uniqueCode, time.Now().UnixNano()/1e6))
+	key := fmt.Sprint(utils.CACHE_CHART_AUTH, token)
+	err = utils.Rc.Put(key, uniqueCode, expireTime)
+
+	return
+}
+
+// GeneralReportToken
+// @Description: 生成报告授权token
+// @author: Roc
+// @datetime 2025-01-07 10:41:36
+// @param uniqueCode string
+// @return token string
+// @return err error
+func GeneralReportToken(linkToken string, reportId int) (token string, err error) {
+	// 图表授权token
+	token = utils.MD5(fmt.Sprint(linkToken, time.Now().UnixNano()/1e6))
+
+	// 缓存key
+	reportKey := getReportShareTokenKey(linkToken)
+	err = utils.Rc.Put(reportKey, token, utils.BusinessConfReportChartExpiredTime)
+	if err != nil {
+		return
+	}
+
+	// 生成报告的图表授权token
+	err = generalReportAuthToken(token, ``, reportId)
+	if err != nil {
+		return
+	}
+
 	return
 }
+
+// generalReportAuthToken
+// @Description: 生成报告的图表授权token
+// @author: Roc
+// @datetime 2025-03-17 17:47:07
+// @param token string
+// @param reportId int
+// @return err error
+func generalReportAuthToken(token, source string, reportId int) (err error) {
+	// 缓存key
+	reportTokenKey := getReportTokenKey(token, source)
+	err = utils.Rc.Put(reportTokenKey, reportId, utils.BusinessConfReportChartExpiredTime)
+
+	return
+}
+
+// getReportShareTokenKey
+// @Description:
+// @author: Roc
+// @datetime 2025-03-17 14:00:14
+// @param linkToken string
+// @return string
+func getReportShareTokenKey(linkToken string) string {
+	return fmt.Sprint(utils.CACHE_REPORT_SHARE_AUTH, utils.MD5(linkToken))
+}
+
+// GetReportAuthToken
+// @Description: 获取报告token
+// @author: Roc
+// @datetime 2025-03-17 16:48:38
+// @param linkToken string
+// @return string
+func GetReportAuthToken(linkToken string) string {
+	key := getReportShareTokenKey(linkToken)
+	return utils.Rc.GetStr(key)
+
+}
+
+// getReportTokenKey
+// @Description:
+// @author: Roc
+// @datetime 2025-03-17 14:00:14
+// @param linkToken string
+// @return string
+func getReportTokenKey(token, source string) string {
+	return fmt.Sprint(utils.CACHE_REPORT_AUTH, source, token)
+}
+
+// HandleReportContentStruct
+// @Description: 处理内容组件的链接
+// @author: Roc
+// @datetime 2025-01-07 13:38:39
+// @param body string
+// @param opType string
+// @return newBody string
+func HandleReportContentStruct(body string, opType string, tokenMap map[string]string) (newBody string) {
+	if body == `` {
+		return
+	}
+	newBody = body
+
+	// 解析JSON数据到map[string]interface{}
+	var jsonData []map[string]interface{}
+	if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
+		fmt.Println("Error parsing JSON:", err)
+		return
+	}
+
+	// 处理每个组件
+	for i := range jsonData {
+		if err := processMap(jsonData[i], opType, tokenMap); err != nil {
+			fmt.Println("Error processing component:", err)
+			return
+		}
+	}
+
+	// 将处理后的数据转换回JSON字符串
+	modifiedJSON, err := json.MarshalIndent(jsonData, "", "  ")
+	if err != nil {
+		fmt.Println("Error marshaling JSON:", err)
+		return
+	}
+	newBody = string(modifiedJSON)
+
+	return
+}
+
+// processMap 递归处理map中的content字段
+func processMap(data map[string]interface{}, opType string, tokenMap map[string]string) error {
+	for key, value := range data {
+		switch v := value.(type) {
+		case string:
+			if key == "content" {
+				newContent := v
+				// 处理链接
+				switch opType {
+				case `add`:
+					newContent = linkAddToken(v, tokenMap)
+				case `del`:
+					newContent = linkDelToken(v)
+				}
+				data[key] = newContent
+			}
+		case map[string]interface{}:
+			if err := processMap(v, opType, tokenMap); err != nil {
+				return err
+			}
+		case []interface{}:
+			for i := range v {
+				if m, ok := v[i].(map[string]interface{}); ok {
+					if err := processMap(m, opType, tokenMap); err != nil {
+						return err
+					}
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// GetReportShareUrlToken 获取报告分享链接token
+func GetReportShareUrlToken(req models.ReportShartUrlReq, adminId int) (linkToken string, err error) {
+	defer func() {
+		if err == nil && linkToken != `` {
+			GeneralReportToken(linkToken, req.ReportId)
+		}
+	}()
+	cacheLinkKey := utils.CACHE_REPORT_SHARE_SHORT_Url + strconv.Itoa(req.ReportId) + "userId:" + strconv.Itoa(adminId)
+	linkToken, _ = utils.Rc.RedisString(cacheLinkKey)
+	if linkToken != "" && utils.Rc.IsExist(fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))) {
+		return
+	}
+	var tokenKey string
+
+	var ok bool
+	// 冲突检测
+	for i := 0; i < 3; i++ {
+		linkToken = req.Url
+		if i > 0 {
+			linkToken += "_" + utils.GetRandDigit(3)
+		}
+		hashUrl := utils.MurmurHash64([]byte(linkToken))
+		linkToken = utils.ConvertNumToBase62(hashUrl)
+		// 拼上报告标题
+		//linkToken = fmt.Sprintf("%s %s", linkToken, req.Title)
+
+		tokenKey = fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
+		ok = utils.Rc.IsExist(tokenKey)
+		if !ok {
+			break
+		}
+	}
+	if !ok {
+		after := time.Now().AddDate(0, 0, 7)
+		err = utils.Rc.Put(cacheLinkKey, linkToken, time.Until(after))
+		if err != nil {
+			return
+		}
+		err = utils.Rc.Put(tokenKey, req.Url, time.Until(after))
+		if err != nil {
+			return
+		}
+	} else {
+		linkToken = ""
+		err = errors.New("生成链接失败")
+	}
+	return
+}
+
+func TransfromToOriginUrl(linkToken string) (originLink string, msg string, err error) {
+	cacheLinkKey := fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
+	originLink, err = utils.Rc.RedisString(cacheLinkKey)
+	if err != nil {
+		if err == redis.Nil {
+			msg = "链接已失效, 请重新获取"
+			return
+		}
+		msg = "获取链接失败"
+		return
+	}
+	if originLink == "" {
+		msg = "链接已失效, 请重新获取"
+		return
+	}
+
+	reportToken := GetReportAuthToken(linkToken)
+	if reportToken != "" {
+		originLink += `&authToken=` + reportToken
+	}
+
+	return
+}
+
+func FilterShareUrl() web.FilterFunc {
+	return func(c *context.Context) {
+		path := c.Input.Context.Request.URL.Path
+		tokenArr := strings.Split(path, "/")
+		token := tokenArr[len(tokenArr)-1]
+
+		newPath := "/v1/report/share/link"
+		q := c.Input.Context.Request.URL.Query()
+		q.Add("Token", token)
+		c.Input.Context.Request.URL.Path = newPath
+		c.Input.Context.Request.URL.RawQuery = q.Encode()
+
+		utils.ApiLog.Info(fmt.Sprintf("原始请求为:%s, 已修改请求路径为:%s?%s", path, newPath, q.Encode()))
+	}
+}

+ 132 - 8
services/smart_report.go

@@ -167,10 +167,10 @@ async def main():
         'printBackground': True,
         'format': "A2",
         'margin': {
-            'top': '10mm',
-            'bottom': '10mm',
-            'left': '10mm',
-            'right': '10mm'
+            'top': '20px',
+            'bottom': '20px',
+            'left': '20px',
+            'right': '20px'
         }
     })
     await browser.close()
@@ -326,8 +326,9 @@ func Report2pdfAndJpeg(reportUrl string, reportId, reportType int) {
 
 	reportCode := utils.MD5(strconv.Itoa(reportId))
 
-	pdfPath := `./static/` + reportCode + ".pdf"
-	jpegPath := `./static/` + reportCode + ".jpeg"
+	// pc端
+	pdfPath := `./static/` + reportCode + "_1200.pdf"
+	jpegPath := `./static/` + reportCode + "_1200.jpeg"
 
 	go func() {
 		err := ReportToPdf(reportUrl, pdfPath)
@@ -392,9 +393,9 @@ func Report2pdfAndJpeg(reportUrl string, reportId, reportType int) {
 
 	go func() {
 		width := 1200
-		if reportType == 3 {
+		/*if reportType == 3 {
 			width = 800
-		}
+		}*/
 		err := ReportToJpeg(width, reportUrl, jpegPath)
 		if err != nil {
 			utils.FileLog.Info("ReportToJpeg failed: , error: \n" + err.Error())
@@ -450,4 +451,127 @@ func Report2pdfAndJpeg(reportUrl string, reportId, reportType int) {
 		}
 
 	}()
+
+	// 移动端
+	pdfPathMobile := `./static/` + reportCode + "_600.pdf"
+	jpegPathMobile := `./static/` + reportCode + "_600.jpeg"
+
+	go func() {
+		err := ReportToPdf(reportUrl, pdfPathMobile)
+		if err != nil {
+			utils.FileLog.Info("ReportToPdf failed: , error: \n" + err.Error())
+			go alarm_msg.SendAlarmMsg("ReportToPdf failed:"+err.Error(), 3)
+		}
+
+		file, err := os.Open(pdfPathMobile)
+		if err != nil {
+			utils.FileLog.Info("Open failed: , error: \n" + err.Error())
+			go alarm_msg.SendAlarmMsg("Open failed:"+err.Error(), 3)
+			return
+		}
+
+		ext := path.Ext(file.Name())
+
+		randStr := utils.GetRandStringNoSpecialChar(28)
+		fileName := randStr + ext
+		defer file.Close() //关闭上传文件
+
+		resourceUrl := ``
+		ossClient := NewOssClient()
+		if ossClient == nil {
+			utils.FileLog.Info("初始化OSS服务失败")
+			return
+		}
+		resourceUrl, err = ossClient.UploadFile(fileName, pdfPathMobile, "")
+		if err != nil {
+			utils.FileLog.Info("文件上传失败, Err: \n" + err.Error())
+			go alarm_msg.SendAlarmMsg("文件上传失败:"+err.Error(), 3)
+			return
+		}
+		defer func() {
+			_ = os.Remove(pdfPathMobile)
+		}()
+
+		if reportType == 3 {
+			// 更新pdf url
+			ob := new(smart_report.SmartReport)
+			ob.SmartReportId = reportId
+			ob.DetailPdfUrlMobile = resourceUrl
+			if err = ob.Update([]string{"DetailPdfUrlMobile"}); err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		} else if reportType == 2 {
+			err = models.ModifyEnglishReportPdfUrlMobile(reportId, resourceUrl)
+			if err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		} else if reportType == 1 {
+			err = models.ModifyReportPdfUrlMobile(reportId, resourceUrl)
+			if err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		}
+
+	}()
+
+	go func() {
+		width := 600
+		err := ReportToJpeg(width, reportUrl, jpegPathMobile)
+		if err != nil {
+			utils.FileLog.Info("ReportToJpeg failed: , error: \n" + err.Error())
+		}
+		file, err := os.Open(jpegPathMobile)
+		if err != nil {
+			utils.FileLog.Info("open file failed: , error: \n" + err.Error())
+			return
+		}
+
+		ext := path.Ext(file.Name())
+
+		randStr := utils.GetRandStringNoSpecialChar(28)
+		fileName := randStr + ext
+		defer file.Close() //关闭上传文件
+
+		resourceUrl := ``
+		ossClient := NewOssClient()
+		if ossClient == nil {
+			utils.FileLog.Info("初始化OSS服务失败")
+			return
+		}
+		resourceUrl, err = ossClient.UploadFile(fileName, jpegPathMobile, "")
+		if err != nil {
+			utils.FileLog.Info("文件上传失败, Err: \n" + err.Error())
+			return
+		}
+		defer func() {
+			_ = os.Remove(jpegPathMobile)
+		}()
+
+		if reportType == 3 {
+			// 更新jpeg url
+			ob := new(smart_report.SmartReport)
+			ob.SmartReportId = reportId
+			ob.DetailImgUrlMobile = resourceUrl
+			if err = ob.Update([]string{"DetailImgUrlMobile"}); err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		} else if reportType == 2 {
+			err = models.ModifyEnglishReportImgUrlMobile(reportId, resourceUrl)
+			if err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		} else if reportType == 1 {
+			err = models.ModifyReportImgUrlMobile(reportId, resourceUrl)
+			if err != nil {
+				utils.FileLog.Info("更新研报失败, Err: \n" + err.Error())
+				return
+			}
+		}
+
+	}()
 }

+ 5 - 0
utils/business_conf.go

@@ -0,0 +1,5 @@
+package utils
+
+import "time"
+
+var BusinessConfReportChartExpiredTime time.Duration //图表有效期鉴权时间,单位:分钟

+ 40 - 4
utils/common.go

@@ -11,10 +11,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"github.com/PuerkitoBio/goquery"
-	"github.com/microcosm-cc/bluemonday"
-	"github.com/shopspring/decimal"
-	xhtml "golang.org/x/net/html"
 	"html"
 	"image"
 	"image/png"
@@ -31,6 +27,12 @@ import (
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/PuerkitoBio/goquery"
+	"github.com/microcosm-cc/bluemonday"
+	"github.com/shopspring/decimal"
+	"github.com/spaolacci/murmur3"
+	xhtml "golang.org/x/net/html"
 )
 
 // 随机数种子
@@ -2562,3 +2564,37 @@ func GetDuration(filePath string) (duration string, err error) {
 
 	return duration, nil
 }
+
+// MurmurHash64 计算字符串的64位哈希值
+func MurmurHash64(val []byte) uint64 {
+	hash64 := murmur3.New64()
+	hash64.Write(val)
+	return hash64.Sum64()
+}
+
+const base62Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+type TUint interface {
+	uint64 | uint32 | uint16 | uint8 | uint
+}
+
+// ConvertNumToBase62 转换数字为base62编码
+func ConvertNumToBase62[T TUint](num T) string {
+	if num == 0 {
+		return string(base62Chars[0])
+	}
+
+	var result []byte
+	for num > 0 {
+		remainder := num % 62
+		result = append(result, base62Chars[remainder])
+		num /= 62
+	}
+
+	// 反转结果
+	for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
+		result[i], result[j] = result[j], result[i]
+	}
+
+	return string(result)
+}

+ 5 - 0
utils/constants.go

@@ -218,6 +218,11 @@ const (
 	CACHE_SMART_REPORT_EDITING        = "eta:smart_report:editing:"         // 智能研报用户编辑中
 	CACHE_SMART_REPORT_SEND_MSG       = "eta:smart_report:sending:"         // 智能研报用户报告推送
 	CACHE_KEY_REPLACE_EDB             = "eta:replace_edb"                   //系统用户操作日志队列
+	CACHE_REPORT_SHARE_SHORT_Url      = "eta:report_share_url:report_id:"   //报告短链映射key
+	CACHE_REPORT_SHARE_ORIGIN_Url     = "eta:report_share_url:token:"       //短链与原始报告链接的映射key
+	CACHE_CHART_AUTH                  = "eta:chart:auth:"                   //图表数据授权
+	CACHE_REPORT_SHARE_AUTH           = "eta:report:auth:share:"            //报告短链与报告图表授权映射key
+	CACHE_REPORT_AUTH                 = "eta:report:auth:"                  //报告图表数据授权
 )
 
 // 模板消息推送类型

+ 2 - 0
utils/redis.go

@@ -7,6 +7,8 @@ import (
 
 type RedisClient interface {
 	Get(key string) interface{}
+	GetStr(key string) string
+	GetUInt64(key string) (uint64, error)
 	RedisBytes(key string) (data []byte, err error)
 	RedisString(key string) (data string, err error)
 	RedisInt(key string) (data int, err error)

+ 19 - 0
utils/redis/cluster_redis.go

@@ -86,6 +86,25 @@ func (rc *ClusterRedisClient) Get(key string) interface{} {
 	return data
 }
 
+// GetStr
+// @Description: 根据key获取字符串数据
+// @receiver rc
+// @param key
+// @return string
+func (rc *ClusterRedisClient) GetStr(key string) string {
+	return rc.redisClient.Get(context.TODO(), key).Val()
+}
+
+// GetUInt64
+// @Description: 根据key获取uint64数据
+// @receiver rc
+// @param key
+// @return int
+// @return error
+func (rc *ClusterRedisClient) GetUInt64(key string) (uint64, error) {
+	return rc.redisClient.Get(context.TODO(), key).Uint64()
+}
+
 // RedisBytes
 // @Description: 根据key获取字节编码数据
 // @receiver rc

+ 19 - 0
utils/redis/standalone_redis.go

@@ -78,6 +78,25 @@ func (rc *StandaloneRedisClient) Get(key string) interface{} {
 	return data
 }
 
+// GetStr
+// @Description: 根据key获取字符串数据
+// @receiver rc
+// @param key
+// @return string
+func (rc *StandaloneRedisClient) GetStr(key string) string {
+	return rc.redisClient.Get(context.TODO(), key).Val()
+}
+
+// GetUInt64
+// @Description: 根据key获取uint64数据
+// @receiver rc
+// @param key
+// @return int
+// @return error
+func (rc *StandaloneRedisClient) GetUInt64(key string) (uint64, error) {
+	return rc.redisClient.Get(context.TODO(), key).Uint64()
+}
+
 // RedisBytes
 // @Description: 根据key获取字节编码数据
 // @receiver rc