report_handle.go 5.7 KB

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