package warningnotify
import (
"fmt"
"html"
"strings"
"time"
)
const warningEmailHTMLSignature = `data-warning-email="iotlcm"`
func applyContent(batch *Batch) {
if batch == nil {
return
}
switch batch.Method {
case MethodSMS:
batch.SMSContent = buildSMSContent(*batch)
case MethodEmail:
batch.EmailSubject = buildEmailSubject(*batch)
batch.EmailBody = buildEmailBody(*batch)
case MethodPlatform:
batch.PlatformTitle = buildPlatformTitle(*batch)
batch.PlatformContent = buildPlatformContent(*batch)
}
}
func buildSMSContent(batch Batch) string {
count := batchItemCount(batch)
if count == 0 {
return ""
}
summary := batchObjectSummary(batch)
title := warningTitle(batch)
action := ""
if batchHasAffectOperation(batch) {
action = ",涉及停机或断网操作"
}
return fmt.Sprintf(
"【物联网】%s触发%s%s,请登录控制台查看。",
summary,
title,
action,
)
}
func buildEmailSubject(batch Batch) string {
count := batchItemCount(batch)
if count == 0 {
return "物联网预警提醒"
}
return fmt.Sprintf("%s(%d条)", warningTitle(batch), count)
}
func buildEmailBody(batch Batch) string {
count := batchItemCount(batch)
if count == 0 {
return ""
}
var builder strings.Builder
builder.WriteString(`
`)
fmt.Fprintf(&builder, `
%s,共 %d 条,最高级别:%s。
`, htmlEscape(warningTitle(batch)), count, htmlEscape(levelText(batchHighestLevel(batch))))
if batchHasAffectOperation(batch) {
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 := batchItemCount(batch)
if count == 0 {
return ""
}
content := buildPlatformSummaryContent(batch)
if batchHasAffectOperation(batch) {
content += "本次提醒包含停机或断网类操作,请及时确认。"
}
return content
}
func buildPlatformSummaryContent(batch Batch) string {
if isExpireDayBatch(batch) {
return fmt.Sprintf(
"%s有%d张卡临近到期,最高档位:%s,请登录控制台查看。",
firstObjectCode(batch),
batchItemCount(batch),
buildPlatformTitle(batch),
)
}
return fmt.Sprintf(
"%s触发%s,最高级别:%s,请登录控制台查看。",
platformObjectSummary(batch),
buildPlatformTitle(batch),
levelText(batchHighestLevel(batch)),
)
}
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 := batchItemCount(batch)
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)
}
func platformObjectSummary(batch Batch) string {
if len(batch.Items) == 0 {
return ""
}
if batchItemCount(batch) > 5 {
return fmt.Sprintf("\u5171%d%s", batchItemCount(batch), objectCountUnit(batch.Items[0]))
}
codes := make([]string, 0, len(batch.Items))
for _, item := range batch.Items {
codes = append(codes, displayObjectCode(item))
}
return strings.Join(codes, "\u3001")
}