Files
ai_dianshang/server/pkg/utils/utils.go
2025-11-17 14:11:46 +08:00

315 lines
7.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}