package services import ( "encoding/json" "errors" "fmt" "hongze/hz_crm_api/models" "hongze/hz_crm_api/services/alarm_msg" "hongze/hz_crm_api/utils" "html" "strconv" "strings" "time" ) // IEnglishEmailSend 英文研报-邮件推送接口 type IEnglishEmailSend interface { NewClient() (err error) SendEmail(item *EnglishReportSendEmailRequest) (ok bool, result string, err error) BatchSendEmail(list []*EnglishReportSendEmailRequest) (results []*EnglishReportSendEmailResult, err error) } // EnglishReportSendEmailRequest 英文研报-推送邮件请求体 type EnglishReportSendEmailRequest struct { ReportId int `description:"英文报告ID"` EmailId int `description:"邮箱ID"` Email string `description:"邮箱地址"` Subject string `description:"邮件主题"` FromAlias string `description:"发信人昵称"` ReportTitle string `description:"报告标题"` ReportAbstract string `description:"报告摘要"` ReportContent string `description:"报告内容"` ReportShareLink string `description:"报告分享链接"` ReportTime string `description:"报告时间"` HtmlBody string `description:"模板内容主体"` } // EnglishReportSendEmailResult 英文研报-推送邮件响应体 type EnglishReportSendEmailResult struct { ReportId int `description:"英文报告ID"` EmailId int `description:"邮箱ID"` Email string `description:"邮箱地址"` Ok bool `description:"是否推送成功"` SendData string `description:"请求数据-JSON"` ResultData string `description:"推送结果-JSON"` Source int `description:"服务来源:1-阿里云;2-腾讯云"` } // BatchSendAliEnglishReportEmail 批量推送英文研报邮件 func BatchSendAliEnglishReportEmail(list []*EnglishReportSendEmailRequest) (err error) { defer func() { if err != nil { go alarm_msg.SendAlarmMsg("阿里云群发英文研报邮件失败, Err: "+err.Error(), 3) } }() if len(list) == 0 { return } requestMap := make(map[int]*EnglishReportSendEmailRequest, 0) for i := range list { requestMap[list[i].EmailId] = list[i] } // 请求阿里云接口批量推送 aliEmail := new(AliyunEmail) resultList, e := aliEmail.BatchSendEmail(list) if e != nil { err = e return } // 返回的结果更新日志 resendList := make([]*EnglishReportSendEmailRequest, 0) failLogIds := make([]int, 0) updateCols := []string{"SendData", "Result", "SendStatus", "ErrMsg"} for i := range resultList { var cond string var pars []interface{} cond = ` AND is_deleted = 0 AND report_id = ? AND email_id = ? AND source = ? AND send_status = ?` pars = append(pars, resultList[i].ReportId, resultList[i].EmailId, models.EnglishReportEmailLogSourceAli, models.EnglishReportEmailLogStatusIng) l, e := models.GetEnglishReportEmailLog(cond, pars) if e != nil { continue } l.SendData = resultList[i].SendData l.Result = resultList[i].ResultData if resultList[i].Ok { l.SendStatus = models.EnglishReportEmailLogStatusSuccess } else { l.SendStatus = models.EnglishReportEmailLogStatusFail failLogIds = append(failLogIds, l.Id) if requestMap[resultList[i].EmailId] != nil { resendList = append(resendList, requestMap[resultList[i].EmailId]) } // 取出错误信息 r := new(AliyunEmailResult) if e = json.Unmarshal([]byte(resultList[i].ResultData), &r); e != nil { continue } rd := new(AliyunEmailResultData) res := strings.Replace(r.Data, `\`, ``, -1) if e = json.Unmarshal([]byte(res), &rd); e != nil { continue } l.ErrMsg = rd.Message } if e = l.Update(updateCols); e != nil { continue } } // 推送失败的重新腾讯云, 若腾讯云也失败将不再自动重推, 用户手动去重推 if len(resendList) > 0 && len(failLogIds) > 0 { _ = ResendTencentEnglishReportEmail(resendList, failLogIds) } return } // ResendTencentEnglishReportEmail 腾讯云邮件重新推送 func ResendTencentEnglishReportEmail(resendList []*EnglishReportSendEmailRequest, failLogIds []int) (err error) { defer func() { if err != nil { go alarm_msg.SendAlarmMsg("腾讯云重发英文研报邮件失败, Err: "+err.Error(), 3) } }() if len(resendList) == 0 || len(failLogIds) == 0 { return } // 标记原有日志为已删除 if len(failLogIds) > 0 { if e := models.DeleteEnglishReportEmailLogByIds(failLogIds); e != nil { err = errors.New("删除原邮件日志失败, Err: " + e.Error()) return } } // 写入新的日志 nowTime := time.Now().Local() logData := make([]*models.EnglishReportEmailLog, 0) for i := range resendList { sendByte, e := json.Marshal(resendList[i]) if e != nil { err = errors.New("sendByte json.Marshal Err, Err: " + e.Error()) return } logData = append(logData, &models.EnglishReportEmailLog{ ReportId: resendList[i].ReportId, EmailId: resendList[i].EmailId, Email: resendList[i].Email, SendData: string(sendByte), Source: models.EnglishReportEmailLogSourceTencent, SendStatus: models.EnglishReportEmailLogStatusIng, CreateTime: nowTime, }) } emailLog := new(models.EnglishReportEmailLog) if e := emailLog.InsertMulti(logData); e != nil { err = errors.New("批量写入群发邮件日志失败, Err: " + e.Error()) return } // 请求腾讯云 tecentEmail := new(TencentEmail) resultList, e := tecentEmail.BatchSendEmail(resendList) if e != nil { err = e return } updateCols := []string{"SendData", "Result", "SendStatus", "ErrMsg"} for i := range resultList { var cond string var pars []interface{} cond = ` AND is_deleted = 0 AND report_id = ? AND email_id = ? AND source = ? AND send_status = ?` pars = append(pars, resultList[i].ReportId, resultList[i].EmailId, models.EnglishReportEmailLogSourceTencent, models.EnglishReportEmailLogStatusIng) l, e := models.GetEnglishReportEmailLog(cond, pars) if e != nil { continue } l.SendData = resultList[i].SendData l.Result = resultList[i].ResultData if resultList[i].Ok { l.SendStatus = models.EnglishReportEmailLogStatusSuccess } else { l.SendStatus = models.EnglishReportEmailLogStatusFail r := new(TencentEmailResult) if e = json.Unmarshal([]byte(resultList[i].ResultData), &r); e != nil { continue } l.ErrMsg = r.Message } if e = l.Update(updateCols); e != nil { continue } } return } // UpdateEnglishVideoEs 更新英文线上路演Es func UpdateEnglishVideoEs(videoId int, publishState int) (err error) { if videoId <= 0 { return } videoInfo, err := models.GetEnglishVideoById(videoId) if err != nil { return } // 新增报告ES esReport := &models.ElasticEnglishReportDetail{ Id: "v" + strconv.Itoa(videoInfo.Id), VideoId: videoInfo.Id, Title: videoInfo.Title, Abstract: videoInfo.Abstract, BodyContent: "", PublishTime: videoInfo.PublishTime, CreateTime: videoInfo.CreateTime, ReportCode: videoInfo.VideoCode, PublishState: publishState, Author: videoInfo.Author, Frequency: "", ClassifyIdFirst: videoInfo.ClassifyIdFirst, ClassifyNameFirst: videoInfo.ClassifyNameFirst, ClassifyIdSecond: videoInfo.ClassifyIdSecond, ClassifyNameSecond: videoInfo.ClassifyNameSecond, StageStr: "", Overview: utils.TrimHtml(html.UnescapeString(videoInfo.Overview)), ContentSub: "", } docId := fmt.Sprintf("v%d", videoInfo.Id) if err = EsAddOrEditEnglishReport(utils.EsEnglishReportIndexName, docId, esReport); err != nil { return } return } // UpdateEnglishCompanyEnabledByCompanyId 根据英文客户ID更新状态 func UpdateEnglishCompanyEnabledByCompanyId(companyId int) (err error) { defer func() { if err != nil { alarm_msg.SendAlarmMsg(fmt.Sprintf("更新英文客户状态失败, Err: %s", err.Error()), 3) } }() // 获取客户 comp, e := models.GetEnglishCompanyById(companyId) if e != nil { err = fmt.Errorf("英文客户已被删除") return } // 获取联系人 emailCond := ` AND company_id = ?` emailPars := make([]interface{}, 0) emailPars = append(emailPars, companyId) emailList, e := models.GetEnglishReportEmailList(emailCond, emailPars, "") if e != nil { err = fmt.Errorf("获取英文联系人列表失败, Err: %s", e.Error()) return } // 无联系人, 保持原状态 total := len(emailList) if total == 0 { return } // 判断状态, 是否部分禁用 status := 0 enabledCount := 0 for _, v := range emailList { if v.Enabled == 1 { enabledCount += 1 } } if enabledCount == 0 { status = models.EnglishCompanyDisabled } if total == enabledCount { status = models.EnglishCompanyEnabled } if total > enabledCount && enabledCount != 0 { status = models.EnglishCompanyHalfEnabled } // 是否需要更新 if comp.Enabled == status { return } comp.Enabled = status comp.ModifyTime = time.Now().Local() if e = comp.Update([]string{"Enabled", "ModifyTime"}); e != nil { err = fmt.Errorf("更新客户状态失败, Err: %s", e.Error()) return } return }