package services import ( "encoding/json" "eta/eta_report/utils" "fmt" html2 "golang.org/x/net/html" "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 { 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 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 { 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 } // 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 }