package services import ( "encoding/json" "errors" "fmt" "github.com/wenzhenxi/gorsa" "hongze/hz_eta_api/models" "hongze/hz_eta_api/services/alarm_msg" "hongze/hz_eta_api/utils" "io/ioutil" "net/http" "net/url" "strconv" "strings" "time" ) //func init() { // report, _ := models.GetReportById(572) // SendReportToThs(report) //} var permissionMap map[string]string = map[string]string{ "化里化外日评": "原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱", "股债日评": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "贵金属复盘": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "每日经济数据备忘录": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "宏观商品复盘": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "知白守黑日评": "钢材,铁矿,双焦(焦煤、焦炭)", "有声有色日度闲篇": "有色(铜、铝),有色(锌、铅),镍+不锈钢", "EIA原油库存点评": "原油", "苯乙烯数据点评": "苯乙烯", "API原油库存点评": "原油", "铁矿航运数据点评": "铁矿", "中观需求点评": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "聚酯数据点评": "PTA,MEG", "钢材周度数据点评": "钢材", "寻根知本": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "国际宏观": "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢", "能化百家谈": "原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱", "有色百家谈": "有色(铜、铝),有色(锌、铅),镍+不锈钢", "黑色百家谈": "钢材,铁矿,双焦(焦煤、焦炭)", } // permissionLabelMap 品种与同花顺标签的映射关系 var permissionLabelMap = map[string]string{ "宏观经济": "宏观", "利率债": "利率债", "原油": "原油", "PTA": "PTA", "MEG": "MEG", "织造终端": "织造终端", "甲醇": "甲醇", "聚烯烃": "聚烯烃", "沥青": "沥青", "纯苯+苯乙烯": "纯苯+苯乙烯", "玻璃纯碱": "玻璃纯碱", "钢材": "钢材", "铁矿": "铁矿", "双焦(焦煤、焦炭)": "双焦(焦煤、焦炭)", "有色(锌)": "有色(锌)", "有色(铜、铝)": "有色(铜、铝)", "镍+不锈钢": "镍+不锈钢", "PVC": "PVC", "聚酯": "聚酯", "钴锂": "钴锂", "策略": "策略", "苯乙烯": "纯苯+苯乙烯", "锌": "有色(锌)", "双焦": "双焦(焦煤、焦炭)", "铜/铝": "有色(铜、铝)", "镍/不锈钢": "镍+不锈钢", "成品油": "成品油", "油品": "成品油", "纺服": "织造终端", } // TshResult 同花顺返回信息 type TshResult struct { ErrorCode int `json:"error" description:"错误状态码"` Message string `json:"message" description:"提示信息"` } // SendReportToThs 发送报告到同花顺 func SendReportToThs(report *models.ReportDetail) (err error) { defer func() { if err != nil { //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers) go alarm_msg.SendAlarmMsg("发送报告至同花顺失败 ErrMsg:"+err.Error(), 3) //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送报告至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers) } }() jumpBaseUrl := `http://rddpweb.brilliantstart.cn/reportdtl?id=` //生产环境地址 if utils.RunMode == "release" { jumpBaseUrl = `https://ficc.hzinsights.com/reportdtl?id=` } logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png` //获取分类信息(标签) permissionName := report.ClassifyNameSecond classifyItem, tmpErr := models.GetClassifyById(report.ClassifyIdSecond) if tmpErr != nil { err = errors.New(fmt.Sprint("获取分类失败:", tmpErr.Error())) return } //获取权限标签名称 var permissionStr string if classifyItem != nil { permissionStr = classifyItem.ClassifyLabel if permissionStr == "" { var isOk bool permissionStr, isOk = permissionMap[permissionName] if !isOk { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } } } else { var isOk bool permissionStr, isOk = permissionMap[permissionName] if !isOk { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } } if permissionStr == "" { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } sendDetail, err := models.GetReportSendThsDetailByReportId(report.Id, "日度点评") if err != nil && err.Error() != utils.ErrNoRow() { return } else if err == nil && sendDetail != nil { if sendDetail.Status >= 0 { fmt.Println("重复发送") return } } pushTime := time.Now() //预发送时间 isPrePush := false //是否预发布 addTime := time.Minute * 40 //短时间内多次发布报告,每篇报告的间隔时间(目前暂定40分钟,只有日度点评的报告需要限制) //获取距离现在最近的一条发送成功失败记录 latelySendDetail, err := models.GetLatelyReportSendThsDetail() //如果存在最近一条发送记录,那么去校验时间 if (err == nil && latelySendDetail != nil) || err.Error() == utils.ErrNoRow() { pushTime = latelySendDetail.PushTime.Add(addTime) //如果最近一条的发送记录 的 (发送时间 + 每篇报告的间隔时间) 晚于 当前时间 if pushTime.After(time.Now()) { isPrePush = true } else { pushTime = time.Now() } } //fmt.Println("sendDetailId:", sendDetailId) stageStr := fmt.Sprintf("%v", report.Stage) createDate, _ := time.Parse(utils.FormatDateTime, report.CreateTime) createDateFrom := createDate.Format("0102") title := `【第` + stageStr + `期|FICC】` + report.Title + `(` + createDateFrom + ")" if isPrePush { //预发布,只添加预发布记录,不立马发送报告,等待定时任务推送消息给同花顺 newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionStr, ReportId: report.Id, ReportType: "日度点评", Status: 2, Level: 3, PushTime: pushTime, CreateTime: time.Now(), MsgType: 1, Content: report.Abstract, JumpUrl: fmt.Sprint(jumpBaseUrl, report.Id), Pic: logoUrl, } _, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } } else { newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionStr, ReportId: report.Id, ReportType: "日度点评", Status: 0, Level: 1, PushTime: pushTime, CreateTime: time.Now(), MsgType: 1, Content: report.Abstract, JumpUrl: fmt.Sprint(jumpBaseUrl, report.Id), Pic: logoUrl, } sendDetailId, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } dataType := "1" //内容类型:1文字 2小程序 tmpErr = SendThs(title, permissionStr, report.Abstract, fmt.Sprint(jumpBaseUrl, report.Id), logoUrl, dataType) if tmpErr != nil { _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), -1, tmpErr.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), 1, "") } go SendReportToEmail(report) return } // SendMsgToThs 发送群发消息到同花顺 func SendMsgToThs(groupSendMsg *models.GroupSendMsg) (err error) { sendDetail, err := models.GetReportSendThsDetailByReportId(groupSendMsg.MsgId, "群发消息") if err != nil && err.Error() != utils.ErrNoRow() { return } else if err == nil && sendDetail != nil { if sendDetail.Status >= 0 { err = errors.New("重复发送") return } } newSendDetail := &models.ReportSendThsDetail{ Title: groupSendMsg.Title, LabelStr: groupSendMsg.Label, ReportId: groupSendMsg.MsgId, ReportType: "群发消息", Status: 0, Level: 1, PushTime: time.Now(), CreateTime: time.Now(), MsgType: int(groupSendMsg.JumpType), Content: groupSendMsg.Description, JumpUrl: groupSendMsg.LinkUrl, Pic: groupSendMsg.ImgUrl, } sendDetailId, err := models.AddReportSendThsDetail(newSendDetail) if err != nil { return } dataType := fmt.Sprint(groupSendMsg.JumpType) //dataType := "1" //内容类型:1文字 2小程序 err = SendThs(groupSendMsg.Title, groupSendMsg.Label, groupSendMsg.Description, groupSendMsg.LinkUrl, groupSendMsg.ImgUrl, dataType) if err != nil { _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), -1, err.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), 1, "") return } // SendThs 发送消息到同花顺 func SendThs(title, labelStr, abstract, jumpBaseUrl, logoUrl, dataType string) (err error) { defer func() { if err != nil { //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers) go alarm_msg.SendAlarmMsg("发送消息至同花顺失败 ErrMsg:"+err.Error(), 3) //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送报告至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers) } }() pubKey := utils.THS_PubKey sendUrl := utils.THS_SendUrl //fmt.Println("sendUrl:", sendUrl) utils.FileLog.Info(fmt.Sprintf("jumpBaseUrl:%s", jumpBaseUrl)) utils.FileLog.Info(fmt.Sprintf("dataType:%s", dataType)) //标题字符长度截取,最多50位字符 title = utils.SubStr(title, 50) utils.FileLog.Info(fmt.Sprintf("title:%s", title)) title, err = gorsa.PublicEncrypt(title, pubKey) if err != nil { return } //简介字符长度截取,最多50位字符 if dataType != `3` { abstract = utils.SubStr(abstract, 50) utils.FileLog.Info(fmt.Sprintf("abstract:%s", abstract)) abstract, err = gorsa.PublicEncrypt(abstract, pubKey) if err != nil { return } } else { utils.FileLog.Info(fmt.Sprintf("abstract:%s", abstract)) } // 关联后的标签数据 newLabelList := make([]string, 0) labelList := strings.Split(labelStr, ",") for _, v := range labelList { tmpLabel, ok := permissionLabelMap[v] //判断是否在关联标签里面 if !ok { //如果不在关联标签里面,那么就把原始的值赋值给 tmpLabel = v } newLabelList = append(newLabelList, tmpLabel) } labelStr = strings.Join(newLabelList, ",") utils.FileLog.Info(fmt.Sprintf("labelStr:%s", labelStr)) label, err := gorsa.PublicEncrypt(labelStr, pubKey) if err != nil { return } jumpUrl, err := gorsa.PublicEncrypt(jumpBaseUrl, pubKey) if err != nil { return } picUrl, err := gorsa.PublicEncrypt(logoUrl, pubKey) if err != nil { return } dataTypeEncript, err := gorsa.PublicEncrypt(dataType, pubKey) if err != nil { return } //开始发送 client := http.Client{} form := url.Values{} form.Add("title", title) form.Add("description", abstract) form.Add("label", label) form.Add("url", jumpUrl) form.Add("icon", picUrl) form.Add("dataType", dataTypeEncript) utils.FileLog.Info(fmt.Sprintf("SendThs parms:%s", form.Encode())) resp, err := client.PostForm(sendUrl, form) if err != nil { return } defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) //fmt.Println(string(body)) utils.FileLog.Info(fmt.Sprintf("ThsResult parms:%s", string(body))) //同花顺接口返回数据 var tshResult TshResult err = json.Unmarshal(body, &tshResult) if err != nil { err = errors.New(fmt.Sprintf("同花顺接口返回数据转换成结构体异常;body:%s;Err:%s;", string(body), err.Error())) return } if tshResult.ErrorCode != 1 { err = errors.New(fmt.Sprint("发送数据到同花顺接口异常,result:", string(body))) return } return } // SendReportToEmail 发送报告邮件 func SendReportToEmail(report *models.ReportDetail) (err error) { fmt.Println("SendReportToEmail") defer func() { if err != nil { //fmt.Println(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "发送消息至同花顺失败 ErrMsg:"+err.Error(), utils.EmailSendToUsers) go alarm_msg.SendAlarmMsg("发送报告至邮件失败,SendReportToEmail ErrMsg:"+err.Error(), 3) //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "SendReportToEmail ErrMsg:"+err.Error(), utils.EmailSendToUsers) } }() toUser := `` jumpUrl := `` if utils.RunMode == "debug" { //toUser = `glji@hzinsights.com` toUser = `317699326@qq.com` jumpUrl = "http://rddpweb.brilliantstart.cn/reportdtl?id=1578" + strconv.Itoa(report.Id) } else { toUser = "lijun011112@gtjas.com" jumpUrl = "https://ficc.hzinsights.com/reportdtl?id=" + strconv.Itoa(report.Id) } createDate, err := time.Parse(utils.FormatDateTime, report.CreateTime) createDateFrom := createDate.Format("060102") emailBody := ` Email

弘则研报:` + report.Title + "_" + createDateFrom + `

你好,

今日报告已推送。

报告类型:` + report.ClassifyNameFirst + `

报告标题:` + report.Title + `

报告链接:弘则研究

` fmt.Println("start SendReportToEmail") result, err := utils.SendEmailByHz("弘则研报报告", emailBody, toUser) fmt.Println("send result:", result, err) return } // SendReportMiniToThs 发送报告-研报小程序到同花顺 func SendReportMiniToThs(report *models.ReportDetail) (err error) { defer func() { if err != nil { go alarm_msg.SendAlarmMsg("SendReportMiniToThs 发送报告-研报小程序到同花顺失败, ReportId:"+strconv.Itoa(report.Id)+", ErrMsg:"+err.Error(), 3) //go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "SendReportMiniToThs发送报告至同花顺失败, ReportId:" + strconv.Itoa(report.Id) + ", ErrMsg:" + err.Error(), utils.EmailSendToUsers) } }() //小程序跳转地址 jumpBaseUrl := utils.WxYbAppId + `/pages-report/reportDetail?reportId=` // 如果是晨报、周报,那么地址还不一样 (2023-4-7 09:24:25:添加晨报推送) if utils.InArrayByStr([]string{utils.REPORT_TYPE_DAY, utils.REPORT_TYPE_WEEK}, report.ChapterType) { jumpBaseUrl = utils.WxYbAppId + `/pages-report/chapterList?reportId=` } logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png` var permissionStr string if report.HasChapter == 0 { // 获取分类信息(标签) permissionName := report.ClassifyNameSecond classifyItem, tmpErr := models.GetClassifyById(report.ClassifyIdSecond) if tmpErr != nil { err = errors.New(fmt.Sprint("获取分类失败:", permissionName)) return } // 获取权限标签名称 if classifyItem != nil { permissionStr = classifyItem.ClassifyLabel if permissionStr == "" { var isOk bool permissionStr, isOk = permissionMap[permissionName] if !isOk { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } } } else { var isOk bool permissionStr, isOk = permissionMap[permissionName] if !isOk { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } } if permissionStr == "" { err = errors.New(fmt.Sprint("没有该权限的标签,权限名:", permissionName)) return } } else { // 同php的 permissionStr = "宏观,利率债,原油,PTA,MEG,织造终端,甲醇,聚烯烃,沥青,橡胶,苯乙烯,玻璃纯碱,钢材,铁矿,双焦(焦煤、焦炭),有色(铜、铝),有色(锌、铅),镍+不锈钢" } sendDetail, err := models.GetReportSendThsDetailByReportId(report.Id, "研报小程序") if err != nil { // 如果不是找不到数据,那么直接返回报错 if err.Error() != utils.ErrNoRow() { return } //如果是找不到数据,那么就将err置空 err = nil } else if err == nil && sendDetail != nil { if sendDetail.Status >= 0 { fmt.Println("重复发送") return } } //pushTime := time.Now() //预发送时间 //isPrePush := false //是否预发布 //addTime := time.Minute * 40 //短时间内多次发布报告,每篇报告的间隔时间(目前暂定40分钟,只有日度点评的报告需要限制) //level := 3 //默认是普通的推送等级 classifyId := report.ClassifyIdSecond if classifyId <= 0 { classifyId = report.ClassifyIdFirst } level, pushTime, isPrePush, err := getPushTime("研报", classifyId) if isPrePush { //预发布,只添加预发布记录,不立马发送报告,等待定时任务推送消息给同花顺 newSendDetail := &models.ReportSendThsDetail{ Title: report.Title, LabelStr: permissionStr, ReportId: report.Id, ReportType: "研报", Status: 2, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: report.Abstract, JumpUrl: fmt.Sprint(jumpBaseUrl, report.Id), Pic: logoUrl, } _, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } } else { newSendDetail := &models.ReportSendThsDetail{ Title: report.Title, LabelStr: permissionStr, ReportId: report.Id, ReportType: "研报", Status: 0, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: report.Abstract, JumpUrl: fmt.Sprint(jumpBaseUrl, report.Id), Pic: logoUrl, } sendDetailId, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } //及时发送 dataType := "2" //内容类型:1文字 2小程序 err = SendThs(report.Title, permissionStr, report.Abstract, fmt.Sprint(jumpBaseUrl, report.Id), logoUrl, dataType) if err != nil { _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), -1, err.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), 1, "") } if report.HasChapter == 0 { go SendReportToEmail(report) } return } // SendYbPriceDrivenToThs 推送研报小程序价格驱动客群消息 func SendYbPriceDrivenToThs(priceDrivenId, varietyTagId int) (err error) { defer func() { if err != nil { errMsg := "SendReportMiniToThs 推送研报小程序价格驱动到同花顺失败, PriceDrivenId:" + strconv.Itoa(priceDrivenId) + ", ErrMsg:" + err.Error() utils.FileLog.Info("%s", errMsg) go alarm_msg.SendAlarmMsg(errMsg, 3) } }() // 标签信息 if varietyTagId <= 0 { return } varietyTag, err := models.GetVarietyTagById(varietyTagId) if err != nil { return } permissionName := varietyTag.ChartPermissionName if permissionName == "" { err = errors.New("客群标签为空, 不可推送") return } if permissionName == "宏观经济" { permissionName = "宏观" } title := fmt.Sprintf("%s价格驱动", permissionName) jumpUrl := fmt.Sprintf(`%s/pages/pricedriven/pricedriven?default_classify_first=%d&default_classify_sub=%d`, utils.WxYbAppId, varietyTag.VarietyClassifyId, varietyTag.VarietyTagId) logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png` // 校验发送类型: 0-不发送 1-即时发送 2-预发送 reportType := "研报价格驱动" sendType, pushTime, err := checkPreparePush(priceDrivenId, reportType) if err != nil || sendType == 0 { return } thsDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionName, ReportId: priceDrivenId, ReportType: reportType, Status: 0, Level: 1, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: title, JumpUrl: jumpUrl, Pic: logoUrl, } // 延时发送 if sendType == 2 { thsDetail.Status = 2 thsDetail.Level = 3 if _, e := models.AddReportSendThsDetail(thsDetail); e != nil { err = errors.New("AddReportSendThsDetail-新增发送记录失败, Err:" + e.Error()) return } return } // 即时发送 if sendType == 1 { lastId, e := models.AddReportSendThsDetail(thsDetail) if e != nil { err = errors.New("AddReportSendThsDetail-新增发送记录失败, Err:" + e.Error()) return } dataType := "2" // 内容类型: 1-文字 2-小程序 if e := SendThs(title, permissionName, title, jumpUrl, logoUrl, dataType); e != nil { err = errors.New("SendThs-推送失败, Err:" + e.Error()) _ = models.ModifyReportSendThsDetailStatus(int(lastId), -1, e.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(lastId), 1, "") } return } // checkPreparePush 校验发送类型 func checkPreparePush(reportId int, reportType string) (sendType int, pushTime time.Time, err error) { // sendType 发送类型 0-不发送 1-即时发送 2-预发送 sendDetail, e := models.GetReportSendThsDetailByReportId(reportId, reportType) if e != nil && e.Error() != utils.ErrNoRow() { err = errors.New("checkPreparePush-获取发送记录失败, Err:" + e.Error()) return } // 重复发送 if sendDetail != nil && sendDetail.Status >= 0 { return } // 最新一条(发送中/发送成功)的记录 latelySendDetail, e := models.GetLatelyReportSendThsDetail() if e != nil && e.Error() != utils.ErrNoRow() { err = errors.New("checkPreparePush-获取最近一条发送记录失败, Err:" + e.Error()) return } sendType = 1 pushTime = time.Now() if latelySendDetail != nil { addTime := time.Minute * 40 // 报告间隔时间 delayTime := latelySendDetail.PushTime.Add(addTime) // 最近一条发送记录的(发送时间+间隔时间)晚于当前时间, 则预发送 if delayTime.After(time.Now()) { sendType = 2 pushTime = delayTime } } return } // SendYbCommunityVideoThs 发送研报视频社区到同花顺 func SendYbCommunityVideoThs(videoId int, title string) (err error) { defer func() { if err != nil { errMsg := "SendYbCommunityVideoThs 发送视频社区到同花顺失败, CommunityVideoId:" + strconv.Itoa(videoId) + ", ErrMsg:" + err.Error() utils.FileLog.Info("%s", errMsg) go alarm_msg.SendAlarmMsg(errMsg, 3) } }() permissionName := "宏观" //写死宏观,默认所有群都推 jumpUrl := fmt.Sprint(utils.WxYbAppId+`/pages/video/videoList?videoId=`, videoId) logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png` reportType := "视频社区" sendDetail, err := models.GetReportSendThsDetailByReportId(videoId, reportType) if err != nil && err.Error() != utils.ErrNoRow() { return } else if err == nil && sendDetail != nil { if sendDetail.Status >= 0 { fmt.Println("重复发送") return } } //pushTime := time.Now() // 预发送时间 //isPrePush := false // 是否预发布 //addTime := time.Minute * 40 // 短时间内多次发布报告,每篇报告的间隔时间(目前暂定40分钟,只有日度点评的报告需要限制) //// 获取距离现在最近的一条发送成功失败记录 level, pushTime, isPrePush, err := getPushTime("视频社区", 0) if isPrePush { // 预发布,只添加预发布记录,不立马发送报告,等待定时任务推送消息给同花顺 newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionName, ReportId: videoId, ReportType: reportType, Status: 2, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: title, JumpUrl: jumpUrl, Pic: logoUrl, } _, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } } else { // 即时发送 newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionName, ReportId: videoId, ReportType: reportType, Status: 0, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: title, JumpUrl: jumpUrl, Pic: logoUrl, } sendDetailId, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } dataType := "2" // 内容类型:1-文字 2-小程序 err = SendThs(title, permissionName, title, jumpUrl, logoUrl, dataType) if err != nil { _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), -1, err.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), 1, "") } return } // SendYbRoadVideoThs 发送研报线上路演到同花顺 func SendYbRoadVideoThs(videoId int, title, chartPermissionIds string) (err error) { defer func() { if err != nil { errMsg := "SendYbRoadVideoThs 发送研报线上路演到同花顺, RoadVideoId:" + strconv.Itoa(videoId) + ", ErrMsg:" + err.Error() utils.FileLog.Info("%s", errMsg) go alarm_msg.SendAlarmMsg(errMsg, 3) } }() // 标签信息 if chartPermissionIds == "" { return } chartPermissionIdSlice := strings.Split(chartPermissionIds, ",") chartList, e := models.GetChartPermissionByIds(chartPermissionIdSlice) if e != nil { err = errors.New("获取品种信息失败, Err:" + e.Error()) return } permissionName := "" for _, v := range chartList { if v.PermissionName == "宏观经济" { v.PermissionName = "宏观" } permissionName += v.PermissionName + "," } if permissionName == "" { err = errors.New("客群标签为空, 不可推送") return } permissionName = strings.Trim(permissionName, ",") //permissionName := "宏观" //写死宏观,默认所有群都推 jumpUrl := fmt.Sprint(utils.WxYbAppId+`/pages/roadShow/video/list?videoId=`, videoId) logoUrl := `https://hongze.oss-cn-shanghai.aliyuncs.com/hzyj.png` reportType := "线上路演" sendDetail, err := models.GetReportSendThsDetailByReportId(videoId, reportType) if err != nil && err.Error() != utils.ErrNoRow() { return } else if err == nil && sendDetail != nil { if sendDetail.Status >= 0 { fmt.Println("重复发送") return } } //pushTime := time.Now() // 预发送时间 //isPrePush := false // 是否预发布 //addTime := time.Minute * 40 // 短时间内多次发布报告,每篇报告的间隔时间(目前暂定40分钟,只有日度点评的报告需要限制) //// 获取距离现在最近的一条发送成功失败记录 level, pushTime, isPrePush, err := getPushTime("线上路演", 0) if isPrePush { // 预发布,只添加预发布记录,不立马发送报告,等待定时任务推送消息给同花顺 newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionName, ReportId: videoId, ReportType: reportType, Status: 2, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: title, JumpUrl: jumpUrl, Pic: logoUrl, } _, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } } else { // 即时发送 newSendDetail := &models.ReportSendThsDetail{ Title: title, LabelStr: permissionName, ReportId: videoId, ReportType: reportType, Status: 0, Level: level, PushTime: pushTime, CreateTime: time.Now(), MsgType: 2, Content: title, JumpUrl: jumpUrl, Pic: logoUrl, } sendDetailId, tmpErr := models.AddReportSendThsDetail(newSendDetail) if tmpErr != nil { err = tmpErr return } dataType := "2" // 内容类型:1-文字 2-小程序 err = SendThs(title, permissionName, title, jumpUrl, logoUrl, dataType) if err != nil { _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), -1, err.Error()) return } _ = models.ModifyReportSendThsDetailStatus(int(sendDetailId), 1, "") } return } // getPushTime 获取下次推送时间 func getPushTime(configType string, classifyId int) (level int, pushTime time.Time, isPrePush bool, err error) { addTime := 40 //默认间隔40分钟 level = 3 //默认是普通的推送等级 pushTime = time.Now() isPrePush = true // 是否预发送 // 查找对应的推送配置 { findConfig, tmpErr := models.GetReportSendThsConfigByClassifyId(configType, classifyId) if tmpErr != nil { if tmpErr.Error() != utils.ErrNoRow() { err = tmpErr return } } else { addTime = findConfig.Time level = findConfig.Level } } // 如果是紧急的,那么立马推送 if level == 1 { isPrePush = false return } updateMinuteStr := fmt.Sprintf(" DATE_ADD(push_time, INTERVAL %d minute) ", addTime) //获取相同推送等级level下待发送的 距离现在最近的一条等待发送的记录 latelyLevelSendDetail, tmpErr := models.GetLatelyWaitLevelReportSendThs(level) //如果当前推送等级下,存在最近一条等待发送的记录,那么将该记录的推送时间后面的全部给往后推迟对应的时间 if tmpErr == nil { err = models.UpdateReportSendThsPushTime(latelyLevelSendDetail.PushTime, updateMinuteStr) pushTime = latelyLevelSendDetail.PushTime.Add(time.Duration(addTime) * time.Minute) return } // 如果是查询sql报错,那么直接返回 if tmpErr.Error() != utils.ErrNoRow() { err = tmpErr return } // 当前情况是:当前是同等级下没有待发送的消息 var latelyPushTime time.Time //查询最近的发送中/已经成功/发送失败的记录 latelyThsIsSendDetail, err := models.GetLatelyIsSendSendThsDetail() if err == nil { latelyPushTime = latelyThsIsSendDetail.PushTime } else { // 如果是查询sql报错,那么直接返回 if err.Error() != utils.ErrNoRow() { return } } // 那么需要寻找下一个推送等级的第一条推送记录 // 获取当前下一个推送等级下面的第一条数据 earliestLevelSendDetail, tmpErr := models.GetEarliestWaitGtLevelReportSendThs(level) // 如果当前下一个推送等级下面存在数据数据,那么将该记录的推送时间以及后面时间的记录全部给往后推迟对应的时间 if tmpErr == nil { if latelyPushTime.IsZero() { err = models.UpdateReportSendThsPushTimeByEqGtPushTime(earliestLevelSendDetail.PushTime, updateMinuteStr) } else { // 新记录需要发送的时间 pushTime = latelyPushTime.Add(time.Duration(addTime) * time.Minute) // 如果当前时间晚于 新记录需要发送的时间 的话,那么发布时间就是现在 if time.Now().After(pushTime) { pushTime = time.Now() isPrePush = false } // 下一篇报告 与 新报告的发布间隔时间 differenceTime := earliestLevelSendDetail.PushTime.Sub(pushTime) updateMinuteStr := fmt.Sprintf(" DATE_ADD(push_time, INTERVAL %d minute) ", 40+int(differenceTime.Minutes())) err = models.UpdateReportSendThsPushTimeByEqGtPushTime(earliestLevelSendDetail.PushTime, updateMinuteStr) } return } else { // 如果是查询sql报错,那么直接返回 if tmpErr.Error() != utils.ErrNoRow() { err = tmpErr return } // 后面没有报告了,那么就是直接往后面加就好了 if !latelyPushTime.IsZero() { // 新记录需要发送的时间 pushTime = latelyPushTime.Add(time.Duration(addTime) * time.Minute) // 如果当前时间晚于 新记录需要发送的时间 的话,那么发布时间就是现在 if time.Now().After(pushTime) { pushTime = time.Now() isPrePush = false } return } } err = nil isPrePush = false return } // Demo 发送文字和图片 func Demo() { description := `先说下玻璃吧,前面两三周还是比较看多05的,年报也是大方向上认为明年选择做多。但是,现在价格和成交已经不是很匹配了,短期盘面给出的升水以及绝对价格的角度来看,认为阶段性到目标位了,年前高位震荡看,策略上维持周报看法,前期多单可以适当止盈部分,轻仓观望。` description = `话不多说,到此结束。[翻白眼][翻白眼][旺柴][翻白眼] 这里是换行![翻白眼][捂脸]` urlStr := `https://hongze.oss-accelerate.aliyuncs.com/static/images/202301/20230103/CddIbfsYrcMCmhpmVgJyUU5Jyhjw.jpeg` urlStr = `https://hongze.oss-accelerate.aliyuncs.com/static/images/202301/20230103/siP2p9VjQMasEAZ52uFtl1CgNInS.png` //dataType, h5:1; 小程序:2;3:文字;4:图片 SendThs("测试图片", "宏观", description, urlStr, "", "4") }