Files
ai_dianshang/server/pkg/utils/utils.go

315 lines
7.2 KiB
Go
Raw Normal View History

2025-11-17 14:11:46 +08:00
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
}