package utils import ( "crypto/md5" "crypto/rand" "encoding/hex" "fmt" "math" "strconv" "strings" "time" "golang.org/x/crypto/bcrypt" ) // HashPassword 密码加密 func HashPassword(password string) (string, error) { bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) return string(bytes), err } // CheckPassword 验证密码 func CheckPassword(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } // MD5 MD5加密 func MD5(str string) string { h := md5.New() h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } // GenerateRandomString 生成随机字符串 func GenerateRandomString(length int) string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" b := make([]byte, length) for i := range b { randomByte := make([]byte, 1) rand.Read(randomByte) b[i] = charset[randomByte[0]%byte(len(charset))] } return string(b) } // GenerateOrderNo 生成订单号 func GenerateOrderNo() string { now := time.Now() timestamp := now.Format("20060102150405") random := GenerateRandomString(6) return timestamp + strings.ToUpper(random) } // GenerateWechatOutTradeNo 生成微信支付商户订单号 // 格式:WX + 时间戳(精确到毫秒) + 8位随机字符串 // 确保每次支付请求都有唯一的订单号,避免重复支付问题 func GenerateWechatOutTradeNo() string { now := time.Now() // 使用纳秒时间戳确保唯一性 timestamp := now.Format("20060102150405") + fmt.Sprintf("%03d", now.Nanosecond()/1000000) random := GenerateRandomString(8) return "WX" + timestamp + strings.ToUpper(random) } // GenerateRefundNo 生成退款单号 func GenerateRefundNo() string { now := time.Now() timestamp := now.Format("20060102150405") random := GenerateRandomString(6) return "RF" + timestamp + strings.ToUpper(random) } // GenerateWechatOutRefundNo 生成微信退款单号 // 格式:WXR + 时间戳(精确到毫秒) + 8位随机字符串 func GenerateWechatOutRefundNo() string { now := time.Now() // 使用纳秒时间戳确保唯一性 timestamp := now.Format("20060102150405") + fmt.Sprintf("%03d", now.Nanosecond()/1000000) random := GenerateRandomString(8) return "WXR" + timestamp + strings.ToUpper(random) } // StringToUint 字符串转uint func StringToUint(str string) uint { if str == "" { return 0 } num, err := strconv.ParseUint(str, 10, 32) if err != nil { return 0 } return uint(num) } // StringToInt 字符串转int func StringToInt(str string) int { if str == "" { return 0 } num, err := strconv.Atoi(str) if err != nil { return 0 } return num } // StringToFloat64 字符串转float64 func StringToFloat64(str string) float64 { if str == "" { return 0 } num, err := strconv.ParseFloat(str, 64) if err != nil { return 0 } return num } // UintToString uint转字符串 func UintToString(num uint) string { return strconv.FormatUint(uint64(num), 10) } // IntToString 整数转字符串 func IntToString(num int) string { return strconv.Itoa(num) } // FloatToString 浮点数转字符串 func FloatToString(num float64) string { return fmt.Sprintf("%.0f", num) } // BoolToInt bool转int func BoolToInt(b bool) int { if b { return 1 } return 0 } // FormatPrice 格式化价格(分转元) func FormatPrice(price uint) string { yuan := float64(price) / 100 return fmt.Sprintf("%.2f", yuan) } // ParsePrice 解析价格(元转分) func ParsePrice(priceStr string) uint { price, err := strconv.ParseFloat(priceStr, 64) if err != nil { return 0 } return uint(math.Round(price * 100)) } // InArray 检查元素是否在数组中 func InArray(needle interface{}, haystack []interface{}) bool { for _, item := range haystack { if item == needle { return true } } return false } // InStringArray 检查字符串是否在字符串数组中 func InStringArray(needle string, haystack []string) bool { for _, item := range haystack { if item == needle { return true } } return false } // InUintArray 检查uint是否在uint数组中 func InUintArray(needle uint, haystack []uint) bool { for _, item := range haystack { if item == needle { return true } } return false } // RemoveDuplicateStrings 去除字符串数组重复元素 func RemoveDuplicateStrings(slice []string) []string { keys := make(map[string]bool) result := []string{} for _, item := range slice { if !keys[item] { keys[item] = true result = append(result, item) } } return result } // RemoveDuplicateUints 去除uint数组重复元素 func RemoveDuplicateUints(slice []uint) []uint { keys := make(map[uint]bool) result := []uint{} for _, item := range slice { if !keys[item] { keys[item] = true result = append(result, item) } } return result } // GetClientIP 获取客户端IP func GetClientIP(remoteAddr, xForwardedFor, xRealIP string) string { if xRealIP != "" { return xRealIP } if xForwardedFor != "" { ips := strings.Split(xForwardedFor, ",") if len(ips) > 0 { return strings.TrimSpace(ips[0]) } } if remoteAddr != "" { ip := strings.Split(remoteAddr, ":")[0] return ip } return "unknown" } // Pagination 分页计算 type Pagination struct { Page int `json:"page"` PageSize int `json:"page_size"` Total int64 `json:"total"` Offset int `json:"offset"` Limit int `json:"limit"` } // NewPagination 创建分页对象 func NewPagination(page, pageSize int) *Pagination { if page <= 0 { page = 1 } if pageSize <= 0 { pageSize = 10 } if pageSize > 100 { pageSize = 100 } offset := (page - 1) * pageSize return &Pagination{ Page: page, PageSize: pageSize, Offset: offset, Limit: pageSize, } } // IsValidEmail 验证邮箱格式 func IsValidEmail(email string) bool { // 简单的邮箱格式验证 return strings.Contains(email, "@") && strings.Contains(email, ".") } // IsValidPhone 验证手机号格式 func IsValidPhone(phone string) bool { // 简单的手机号格式验证(中国大陆) if len(phone) != 11 { return false } return strings.HasPrefix(phone, "1") } // TruncateString 截断字符串 func TruncateString(str string, length int) string { if len(str) <= length { return str } return str[:length] + "..." } // GetTimeRange 获取时间范围 func GetTimeRange(rangeType string) (time.Time, time.Time) { now := time.Now() var start, end time.Time switch rangeType { case "today": start = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) end = start.Add(24 * time.Hour).Add(-time.Nanosecond) case "yesterday": yesterday := now.AddDate(0, 0, -1) start = time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()) end = start.Add(24 * time.Hour).Add(-time.Nanosecond) case "week": weekday := int(now.Weekday()) if weekday == 0 { weekday = 7 } start = now.AddDate(0, 0, -weekday+1) start = time.Date(start.Year(), start.Month(), start.Day(), 0, 0, 0, 0, start.Location()) end = start.AddDate(0, 0, 7).Add(-time.Nanosecond) case "month": start = time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location()) end = start.AddDate(0, 1, 0).Add(-time.Nanosecond) default: start = now end = now } return start, end }