package sms import ( "fmt" "strings" ) // newSys 按 Provider 建对应服务商的客户端(腾讯云 / 阿里云)。 func newSys(options Options) (sys ISys, err error) { switch options.provider() { case ProviderTencent: return newTencent(options) case ProviderAliyun: return newAliyun(options) default: return nil, fmt.Errorf("sms 未知服务商: %s", options.Provider) } } // isDomestic 判断是否国内号码(决定用国内模板还是国际模板)。 // 号码来自客户端,格式不统一:可能是 +8613…、008613…、13… 或国际号 +852…。 // 带国家码前缀的看前缀;不带前缀的只有"1 开头的 11 位"按国内算(大陆手机号), // 其余仍按国际处理——与加入阿里云之前的行为保持一致。 func isDomestic(mobile string) bool { m := normalizeMobile(mobile) if strings.HasPrefix(m, "+") { return strings.HasPrefix(m, "+86") } if strings.HasPrefix(m, "00") { return strings.HasPrefix(m, "0086") } return len(m) == 11 && strings.HasPrefix(m, "1") } // normalizeMobile 去掉号码里的空格、短横等分隔符。 func normalizeMobile(mobile string) string { return strings.NewReplacer(" ", "", "-", "", "\t", "").Replace(strings.TrimSpace(mobile)) } // pickTemplate 按号码归属选模板;对应模板没配时回退到另一个,两个都没配则报错 // (模板 ID 是发短信的必填项,缺了发出去也是失败,不如早点给出可读的错误)。 func pickTemplate(o Options, mobile string) (string, error) { domestic := isDomestic(mobile) primary, fallback := o.Template1, o.Template2 if !domestic { primary, fallback = o.Template2, o.Template1 } if primary != "" { return primary, nil } if fallback != "" { return fallback, nil } return "", fmt.Errorf("sms 配置缺失: 未配置短信模板(Template1/Template2)") }