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

Merge branch 'eta/2.4.5' into debug

Roc 2 сар өмнө
parent
commit
d546d6b66c

+ 13 - 6
controller/english_report/english_report.go

@@ -458,13 +458,13 @@ func (er *EnglishReportController) Detail(c *gin.Context) {
 	baseData.AuthOk = authOk
 
 	// 配置信息
+	obj := business_conf.BusinessConf{}
+	conf, e := obj.GetBusinessConf()
+	if e != nil {
+		resp.FailMsg("获取失败", "获取免责声明失败,Err:"+e.Error(), c)
+		return
+	}
 	{
-		obj := business_conf.BusinessConf{}
-		conf, e := obj.GetBusinessConf()
-		if e != nil {
-			resp.FailMsg("获取失败", "获取免责声明失败,Err:"+e.Error(), c)
-			return
-		}
 
 		// 免责声明
 		if conf[business_conf.BusinessConfDisclaimerEn] != "" {
@@ -481,5 +481,12 @@ func (er *EnglishReportController) Detail(c *gin.Context) {
 		}
 	}
 
+	// 授权token
+	if conf[business_conf.BusinessConfIsOpenChartExpired] == `true` {
+		tokenMap := make(map[string]string)
+		baseData.Report.Content = english_report_service.HandleReportContent(baseData.Report.Content, "add", tokenMap)
+		baseData.Report.ContentSub = english_report_service.HandleReportContent(baseData.Report.ContentSub, "add", tokenMap)
+	}
+
 	resp.OkData("查询成功", baseData, c)
 }

+ 1 - 0
models/business_conf/business_conf.go

@@ -35,6 +35,7 @@ const (
 	BusinessConfReportCenterLogoShow = "ReportCenterLogoShow" // 报告logo
 	BusinessConfReportEnLogoShow     = "ReportEnLogoShow"     // 报告logo
 	BusinessConfDisclaimerEn         = "DisclaimerEn"         // 英文免责声明
+	BusinessConfIsOpenChartExpired   = "IsOpenChartExpired"   // 图表是否鉴权
 )
 
 func (c *BusinessConf) GetList(condition string, pars []interface{}) (list []*BusinessConf, err error) {

+ 240 - 0
services/english_report/report_handle.go

@@ -0,0 +1,240 @@
+package english_report
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	html2 "golang.org/x/net/html"
+	"hongze/hongze_yb_en_api/global"
+	"hongze/hongze_yb_en_api/utils"
+	"net/url"
+	"strings"
+	"time"
+)
+
+// 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 {
+			global.LOG.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
+	key := fmt.Sprint(showType, `:`, code)
+	if tokenMap != nil {
+		if token, ok := tokenMap[key]; ok {
+			// 在链接后面添加一个token值
+			return link + "&authToken=" + token
+		}
+	}
+
+	token, err := GeneralChartToken(showType, code, 30*time.Minute)
+	if err != nil {
+		return link
+	}
+
+	if tokenMap != nil {
+		tokenMap[key] = token
+	}
+
+	// 在链接后面添加一个token值
+	return link + "&authToken=" + token
+}
+
+// linkDelToken 链接添加token
+func linkDelToken(link string) string {
+	var err error
+	defer func() {
+		if err != nil {
+			global.LOG.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 = global.Redis.SetEX(context.TODO(), key, uniqueCode, expireTime).Err()
+
+	return
+}
+
+// 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
+}

+ 15 - 10
utils/constants.go

@@ -1,6 +1,6 @@
 package utils
 
-//常量定义
+// 常量定义
 const (
 	FormatTime            = "15:04:05"                //时间格式
 	FormatDate            = "2006-01-02"              //日期格式
@@ -16,7 +16,7 @@ const (
 	PageSize30            = 30
 )
 
-//手机号,电子邮箱正则
+// 手机号,电子邮箱正则
 const (
 	RegularMobile = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9])|(17[0-9])|(16[0-9])|(19[0-9]))\\d{8}$" //手机号码
 	RegularEmail  = `\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*`                                             //匹配电子邮箱
@@ -29,20 +29,20 @@ const (
 
 // 招聘流程状态:0待一面结果、1待二面结果、2待三面结果;3已淘汰,4已通过
 const (
-	RcrtProcessStatusWaitFirstResult = 0
+	RcrtProcessStatusWaitFirstResult  = 0
 	RcrtProcessStatusWaitSecondResult = 1
-	RcrtProcessStatusWaitThirdResult = 2
-	RcrtProcessStatusOut = 3
-	RcrtProcessStatusWPass = 4
+	RcrtProcessStatusWaitThirdResult  = 2
+	RcrtProcessStatusOut              = 3
+	RcrtProcessStatusWPass            = 4
 )
 
 const DefaultPwd = "9cbf8a4dcb8e30682b927f352d6559a0" //初始密码:123456a
 
 // redis 缓存
 const (
-	HRSYSTEM_LOGIN_TOKEN = "hrSystem:login:token:"
-	HRSYSTEM_LOGIN_TOKEN_NO_TRUST = "hrSystem:login:no_trust:"        //管理后台登录(不可信登录态)
-	HRSYSTEM_LOGIN_ADMINID_IP = "hrSystem:login:admin_id:"
+	HRSYSTEM_LOGIN_TOKEN          = "hrSystem:login:token:"
+	HRSYSTEM_LOGIN_TOKEN_NO_TRUST = "hrSystem:login:no_trust:" //管理后台登录(不可信登录态)
+	HRSYSTEM_LOGIN_ADMINID_IP     = "hrSystem:login:admin_id:"
 )
 
 // 聚合短信
@@ -57,4 +57,9 @@ var (
 // 加密key
 const (
 	KEY = "wdO40P8eCNXEqZbX44pcl9tN"
-)
+)
+
+// 缓存key
+const (
+	CACHE_CHART_AUTH = "chart:auth:" //图表数据授权
+)