feat: product item
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
// 短信签名常量
|
||||
const (
|
||||
//SignLone = "爱萝湾"
|
||||
SignLone = "爱萝湾上海科技有限公司"
|
||||
)
|
||||
|
||||
// 短信模板CODE常量
|
||||
const (
|
||||
SmsCode = "SMS_506160477"
|
||||
SmsPwd = "SMS_506200455"
|
||||
)
|
||||
|
||||
// 状态码常量(模拟PHP中的Code类)
|
||||
const (
|
||||
CodeOK = 0 // 成功状态码
|
||||
CodeError = -1 // 错误状态码
|
||||
)
|
||||
|
||||
// ResponseData 短信发送返回结构体
|
||||
type ResponseData struct {
|
||||
Code int `json:"code"`
|
||||
Msg interface{} `json:"msg"`
|
||||
}
|
||||
|
||||
type EmailMsg struct {
|
||||
To []string // 收件人
|
||||
Cc []string // 抄送
|
||||
Bcc []string // 密送
|
||||
Subject string // 标题
|
||||
Body string // 正文,支持html
|
||||
IsHTML bool // 是否HTML格式
|
||||
}
|
||||
|
||||
// CreateClient 创建阿里云短信客户端
|
||||
func CreateClient() (*dysmsapi20170525.Client, error) {
|
||||
// 加载.env文件(如果需要)
|
||||
_ = godotenv.Load()
|
||||
|
||||
key := GetConfigString("sms.sms_ali_api_key")
|
||||
secret := GetConfigString("sms.sms_ali_api_secret")
|
||||
// 初始化配置
|
||||
config := &openapi.Config{
|
||||
// 从环境变量获取AccessKey ID
|
||||
AccessKeyId: &key,
|
||||
// 从环境变量获取AccessKey Secret
|
||||
AccessKeySecret: &secret,
|
||||
}
|
||||
// 设置短信服务接入点
|
||||
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
|
||||
|
||||
// 创建客户端
|
||||
client, err := dysmsapi20170525.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// SendSMS 发送短信主方法
|
||||
// mobile: 手机号
|
||||
// code: 短信模板CODE
|
||||
// data: 模板参数(map格式)
|
||||
// sign: 短信签名(可选,默认使用SignLone)
|
||||
func SendSMS(mobile, code string, data map[string]interface{}, sign ...string) ResponseData {
|
||||
test := GetConfigBool("sms.sms_test")
|
||||
retData := ResponseData{
|
||||
Code: CodeOK,
|
||||
Msg: "",
|
||||
}
|
||||
if test {
|
||||
return retData
|
||||
}
|
||||
// 设置默认签名
|
||||
signName := SignLone
|
||||
name := GetConfigString("sms.sms_sign")
|
||||
if name != "" {
|
||||
signName = name
|
||||
}
|
||||
|
||||
if len(sign) > 0 && sign[0] != "" {
|
||||
signName = sign[0]
|
||||
}
|
||||
|
||||
// 创建客户端
|
||||
client, err := CreateClient()
|
||||
if err != nil {
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: fmt.Sprintf("创建客户端失败: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
// 转换模板参数为JSON字符串
|
||||
templateParam, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: fmt.Sprintf("参数JSON编码失败: %s", err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
// 构建发送短信请求
|
||||
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
|
||||
PhoneNumbers: tea.String(mobile),
|
||||
SignName: tea.String(signName),
|
||||
TemplateCode: tea.String(code),
|
||||
TemplateParam: tea.String(string(templateParam)),
|
||||
}
|
||||
|
||||
Logger.Error(signName, "m=", mobile, "<UNK>:", sendSmsRequest, "2=", code, "tmpo:", string(templateParam))
|
||||
|
||||
// 发送短信
|
||||
response, err := client.SendSms(sendSmsRequest)
|
||||
if err != nil {
|
||||
// 处理错误
|
||||
retData.Code = CodeError
|
||||
retData.Msg = fmt.Sprintf("发送短信失败: %s", err.Error())
|
||||
return retData
|
||||
}
|
||||
|
||||
statusCode := *response.StatusCode
|
||||
|
||||
// 检查响应状态
|
||||
if statusCode != 200 {
|
||||
retData.Code = CodeError
|
||||
}
|
||||
|
||||
// 将响应转换为map返回
|
||||
retData.Msg = map[string]interface{}{
|
||||
"StatusCode": response.StatusCode,
|
||||
"Body": response.Body,
|
||||
}
|
||||
|
||||
return retData
|
||||
}
|
||||
|
||||
// 简化调用示例(可选)
|
||||
// SendCodeSMS 发送验证码短信
|
||||
func SendCodeSMS(mobile string, code string) ResponseData {
|
||||
data := map[string]interface{}{
|
||||
"code": code,
|
||||
}
|
||||
code = GetConfigString("sms.sms_code_sign")
|
||||
if code == "" {
|
||||
code = SmsCode
|
||||
}
|
||||
return SendSMS(mobile, code, data)
|
||||
}
|
||||
|
||||
func SendCodeMail(msg EmailMsg) ResponseData {
|
||||
user := GetConfigString("sms.sms_mail_user")
|
||||
pwd := GetConfigString("sms.sms_mail_pwd")
|
||||
host := GetConfigString("sms.sms_mail_host")
|
||||
port := GetConfigInt("sms.sms_mail_port")
|
||||
name := GetConfigString("sms.sms_mail_show_name")
|
||||
auth := smtp.PlainAuth("", user, pwd, host)
|
||||
from := fmt.Sprintf("%s <%s>", name, user)
|
||||
// 构建邮件头部
|
||||
var header string
|
||||
header += fmt.Sprintf("From: %s\r\n", from)
|
||||
header += fmt.Sprintf("To: %s\r\n", joinStrings(msg.To, ","))
|
||||
if len(msg.Cc) > 0 {
|
||||
header += fmt.Sprintf("Cc: %s\r\n", joinStrings(msg.Cc, ","))
|
||||
}
|
||||
if len(msg.Bcc) > 0 {
|
||||
header += fmt.Sprintf("Bcc: %s\r\n", joinStrings(msg.Bcc, ","))
|
||||
}
|
||||
header += fmt.Sprintf("Subject: %s\r\n", msg.Subject)
|
||||
|
||||
contentType := "text/plain; charset=utf-8"
|
||||
if msg.IsHTML {
|
||||
contentType = "text/html; charset=utf-8"
|
||||
}
|
||||
header += fmt.Sprintf("Content-Type: %s\r\n\r\n", contentType)
|
||||
fullMsg := []byte(header + msg.Body)
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
ServerName: host,
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", host, port)
|
||||
|
||||
// 1. 先建立SSL连接(465端口)
|
||||
conn, err := tls.Dial("tcp", addr, tlsConfig)
|
||||
if err != nil {
|
||||
Logger.Error("tls dial err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
// 2. 关键:用加密连接创建smtp client
|
||||
client, err := smtp.NewClient(conn, host)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
Logger.Error("smtp.NewClient err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
// 由client统一管理连接关闭
|
||||
defer client.Close()
|
||||
|
||||
if err = client.Auth(auth); err != nil {
|
||||
Logger.Error("client.Auth err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
if err = client.Mail(user); err != nil {
|
||||
Logger.Error("client.Mail err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
receivers := append(append(msg.To, msg.Cc...), msg.Bcc...)
|
||||
for _, r := range receivers {
|
||||
if err = client.Rcpt(r); err != nil {
|
||||
Logger.Error("client.Rcpt err:", err, "rcpt:", r)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
Logger.Error("client.Data err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
_, err = w.Write(fullMsg)
|
||||
if err != nil {
|
||||
Logger.Error("write mail body err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
Logger.Error("w.Close err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
err = client.Quit()
|
||||
if err != nil {
|
||||
Logger.Error("client.Quit err:", err)
|
||||
return ResponseData{
|
||||
Code: CodeError,
|
||||
Msg: "smtp quit failed: " + err.Error(),
|
||||
}
|
||||
}
|
||||
return ResponseData{
|
||||
Code: CodeOK,
|
||||
Msg: "",
|
||||
}
|
||||
}
|
||||
|
||||
func joinStrings(arr []string, sep string) string {
|
||||
if len(arr) == 0 {
|
||||
return ""
|
||||
}
|
||||
res := arr[0]
|
||||
for i := 1; i < len(arr); i++ {
|
||||
res += sep + arr[i]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// SendPwdSMS 发送密码相关短信
|
||||
func SendPwdSMS(mobile string, pwd string) ResponseData {
|
||||
data := map[string]interface{}{
|
||||
"code": pwd,
|
||||
}
|
||||
|
||||
code := GetConfigString("sms.sms_code_sign")
|
||||
if code == "" {
|
||||
code = SmsPwd
|
||||
}
|
||||
return SendSMS(mobile, code, data)
|
||||
}
|
||||
Reference in New Issue
Block a user