123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- package services
- import (
- "encoding/json"
- "errors"
- "eta/eta_api/models"
- "eta/eta_api/models/ppt_english"
- "eta/eta_api/models/system"
- "eta/eta_api/services/alarm_msg"
- "eta/eta_api/services/ppt2img"
- "eta/eta_api/utils"
- "fmt"
- "sort"
- "time"
- )
- const (
- ElementsTypeText = "text"
- ElementsTypeImage = "image"
- ElementsTypeChart = "chart"
- ElementsTypeSheet = "sheet"
- )
- type PPTContent struct {
- //Id int `json:"id" description:"此处因目录改版类型有int也有string且并没有使用到该字段所以注释掉"`
- Key int `json:"key"`
- ModelId int `json:"modelId"`
- Title string `json:"title"`
- Elements []PPTContentElements `json:"elements"`
- }
- type PPTContentElements struct {
- Type string `json:"type"`
- Position int `json:"position"`
- Content string `json:"content"`
- RichContent string `json:"richContent"`
- ChartId string `json:"chartId"`
- SheetId string `json:"sheetId"`
- SheetHeight string `json:"sheetHeight"`
- Src string `json:"src"`
- }
- // SavePPTReport 保存PPT报告
- func SavePPTReport(pptId, classifyId int, title string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
- defer func() {
- if err != nil {
- utils.FileLog.Info("%s", err.Error())
- go alarm_msg.SendAlarmMsg("PPT转报告失败, SavePPTReport Msg: "+errMsg+", Err: "+err.Error(), 3)
- }
- }()
- if pptId == 0 {
- errMsg = "参数有误"
- err = errors.New("参数有误")
- return
- }
- item, e := models.GetPptV2ById(pptId)
- if e != nil {
- errMsg = "获取PPT失败"
- err = errors.New("获取PPT失败, Err: " + e.Error())
- return
- }
- // PPT内容转HTML
- htm, e := pptContent2Html(item.Content, false)
- if e != nil {
- errMsg = "转换失败"
- err = e
- return
- }
- // 2023-02-21 PPT可多次转为报告, 不做关联
- if classifyId == 0 {
- errMsg = "请选择报告类型"
- err = errors.New("请选择报告类型")
- return
- }
- if title == "" {
- errMsg = "标题不能为空"
- err = errors.New("标题不能为空")
- return
- }
- // 获取分类及父级分类
- classifyList, e := models.GetAllClassify()
- if e != nil {
- errMsg = "转换失败"
- err = errors.New("获取分类列表失败, Err: " + e.Error())
- return
- }
- classifyMap := make(map[int]*models.Classify, 0)
- for _, v := range classifyList {
- classifyMap[v.Id] = v
- }
- classifyIdFirst := 0
- classifyIdSecond := 0
- classifyIdThird := 0
- classifyNameFirst := ""
- classifyNameSecond := ""
- classifyNameThird := ""
- // 最小单元分类,第二级别的分类 ,最大的分类
- var baseClassify, twoClassify, threeClassify *models.Classify
- var hasTwo, hasThird bool
- baseClassify, ok := classifyMap[classifyId]
- if !ok {
- errMsg = "分类异常"
- err = errors.New("获取分类失败 ")
- return
- }
- twoClassify, hasTwo = classifyMap[baseClassify.ParentId]
- if hasTwo {
- threeClassify, hasThird = classifyMap[twoClassify.ParentId]
- }
- if hasThird { // 如果确实是有三级分类
- classifyIdFirst = threeClassify.Id
- classifyNameFirst = threeClassify.ClassifyName
- classifyIdSecond = twoClassify.Id
- classifyNameSecond = twoClassify.ClassifyName
- classifyIdThird = baseClassify.Id
- classifyNameThird = baseClassify.ClassifyName
- } else if hasTwo {
- classifyIdFirst = twoClassify.Id
- classifyNameFirst = twoClassify.ClassifyName
- classifyIdSecond = baseClassify.Id
- classifyNameSecond = baseClassify.ClassifyName
- } else {
- classifyIdFirst = baseClassify.Id
- classifyNameFirst = baseClassify.ClassifyName
- }
- // 新增报告
- nowTime := time.Now().Local()
- reportReq := &models.AddReq{
- AddType: 1,
- ClassifyIdFirst: classifyIdFirst,
- ClassifyNameFirst: classifyNameFirst,
- ClassifyIdSecond: classifyIdSecond,
- ClassifyNameSecond: classifyNameSecond,
- ClassifyIdThird: classifyIdThird,
- ClassifyNameThird: classifyNameThird,
- Title: title,
- Abstract: "",
- Author: "",
- Frequency: utils.ReportFrequencyDefault,
- State: 1,
- Content: htm,
- CreateTime: nowTime.Format(utils.FormatDateTime),
- ReportVersion: 2,
- CollaborateType: 1, // 协作方式,1:个人,2:多人协作。默认:1
- ReportLayout: 1, // 报告布局,1:常规布局,2:智能布局。默认:1
- IsPublicPublish: 1, // 是否公开发布,1:是,2:否
- }
- // 如果PPT是公开的,则报告也公开发布
- if item.IsShare == 1 {
- reportReq.IsPublicPublish = 1
- }
- newReportId, newCode, _, e := CreateNewReport(*reportReq, adminInfo)
- if e != nil {
- errMsg = "转换失败"
- err = errors.New("新增报告失败, Err: " + e.Error())
- return
- }
- reportId = int(newReportId)
- reportCode = newCode
- // 更新报告中的ppt图片
- go saveReportPptImg(pptId, reportId, item.PptxUrl)
- return
- }
- // PPT2内容转HTML
- func pptContent2Html(content string, isEnglish bool) (htm string, err error) {
- contents := make([]PPTContent, 0)
- if e := json.Unmarshal([]byte(content), &contents); e != nil {
- err = errors.New("PPT内容转换失败")
- return
- }
- pageLen := len(contents)
- htmlContent := ``
- // iframe图表/表格域名
- // 获取基础配置, 若未配置则直接返回
- // 获取配置好的短信模版
- smsCond := ` AND conf_key = ? `
- smsPars := make([]interface{}, 0)
- smsPars = append(smsPars, "ChartViewUrl")
- conf := new(models.BusinessConf)
- conf, e := conf.GetItemByCondition(smsCond, smsPars)
- if e != nil {
- if e.Error() == utils.ErrNoRow() {
- err = fmt.Errorf("请先配置公共图库的地址")
- return
- }
- err = fmt.Errorf("获取聚合短信配置信息失败, Err: %s", e.Error())
- return
- }
- if conf.ConfVal == "" {
- err = fmt.Errorf("请先配置公共图库的地址")
- return
- }
- chartRoot := conf.ConfVal
- if pageLen > 0 {
- htmlPrefix := `<p style="text-align: left; margin-top: 10px; font-size: 16px;">`
- htmlSuffix := `</p>`
- htmlBr := `<br>`
- for i := 0; i < pageLen; i++ {
- // 每页标题加粗居中
- title := contents[i].Title
- if title != "" {
- htmlContent += `<p style="font-size: 16px; text-align: left;"><strong>`
- htmlContent += title
- htmlContent += `</strong></p>`
- }
- ele := contents[i].Elements
- // 每页元素按照Position升序排序
- sort.Slice(ele, func(k, j int) bool {
- return ele[k].Position < ele[j].Position
- })
- for _, v := range ele {
- // 根据不同的Type拼接不同的内容
- htmlContent += htmlPrefix
- switch v.Type {
- case ElementsTypeText:
- htmlContent += v.RichContent
- case ElementsTypeImage:
- htmlContent += fmt.Sprint(`<img src="`, v.Src, `" class="fr-fic fr-dib fr-draggable">`)
- case ElementsTypeChart:
- if isEnglish {
- // 英文研报图表src多加一个fromPage=en, 表格暂时没有区分
- 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)
- break
- }
- htmlContent += fmt.Sprintf(`<iframe src="%s/chartshow?code=%s" width="100%%" height="350" style="border-width:0px; min-height:350px;"></iframe>`, chartRoot, v.ChartId)
- case ElementsTypeSheet:
- 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)
- }
- htmlContent += htmlSuffix
- }
- // 每页中间插入一个换行符, 最后一页不插入
- currentPage := i + 1
- if currentPage != pageLen {
- htmlContent += htmlPrefix + htmlBr + htmlSuffix
- }
- }
- }
- htm = htmlContent
- return
- }
- // ResetPPTReport 重置PPT关联的报告(如删除关联的报告后)
- func ResetPPTReport(reportId int, isEnglish bool) (err error) {
- defer func() {
- if err != nil {
- utils.FileLog.Info("%s", err.Error())
- go alarm_msg.SendAlarmMsg("重置PPT关联报告失败, ResetPPTReport Err: "+err.Error(), 3)
- }
- }()
- // 英文报告
- if isEnglish {
- en, e := ppt_english.GetPptEnglishByReportId(reportId)
- if e != nil && e.Error() != utils.ErrNoRow() {
- err = errors.New("获取英文PPT失败, Err: " + e.Error())
- return
- }
- if en != nil {
- updateCols := []string{"ReportId", "ReportCode"}
- en.ReportId = 0
- en.ReportCode = ""
- if e = en.Update(updateCols); e != nil {
- err = errors.New("更新英文PPT关联报告失败, Err: " + e.Error())
- return
- }
- }
- return
- }
- // 中文报告
- item, e := models.GetPptV2ByReportId(reportId)
- if e != nil && e.Error() != utils.ErrNoRow() {
- err = errors.New("获取PPT失败, Err: " + e.Error())
- return
- }
- if item != nil {
- updateCols := []string{"ReportId", "ReportCode"}
- item.ReportId = 0
- item.ReportCode = ""
- if e = item.Update(updateCols); e != nil {
- err = errors.New("更新PPT关联报告失败, Err: " + e.Error())
- return
- }
- }
- return
- }
- // saveReportPptImg ppt转报告后,需要再次将ppt转图片
- func saveReportPptImg(pptId, reportId int, pptUrl string) {
- var err error
- defer func() {
- if err != nil {
- utils.FileLog.Info(fmt.Sprintf("将ppt转图片失败, saveReportPptImg Err:%s", err.Error()))
- go alarm_msg.SendAlarmMsg("将ppt转图片失败, saveReportPptImg Err: "+err.Error(), 3)
- }
- }()
- // 更新报告内容
- report, e := models.GetReportByReportId(reportId)
- if e != nil && e.Error() != utils.ErrNoRow() {
- err = errors.New("获取报告失败, Err: " + e.Error())
- return
- }
- if report == nil {
- return
- }
- // 获取ppt转图片的结果
- list, err := ppt2img.Ppt2Img(pptUrl)
- if err != nil {
- return
- }
- reportPptImgList := make([]*models.ReportPptImg, 0)
- for _, v := range list {
- reportPptImg := &models.ReportPptImg{
- //ReportPptImgId: 0,
- PptId: pptId,
- ReportId: reportId,
- ReportChapterId: 0,
- ImgUrl: v,
- CreateTime: time.Now(),
- }
- reportPptImgList = append(reportPptImgList, reportPptImg)
- }
- //批量添加Ppt转报告的图片记录
- err = models.AddAndEditMultiReportPptImg(pptId, reportPptImgList)
- return
- }
- // SaveEnglishPPTReport 保存英文PPT报告
- func SaveEnglishPPTReport(pptId, classifyIdFirst, classifyIdSecond int, title, abstract string, adminInfo *system.Admin) (reportId int, reportCode, errMsg string, err error) {
- defer func() {
- if err != nil {
- utils.FileLog.Info("%s", err.Error())
- go alarm_msg.SendAlarmMsg("PPT转报告失败, SavePPTReport Msg: "+errMsg+", Err: "+err.Error(), 3)
- }
- }()
- if pptId == 0 {
- errMsg = "参数有误"
- err = errors.New("参数有误")
- return
- }
- item, e := ppt_english.GetPptEnglishById(pptId)
- if e != nil {
- errMsg = "获取PPT失败"
- err = errors.New("获取PPT失败, Err: " + e.Error())
- return
- }
- // PPT内容转HTML
- htm, e := pptContent2Html(item.Content, true)
- if e != nil {
- errMsg = "转换失败"
- err = e
- return
- }
- // 2023-02-21 PPT可多次转为报告, 不做关联
- if title == "" {
- errMsg = "标题不能为空"
- err = errors.New("标题不能为空")
- return
- }
- if classifyIdFirst <= 0 {
- errMsg = "请选择报告分类"
- err = errors.New("报告分类不能为空")
- return
- }
- // 分类
- classifyList, e := models.GetAllEnglishClassify()
- if e != nil {
- errMsg = "转换失败"
- err = errors.New("获取分类列表失败, Err: " + e.Error())
- return
- }
- classifyMap := make(map[int]string, 0)
- for _, v := range classifyList {
- classifyMap[v.Id] = v.ClassifyName
- }
- classifyNameFirst := classifyMap[classifyIdFirst]
- classifyNameSecond := classifyMap[classifyIdSecond]
- // 新增报告
- nowTime := time.Now().Local()
- reportReq := &models.AddEnglishReportReq{
- AddType: 1,
- ClassifyIdFirst: classifyIdFirst,
- ClassifyNameFirst: classifyNameFirst,
- ClassifyIdSecond: classifyIdSecond,
- ClassifyNameSecond: classifyNameSecond,
- Title: title,
- Abstract: abstract,
- Author: "Horizon Insights FICC Team",
- Frequency: utils.ReportFrequencyDefault,
- State: 1,
- Content: htm,
- CreateTime: nowTime.Format(utils.FormatDateTime),
- }
- newReportId, newCode, e := CreateNewEnglishReport(*reportReq, adminInfo)
- if e != nil {
- errMsg = "转换失败"
- err = errors.New("新增报告失败, Err: " + e.Error())
- return
- }
- reportId = int(newReportId)
- reportCode = newCode
- return
- }
- // UpdatePptEditing 更新PPT编辑状态
- func UpdatePptEditing(pptId, status, userId int, userName string, isEn bool) (ret ppt_english.PPTEditingCache, err error) {
- if pptId <= 0 {
- return
- }
- cacheKey := ""
- if isEn {
- cacheKey = fmt.Sprint(utils.CACHE_EN_PPT_EDITING, pptId)
- } else {
- cacheKey = fmt.Sprint(utils.CACHE_PPT_EDITING, pptId)
- }
- // 完成编辑
- if status == 2 {
- _ = utils.Rc.Delete(cacheKey)
- return
- }
- // 读取缓存中的结果
- var editor ppt_english.PPTEditingCache
- strCache, _ := utils.Rc.RedisString(cacheKey)
- fmt.Println(strCache)
- if strCache != "" {
- e := json.Unmarshal([]byte(strCache), &editor)
- if e != nil {
- err = fmt.Errorf("解析缓存内容失败: %s", e.Error())
- return
- }
- }
- // 标记编辑中
- if status == 1 {
- // 无人编辑, 写入缓存
- if !editor.IsEditing {
- ret.IsEditing = true
- ret.AdminId = userId
- ret.Editor = userName
- ret.Tips = fmt.Sprintf("当前%s正在编辑PPT", userName)
- b, _ := json.Marshal(ret)
- utils.Rc.SetNX(cacheKey, string(b), utils.ReportPptEditingWait*time.Second)
- return
- }
- // 有人编辑
- if editor.IsEditing {
- // 编辑用户与当前用户不一致, 返回编辑用户, 一致则更新缓存
- if userId == editor.AdminId {
- b, _ := json.Marshal(editor)
- utils.Rc.Do("SETEX", cacheKey, int64(utils.ReportPptEditingWait), string(b))
- }
- ret = editor
- return
- }
- } else {
- // 默认查询
- ret = editor
- }
- return
- }
|