report.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package services
  2. import (
  3. "encoding/json"
  4. "eta/eta_report/utils"
  5. "fmt"
  6. html2 "golang.org/x/net/html"
  7. "net/url"
  8. "strings"
  9. "time"
  10. )
  11. // HandleReportContent
  12. // @Description: 处理报告内容(动态图表/表格添加授权token)
  13. // @author: Roc
  14. // @datetime 2025-01-07 10:03:15
  15. // @param body string
  16. // @return newBody string
  17. func HandleReportContent(body string, opType string, tokenMap map[string]string) (newBody string) {
  18. if body == `` {
  19. return
  20. }
  21. newBody = body
  22. // 解析HTML
  23. doc, err := html2.Parse(strings.NewReader(body))
  24. if err != nil {
  25. fmt.Println("Error parsing HTML:", err)
  26. return
  27. }
  28. replaceIframeSrc(doc, opType, tokenMap)
  29. // 输出修改后的HTML
  30. var modifiedHtml strings.Builder
  31. err = html2.Render(&modifiedHtml, doc)
  32. if err != nil {
  33. fmt.Println("Error rendering HTML:", err)
  34. return
  35. }
  36. newBody = modifiedHtml.String()
  37. fmt.Println(newBody)
  38. return
  39. }
  40. // replaceIframeSrc 遍历HTML节点,替换iframe的src属性
  41. func replaceIframeSrc(n *html2.Node, opType string, tokenMap map[string]string) {
  42. if n.Type == html2.ElementNode && n.Data == "iframe" {
  43. for i, attr := range n.Attr {
  44. if attr.Key == "src" {
  45. newLink := attr.Val
  46. // 处理链接
  47. switch opType {
  48. case `add`:
  49. newLink = linkAddToken(attr.Val, tokenMap)
  50. case `del`:
  51. newLink = linkDelToken(attr.Val)
  52. }
  53. // 替换原来的链接
  54. n.Attr[i].Val = newLink
  55. break
  56. }
  57. }
  58. }
  59. // 递归处理子节点
  60. for c := n.FirstChild; c != nil; c = c.NextSibling {
  61. replaceIframeSrc(c, opType, tokenMap)
  62. }
  63. }
  64. // linkAddToken 链接添加token
  65. func linkAddToken(link string, tokenMap map[string]string) string {
  66. var err error
  67. defer func() {
  68. if err != nil {
  69. utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
  70. }
  71. }()
  72. parsedURL, err := url.Parse(link)
  73. if err != nil {
  74. return link
  75. }
  76. // 获取查询参数
  77. queryParams := parsedURL.Query()
  78. // 先移除authToken参数,避免莫名其妙的这个值入库了
  79. queryParams.Del("authToken")
  80. // 获取code参数
  81. code := queryParams.Get("code")
  82. if code == "" {
  83. return link
  84. }
  85. showType := `chart`
  86. if strings.Contains(parsedURL.Path, "sheetshow") {
  87. showType = `excel`
  88. }
  89. // 避免报告里面一个图表/表格重复生成token
  90. key := fmt.Sprint(showType, `:`, code)
  91. if tokenMap != nil {
  92. if token, ok := tokenMap[key]; ok {
  93. // 在链接后面添加一个token值
  94. return link + "&authToken=" + token
  95. }
  96. }
  97. token, err := GeneralChartToken(showType, code, 30*time.Minute)
  98. if err != nil {
  99. return link
  100. }
  101. if tokenMap != nil {
  102. tokenMap[key] = token
  103. }
  104. // 在链接后面添加一个token值
  105. return link + "&authToken=" + token
  106. }
  107. // linkDelToken 链接添加token
  108. func linkDelToken(link string) string {
  109. var err error
  110. defer func() {
  111. if err != nil {
  112. utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
  113. }
  114. }()
  115. parsedURL, err := url.Parse(link)
  116. if err != nil {
  117. return link
  118. }
  119. // 获取查询参数
  120. queryParams := parsedURL.Query()
  121. // 移除authToken参数
  122. queryParams.Del("authToken")
  123. // 更新URL的查询参数
  124. parsedURL.RawQuery = queryParams.Encode()
  125. return parsedURL.String()
  126. }
  127. // GeneralChartToken
  128. // @Description: 生产图表/表格授权token
  129. // @author: Roc
  130. // @datetime 2025-01-07 10:41:36
  131. // @param showType string
  132. // @param uniqueCode string
  133. // @param expireTime time.Duration
  134. // @return token string
  135. // @return err error
  136. func GeneralChartToken(showType, uniqueCode string, expireTime time.Duration) (token string, err error) {
  137. // 缓存key
  138. token = utils.MD5(fmt.Sprint(showType+`:`, uniqueCode, time.Now().UnixNano()/1e6))
  139. key := fmt.Sprint(utils.CACHE_CHART_AUTH, token)
  140. err = utils.Rc.Put(key, uniqueCode, expireTime)
  141. return
  142. }
  143. // HandleReportContentStruct
  144. // @Description: 处理内容组件的链接
  145. // @author: Roc
  146. // @datetime 2025-01-07 13:38:39
  147. // @param body string
  148. // @param opType string
  149. // @return newBody string
  150. func HandleReportContentStruct(body string, opType string, tokenMap map[string]string) (newBody string) {
  151. if body == `` {
  152. return
  153. }
  154. newBody = body
  155. // 解析JSON数据到map[string]interface{}
  156. var jsonData []map[string]interface{}
  157. if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
  158. fmt.Println("Error parsing JSON:", err)
  159. return
  160. }
  161. // 处理每个组件
  162. for i := range jsonData {
  163. if err := processMap(jsonData[i], opType, tokenMap); err != nil {
  164. fmt.Println("Error processing component:", err)
  165. return
  166. }
  167. }
  168. // 将处理后的数据转换回JSON字符串
  169. modifiedJSON, err := json.MarshalIndent(jsonData, "", " ")
  170. if err != nil {
  171. fmt.Println("Error marshaling JSON:", err)
  172. return
  173. }
  174. newBody = string(modifiedJSON)
  175. return
  176. }
  177. // processMap 递归处理map中的content字段
  178. func processMap(data map[string]interface{}, opType string, tokenMap map[string]string) error {
  179. for key, value := range data {
  180. switch v := value.(type) {
  181. case string:
  182. if key == "content" {
  183. newContent := v
  184. // 处理链接
  185. switch opType {
  186. case `add`:
  187. newContent = linkAddToken(v, tokenMap)
  188. case `del`:
  189. newContent = linkDelToken(v)
  190. }
  191. data[key] = newContent
  192. }
  193. case map[string]interface{}:
  194. if err := processMap(v, opType, tokenMap); err != nil {
  195. return err
  196. }
  197. case []interface{}:
  198. for i := range v {
  199. if m, ok := v[i].(map[string]interface{}); ok {
  200. if err := processMap(m, opType, tokenMap); err != nil {
  201. return err
  202. }
  203. }
  204. }
  205. }
  206. }
  207. return nil
  208. }