ppt.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. package services
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "eta/eta_api/models"
  7. "eta/eta_api/models/ppt_english"
  8. "eta/eta_api/models/system"
  9. "eta/eta_api/services/alarm_msg"
  10. "eta/eta_api/services/ppt2img"
  11. "eta/eta_api/utils"
  12. "sort"
  13. "time"
  14. )
  15. const (
  16. ElementsTypeText = "text"
  17. ElementsTypeImage = "image"
  18. ElementsTypeChart = "chart"
  19. ElementsTypeSheet = "sheet"
  20. )
  21. type PPTContent struct {
  22. //Id int `json:"id" description:"此处因目录改版类型有int也有string且并没有使用到该字段所以注释掉"`
  23. Key int `json:"key"`
  24. ModelId int `json:"modelId"`
  25. Title string `json:"title"`
  26. Elements []PPTContentElements `json:"elements"`
  27. }
  28. type PPTContentElements struct {
  29. Type string `json:"type"`
  30. Position int `json:"position"`
  31. Content string `json:"content"`
  32. RichContent string `json:"richContent"`
  33. ChartId string `json:"chartId"`
  34. SheetId string `json:"sheetId"`
  35. SheetHeight string `json:"sheetHeight"`
  36. Src string `json:"src"`
  37. }
  38. // SavePPTReport 保存PPT报告
  39. func SavePPTReport(pptId, classifyIdSecond int, title string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
  40. defer func() {
  41. if err != nil {
  42. utils.FileLog.Info("%s", err.Error())
  43. go alarm_msg.SendAlarmMsg("PPT转报告失败, SavePPTReport Msg: "+errMsg+", Err: "+err.Error(), 3)
  44. }
  45. }()
  46. if pptId == 0 {
  47. errMsg = "参数有误"
  48. err = errors.New("参数有误")
  49. return
  50. }
  51. item, e := models.GetPptV2ById(pptId)
  52. if e != nil {
  53. errMsg = "获取PPT失败"
  54. err = errors.New("获取PPT失败, Err: " + e.Error())
  55. return
  56. }
  57. // PPT内容转HTML
  58. htm, e := pptContent2Html(item.Content, false)
  59. if e != nil {
  60. errMsg = "转换失败"
  61. err = e
  62. return
  63. }
  64. // 2023-02-21 PPT可多次转为报告, 不做关联
  65. if classifyIdSecond == 0 {
  66. errMsg = "请选择报告类型"
  67. err = errors.New("请选择报告类型")
  68. return
  69. }
  70. if title == "" {
  71. errMsg = "标题不能为空"
  72. err = errors.New("标题不能为空")
  73. return
  74. }
  75. // 获取分类及父级分类
  76. classifyList, e := models.GetAllClassify()
  77. if e != nil {
  78. errMsg = "转换失败"
  79. err = errors.New("获取分类列表失败, Err: " + e.Error())
  80. return
  81. }
  82. classifyMap := make(map[int]*models.Classify, 0)
  83. for _, v := range classifyList {
  84. classifyMap[v.Id] = v
  85. }
  86. classifyIdFirst := 0
  87. classifyNameFirst := ""
  88. classifyNameSecond := ""
  89. secondClassify := classifyMap[classifyIdSecond]
  90. if secondClassify != nil {
  91. classifyNameSecond = secondClassify.ClassifyName
  92. firstClassify := classifyMap[secondClassify.ParentId]
  93. if firstClassify != nil {
  94. classifyIdFirst = firstClassify.Id
  95. classifyNameFirst = firstClassify.ClassifyName
  96. }
  97. }
  98. // 新增报告
  99. nowTime := time.Now().Local()
  100. reportReq := &models.AddReq{
  101. AddType: 1,
  102. ClassifyIdFirst: classifyIdFirst,
  103. ClassifyNameFirst: classifyNameFirst,
  104. ClassifyIdSecond: classifyIdSecond,
  105. ClassifyNameSecond: classifyNameSecond,
  106. Title: title,
  107. Abstract: "",
  108. Author: "FICC团队",
  109. Frequency: utils.ReportFrequencyDefault,
  110. State: 1,
  111. Content: htm,
  112. CreateTime: nowTime.Format(utils.FormatDateTime),
  113. ReportVersion: 2,
  114. }
  115. newReportId, newCode, _, e := CreateNewReport(*reportReq, adminInfo)
  116. if e != nil {
  117. errMsg = "转换失败"
  118. err = errors.New("新增报告失败, Err: " + e.Error())
  119. return
  120. }
  121. reportId = int(newReportId)
  122. reportCode = newCode
  123. // 更新报告中的ppt图片
  124. go saveReportPptImg(pptId, reportId, item.PptxUrl)
  125. return
  126. }
  127. // PPT2内容转HTML
  128. func pptContent2Html(content string, isEnglish bool) (htm string, err error) {
  129. contents := make([]PPTContent, 0)
  130. if e := json.Unmarshal([]byte(content), &contents); e != nil {
  131. err = errors.New("PPT内容转换失败")
  132. return
  133. }
  134. pageLen := len(contents)
  135. htmlContent := ``
  136. // iframe图表/表格域名
  137. chartRoot := utils.PublicChartHost
  138. if pageLen > 0 {
  139. htmlPrefix := `<p style="text-align: left; margin-top: 10px; font-size: 16px;">`
  140. htmlSuffix := `</p>`
  141. htmlBr := `<br>`
  142. for i := 0; i < pageLen; i++ {
  143. // 每页标题加粗居中
  144. title := contents[i].Title
  145. if title != "" {
  146. htmlContent += `<p style="font-size: 16px; text-align: left;"><strong>`
  147. htmlContent += title
  148. htmlContent += `</strong></p>`
  149. }
  150. ele := contents[i].Elements
  151. // 每页元素按照Position升序排序
  152. sort.Slice(ele, func(k, j int) bool {
  153. return ele[k].Position < ele[j].Position
  154. })
  155. for _, v := range ele {
  156. // 根据不同的Type拼接不同的内容
  157. htmlContent += htmlPrefix
  158. switch v.Type {
  159. case ElementsTypeText:
  160. htmlContent += v.RichContent
  161. case ElementsTypeImage:
  162. htmlContent += fmt.Sprint(`<img src="`, v.Src, `" class="fr-fic fr-dib fr-draggable">`)
  163. case ElementsTypeChart:
  164. if isEnglish {
  165. // 英文研报图表src多加一个fromPage=en, 表格暂时没有区分
  166. htmlContent += fmt.Sprintf(`<iframe src="%s/chartshow?code=%s&fromPage=en" width="100%%" height="350" style="border-width:0px; min-height:350px;"></iframe>`, chartRoot, v.ChartId)
  167. break
  168. }
  169. htmlContent += fmt.Sprintf(`<iframe src="%s/chartshow?code=%s" width="100%%" height="350" style="border-width:0px; min-height:350px;"></iframe>`, chartRoot, v.ChartId)
  170. case ElementsTypeSheet:
  171. htmlContent += fmt.Sprintf(`<iframe src="%s/sheetshow?code=%s" class="iframe%s" width="100%%" height="%s" style="border-width:0px;"></iframe>`, chartRoot, v.SheetId, v.SheetId, v.SheetHeight)
  172. }
  173. htmlContent += htmlSuffix
  174. }
  175. // 每页中间插入一个换行符, 最后一页不插入
  176. currentPage := i + 1
  177. if currentPage != pageLen {
  178. htmlContent += htmlPrefix + htmlBr + htmlSuffix
  179. }
  180. }
  181. }
  182. htm = htmlContent
  183. return
  184. }
  185. // ResetPPTReport 重置PPT关联的报告(如删除关联的报告后)
  186. func ResetPPTReport(reportId int, isEnglish bool) (err error) {
  187. defer func() {
  188. if err != nil {
  189. utils.FileLog.Info("%s", err.Error())
  190. go alarm_msg.SendAlarmMsg("重置PPT关联报告失败, ResetPPTReport Err: "+err.Error(), 3)
  191. }
  192. }()
  193. // 英文报告
  194. if isEnglish {
  195. en, e := ppt_english.GetPptEnglishByReportId(reportId)
  196. if e != nil && e.Error() != utils.ErrNoRow() {
  197. err = errors.New("获取英文PPT失败, Err: " + e.Error())
  198. return
  199. }
  200. if en != nil {
  201. updateCols := []string{"ReportId", "ReportCode"}
  202. en.ReportId = 0
  203. en.ReportCode = ""
  204. if e = en.Update(updateCols); e != nil {
  205. err = errors.New("更新英文PPT关联报告失败, Err: " + e.Error())
  206. return
  207. }
  208. }
  209. return
  210. }
  211. // 中文报告
  212. item, e := models.GetPptV2ByReportId(reportId)
  213. if e != nil && e.Error() != utils.ErrNoRow() {
  214. err = errors.New("获取PPT失败, Err: " + e.Error())
  215. return
  216. }
  217. if item != nil {
  218. updateCols := []string{"ReportId", "ReportCode"}
  219. item.ReportId = 0
  220. item.ReportCode = ""
  221. if e = item.Update(updateCols); e != nil {
  222. err = errors.New("更新PPT关联报告失败, Err: " + e.Error())
  223. return
  224. }
  225. }
  226. return
  227. }
  228. // saveReportPptImg ppt转报告后,需要再次将ppt转图片
  229. func saveReportPptImg(pptId, reportId int, pptUrl string) {
  230. var err error
  231. defer func() {
  232. if err != nil {
  233. utils.FileLog.Info(fmt.Sprintf("将ppt转图片失败, saveReportPptImg Err:%s", err.Error()))
  234. go alarm_msg.SendAlarmMsg("将ppt转图片失败, saveReportPptImg Err: "+err.Error(), 3)
  235. }
  236. }()
  237. // 更新报告内容
  238. report, e := models.GetReportByReportId(reportId)
  239. if e != nil && e.Error() != utils.ErrNoRow() {
  240. err = errors.New("获取报告失败, Err: " + e.Error())
  241. return
  242. }
  243. if report == nil {
  244. return
  245. }
  246. // 获取ppt转图片的结果
  247. list, err := ppt2img.Ppt2Img(pptUrl)
  248. if err != nil {
  249. return
  250. }
  251. reportPptImgList := make([]*models.ReportPptImg, 0)
  252. for _, v := range list {
  253. reportPptImg := &models.ReportPptImg{
  254. //ReportPptImgId: 0,
  255. PptId: pptId,
  256. ReportId: reportId,
  257. ReportChapterId: 0,
  258. ImgUrl: v,
  259. CreateTime: time.Now(),
  260. }
  261. reportPptImgList = append(reportPptImgList, reportPptImg)
  262. }
  263. //批量添加Ppt转报告的图片记录
  264. err = models.AddAndEditMultiReportPptImg(pptId, reportPptImgList)
  265. return
  266. }
  267. // SaveEnglishPPTReport 保存英文PPT报告
  268. func SaveEnglishPPTReport(pptId, classifyIdFirst, classifyIdSecond int, title, abstract string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
  269. defer func() {
  270. if err != nil {
  271. utils.FileLog.Info("%s", err.Error())
  272. go alarm_msg.SendAlarmMsg("PPT转报告失败, SavePPTReport Msg: "+errMsg+", Err: "+err.Error(), 3)
  273. }
  274. }()
  275. if pptId == 0 {
  276. errMsg = "参数有误"
  277. err = errors.New("参数有误")
  278. return
  279. }
  280. item, e := ppt_english.GetPptEnglishById(pptId)
  281. if e != nil {
  282. errMsg = "获取PPT失败"
  283. err = errors.New("获取PPT失败, Err: " + e.Error())
  284. return
  285. }
  286. // PPT内容转HTML
  287. htm, e := pptContent2Html(item.Content, true)
  288. if e != nil {
  289. errMsg = "转换失败"
  290. err = e
  291. return
  292. }
  293. // 2023-02-21 PPT可多次转为报告, 不做关联
  294. if title == "" {
  295. errMsg = "标题不能为空"
  296. err = errors.New("标题不能为空")
  297. return
  298. }
  299. if classifyIdFirst <= 0 {
  300. errMsg = "请选择报告分类"
  301. err = errors.New("报告分类不能为空")
  302. return
  303. }
  304. // 分类
  305. classifyList, e := models.GetAllEnglishClassify(0)
  306. if e != nil {
  307. errMsg = "转换失败"
  308. err = errors.New("获取分类列表失败, Err: " + e.Error())
  309. return
  310. }
  311. classifyMap := make(map[int]string, 0)
  312. for _, v := range classifyList {
  313. classifyMap[v.Id] = v.ClassifyName
  314. }
  315. classifyNameFirst := classifyMap[classifyIdFirst]
  316. classifyNameSecond := classifyMap[classifyIdSecond]
  317. // 新增报告
  318. nowTime := time.Now().Local()
  319. reportReq := &models.AddEnglishReportReq{
  320. AddType: 1,
  321. ClassifyIdFirst: classifyIdFirst,
  322. ClassifyNameFirst: classifyNameFirst,
  323. ClassifyIdSecond: classifyIdSecond,
  324. ClassifyNameSecond: classifyNameSecond,
  325. Title: title,
  326. Abstract: abstract,
  327. Author: "Horizon Insights FICC Team",
  328. Frequency: utils.ReportFrequencyDefault,
  329. State: 1,
  330. Content: htm,
  331. CreateTime: nowTime.Format(utils.FormatDateTime),
  332. }
  333. newReportId, newCode, e := CreateNewEnglishReport(*reportReq, adminInfo)
  334. if e != nil {
  335. errMsg = "转换失败"
  336. err = errors.New("新增报告失败, Err: " + e.Error())
  337. return
  338. }
  339. reportId = int(newReportId)
  340. reportCode = newCode
  341. return
  342. }