package warningnotify import ( "fmt" "html" "strings" "time" ) const warningEmailHTMLSignature = `data-warning-email="iotlcm"` func applyContent(batch *Batch) { if batch == nil { return } batch.SMSContent = buildSMSContent(*batch) batch.EmailSubject = buildEmailSubject(*batch) batch.EmailBody = buildEmailBody(*batch) batch.PlatformTitle = buildPlatformTitle(*batch) batch.PlatformContent = buildPlatformContent(*batch) } func buildSMSContent(batch Batch) string { count := len(batch.Items) if count == 0 { return "" } summary := batchObjectSummary(batch) title := warningTitle(batch) action := "" if hasAffectOperation(batch.Items) { action = ",涉及停机或断网操作" } return fmt.Sprintf( "【物联网】%s触发%s%s,请登录控制台查看。", summary, title, action, ) } func buildEmailSubject(batch Batch) string { count := len(batch.Items) if count == 0 { return "物联网预警提醒" } return fmt.Sprintf("%s(%d条)", warningTitle(batch), count) } func buildEmailBody(batch Batch) string { count := len(batch.Items) if count == 0 { return "" } var builder strings.Builder builder.WriteString(`
`) fmt.Fprintf(&builder, `

%s,共 %d 条,最高级别:%s。

`, htmlEscape(warningTitle(batch)), count, htmlEscape(levelText(highestLevel(batch.Items)))) if hasAffectOperation(batch.Items) { builder.WriteString(`

本次预警包含停机或断网类操作,请重点确认。

`) } builder.WriteString(``) builder.WriteString(``) builder.WriteString(emailHeaderCell(emailObjectHeader(batch))) builder.WriteString(emailHeaderCell("预警类型")) builder.WriteString(emailHeaderCell("预警原因")) builder.WriteString(emailHeaderCell("预警时间")) builder.WriteString(``) for _, item := range batch.Items { builder.WriteString(``) builder.WriteString(emailBodyCell(displayObjectCode(item))) builder.WriteString(emailBodyCell(emailWarningType(item, batch))) builder.WriteString(emailBodyCell(emailWarningReason(item))) builder.WriteString(emailBodyCell(emailWarnTime(item))) builder.WriteString(``) } builder.WriteString(`
`) return strings.TrimSpace(builder.String()) } func buildPlatformTitle(batch Batch) string { if len(batch.Items) == 0 { return "预警提醒" } if title := expireDayPlatformTitle(batch); title != "" { return title } return warningTitle(batch) } func buildPlatformContent(batch Batch) string { count := len(batch.Items) if count == 0 { return "" } content := buildPlatformSummaryContent(batch) if hasAffectOperation(batch.Items) { content += "本次提醒包含停机或断网类操作,请及时确认。" } return content } func buildPlatformSummaryContent(batch Batch) string { if isExpireDayBatch(batch) { return fmt.Sprintf( "%s有%d张卡临近到期,最高档位:%s,请登录控制台查看。", firstObjectCode(batch), len(batch.Items), buildPlatformTitle(batch), ) } return fmt.Sprintf( "%s触发%s,最高级别:%s,请登录控制台查看。", batchObjectSummary(batch), buildPlatformTitle(batch), levelText(highestLevel(batch.Items)), ) } func warningTitle(batch Batch) string { category := warningCategory(batch) return categoryStageTitle(category, batch.WarnStage) } func warningCategory(batch Batch) string { category := strings.TrimSpace(batch.Category) if category == "" { category = "预警" } return category } func categoryStageTitle(category string, stage int) string { category = strings.TrimSpace(category) if category == "" { category = "预警" } if stage > 0 { return category + stageText(stage) } if strings.HasSuffix(category, "提醒") { return category } return category + "提醒" } func expireDayPlatformTitle(batch Batch) string { if !isExpireDayBatch(batch) { return "" } threshold := expireDayPlatformThreshold(batch) if threshold <= 0 { return "距离到期时间预警" } return fmt.Sprintf("距离到期时间小于%.0f天", threshold) } func isExpireDayBatch(batch Batch) bool { category := strings.TrimSpace(batch.Category) for _, item := range batch.Items { if strings.TrimSpace(item.Kind) == "expire_day" { return true } if strings.Contains(category, "到期") && strings.TrimSpace(item.UnitText) == "天" { return true } } return false } func expireDayPlatformThreshold(batch Batch) float64 { for _, item := range batch.Items { if item.WarnStage == batch.WarnStage && item.Threshold > 0 { return item.Threshold } } for _, item := range batch.Items { if item.Threshold > 0 { return item.Threshold } } switch batch.WarnStage { case 1: return 30 case 2: return 15 case 3: return 7 default: return 0 } } func itemDetailSummary(item Event) string { return itemSummary(item) } func batchObjectSummary(batch Batch) string { count := len(batch.Items) if count == 0 { return "" } code := firstObjectCode(batch) if count == 1 { return code } return fmt.Sprintf("%s等%d%s", code, count, objectCountUnit(batch.Items[0])) } func firstObjectCode(batch Batch) string { if len(batch.Items) == 0 { return "--" } return displayObjectCode(batch.Items[0]) } func objectCountUnit(item Event) string { switch item.ItemType { case 2: return "个流量池" default: return "张卡" } } func metricSummary(item Event) string { unit := strings.TrimSpace(item.UnitText) switch unit { case "天", "月": parts := []string{ "剩余" + formatMetric(item.Actual, unit), } if item.Threshold > 0 { parts = append(parts, "阈值"+formatMetric(item.Threshold, unit)) } return strings.Join(parts, ",") case "%": parts := []string{ "阈值" + formatMetric(item.Threshold, unit), "实际" + formatMetric(item.Actual, unit), } if shouldShowRemain(item) { parts = append(parts, "剩余"+remainMetric(item)) } if item.TotalFlowMB > 0 { parts = append(parts, "总量"+formatMetric(item.TotalFlowMB, "MB")) } return strings.Join(parts, ",") default: parts := []string{ "阈值" + formatMetric(item.Threshold, item.UnitText), "实际" + formatMetric(item.Actual, item.UnitText), } if shouldShowRemain(item) { parts = append(parts, "剩余"+remainMetric(item)) } if item.TotalFlowMB > 0 { parts = append(parts, "总量"+formatMetric(item.TotalFlowMB, "MB")) } return strings.Join(parts, ",") } } func itemSummary(item Event) string { parts := make([]string, 0, 1) parts = append(parts, fmt.Sprintf("%s:%s", itemLabel(item), displayObjectCode(item))) return strings.Join(parts, ",") } func itemLabel(item Event) string { switch item.ItemType { case 2: return "流量池编号" default: return "ICCID" } } func displayObjectCode(item Event) string { itemCode := strings.TrimSpace(item.ItemCode) if itemCode == "" { return "--" } return itemCode } func stageText(stage int) string { if stage <= 0 { return "" } return fmt.Sprintf("第%d次提醒", stage) } func levelText(level int) string { switch level { case 1: return "提示" case 2: return "注意" case 3: return "警告" case 4: return "危险" case 5: return "紧急" default: return "提醒" } } func highestLevel(items []Event) int { level := 0 for _, item := range items { if item.WarnLevel > level { level = item.WarnLevel } } return level } func hasAffectOperation(items []Event) bool { for _, item := range items { if item.AffectOperation { return true } } return false } func shouldShowRemain(item Event) bool { if item.TotalFlowMB > 0 { return true } unit := strings.TrimSpace(item.UnitText) return unit == "MB" || unit == "%" } func remainMetric(item Event) string { if !shouldShowRemain(item) { return "--" } return formatMetric(item.RemainFlowMB, "MB") } func formatMetric(value float64, unit string) string { unit = strings.TrimSpace(unit) switch unit { case "%": return fmt.Sprintf("%.2f%%", value) case "天", "月": return fmt.Sprintf("%.0f%s", value, unit) case "MB": return fmt.Sprintf("%.3f MB", value) default: if unit == "" { return fmt.Sprintf("%.3f", value) } return fmt.Sprintf("%.3f %s", value, unit) } } func formatTime(value time.Time) string { return value.Format("2006-01-02 15:04:05") } func emailObjectHeader(batch Batch) string { if len(batch.Items) == 0 { return "ICCID" } for _, item := range batch.Items { if item.ItemType != 2 { return "ICCID" } } return "流量池编号" } func emailWarningType(item Event, batch Batch) string { category := strings.TrimSpace(item.Category) if category != "" { return category } return warningCategory(batch) } func emailWarningReason(item Event) string { parts := make([]string, 0, 3) if item.WarnStage > 0 { parts = append(parts, stageText(item.WarnStage)) } if summary := metricSummary(item); summary != "" { parts = append(parts, summary) } if item.OperationText != "" { parts = append(parts, item.OperationText) } if len(parts) == 0 && item.Remark != "" { parts = append(parts, item.Remark) } return strings.Join(parts, ",") } func emailWarnTime(item Event) string { if item.WarnTime.IsZero() { return "--" } return formatTime(item.WarnTime) } func emailHeaderCell(value string) string { return `` + htmlEscape(value) + `` } func emailBodyCell(value string) string { return `` + htmlEscape(value) + `` } func htmlEscape(value string) string { value = strings.TrimSpace(value) if value == "" { return "--" } return html.EscapeString(value) }