|
@@ -2,6 +2,7 @@ package services
|
|
|
|
|
|
import (
|
|
|
"archive/zip"
|
|
|
+ "encoding/json"
|
|
|
"errors"
|
|
|
"eta/eta_mobile/models"
|
|
|
"eta/eta_mobile/models/report"
|
|
@@ -11,9 +12,12 @@ 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"
|
|
|
)
|
|
|
|
|
@@ -1512,3 +1516,230 @@ func GetGeneralPdfUrl(reportCode string, reportLayout int8) (pdfUrl string) {
|
|
|
|
|
|
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()
|
|
|
+
|
|
|
+ // 先移除auth_token参数,避免莫名其妙的这个值入库了
|
|
|
+ queryParams.Del("auth_token")
|
|
|
+
|
|
|
+ // 获取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 + "&auth_token=" + token
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ token, err := GeneralChartToken(showType, code, 30*time.Minute)
|
|
|
+ if err != nil {
|
|
|
+ return link
|
|
|
+ }
|
|
|
+
|
|
|
+ if tokenMap != nil {
|
|
|
+ tokenMap[key] = token
|
|
|
+ }
|
|
|
+
|
|
|
+ // 在链接后面添加一个token值
|
|
|
+ return link + "&auth_token=" + token
|
|
|
+}
|
|
|
+
|
|
|
+// 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()
|
|
|
+
|
|
|
+ // 移除auth_token参数
|
|
|
+ queryParams.Del("auth_token")
|
|
|
+
|
|
|
+ // 更新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
|
|
|
+}
|
|
|
+
|
|
|
+// 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
|
|
|
+}
|