邹方成 45815bfb7d chore: 清理无用文件与优化代码结构
refactor(utils): 修复密码哈希比较逻辑错误
feat(user): 新增按状态筛选优惠券接口
docs: 添加虚拟发货与任务中心相关文档
fix(wechat): 修正Code2Session上下文传递问题
test: 补充订单折扣与积分转换测试用例
build: 更新配置文件与构建脚本
style: 清理多余的空行与注释
2025-12-18 17:35:55 +08:00

232 lines
4.6 KiB
Go
Raw 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 (
"bytes"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/tealeg/xlsx"
"golang.org/x/crypto/bcrypt"
)
// GenerateAdminHashedPassword [管理端]生成密码
func GenerateAdminHashedPassword(password string) (string, error) {
salt := "7M&7p7euU=CC"
passwordWithSalt := password + salt
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(passwordWithSalt), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedPassword), nil
}
// VerifyAdminHashedPassword [管理端]验证密码
func VerifyAdminHashedPassword(hashedPassword, password string) bool {
salt := "7M&7p7euU=CC"
passwordWithSalt := password + salt
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(passwordWithSalt))
return err == nil
}
// ToExcel 生成 Excel
func ToExcel(titleList []string, dataList []interface{}) []byte {
// 生成一个新的文件
file := xlsx.NewFile()
// 添加sheet页
sheet, _ := file.AddSheet("Sheet1")
// 插入表头
titleRow := sheet.AddRow()
for _, v := range titleList {
cell := titleRow.AddCell()
cell.Value = v
}
// 插入内容
for _, v := range dataList {
row := sheet.AddRow()
row.WriteStruct(v, -1)
}
var buffer bytes.Buffer
_ = file.Write(&buffer)
return buffer.Bytes()
}
func MD5(text string) string {
hash := md5.New()
hash.Write([]byte(text))
hashBytes := hash.Sum(nil)
return hex.EncodeToString(hashBytes)
}
// GetIP 尝试从 HTTP 请求中获取真实的客户端 IP 地址
func GetIP(r *http.Request) string {
// 从 X-Forwarded-For 头部获取IP地址
xForwardedFor := r.Header.Get("X-Forwarded-For")
if xForwardedFor != "" {
// 可能有多个IP地址通常第一个是客户端的真实IP
ips := strings.Split(xForwardedFor, ",")
if len(ips) > 0 {
return strings.TrimSpace(ips[0])
}
}
// 如果没有 X-Forwarded-For 头部,尝试从 X-Real-IP 获取
xRealIP := r.Header.Get("X-Real-IP")
if xRealIP != "" {
return strings.TrimSpace(xRealIP)
}
// 如果没有代理头部,最后退回到 RemoteAddr
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
// 如果处理RemoteAddr出错返回空字符串
return ""
}
return ip
}
// FriendlyTimeAgo 友好时间
func FriendlyTimeAgo(date time.Time) string {
now := time.Now()
if date.After(now) {
return "未来的日期"
}
diff := now.Sub(date)
minutes := int(diff.Minutes())
hours := int(diff.Hours())
days := int(hours / 24)
// 小于1分钟
if minutes < 1 {
return "刚刚"
}
// 小于1小时
if hours < 1 {
return fmt.Sprintf("%d分钟", minutes)
}
// 小于1天
if hours < 24 {
return fmt.Sprintf("%d小时", hours)
}
// 小于1周
if days < 7 {
return fmt.Sprintf("%d天", days)
}
// 小于1个月
if days < 30 {
return fmt.Sprintf("%d周", days/7)
}
// 小于1年
if days < 365 {
months := int(days / 30)
if months < 1 {
return fmt.Sprintf("%d天", days)
}
return fmt.Sprintf("%d个月", months)
}
// 大于等于1年
years := days / 365
remainingDays := days % 365
months := remainingDays / 30
if months == 0 {
return fmt.Sprintf("%d年", years)
}
return fmt.Sprintf("%d年%d个月", years, months)
}
// FriendlySubTime 时间相减
func FriendlySubTime(birthday, date time.Time) string {
diff := date.Sub(birthday)
minutes := int(diff.Minutes())
hours := int(diff.Hours())
days := int(hours / 24)
// 小于1分钟
if minutes < 1 {
return "刚刚"
}
// 小于1小时
if hours < 1 {
return fmt.Sprintf("%d分钟", minutes)
}
// 小于1天
if hours < 24 {
return fmt.Sprintf("%d小时", hours)
}
// 小于1周
if days < 7 {
return fmt.Sprintf("%d天", days)
}
// 小于1个月
if days < 30 {
return fmt.Sprintf("%d周", days/7)
}
// 小于1年
if days < 365 {
months := int(days / 30)
if months < 1 {
return fmt.Sprintf("%d天", days)
}
return fmt.Sprintf("%d个月", months)
}
// 大于等于1年
years := days / 365
remainingDays := days % 365
months := remainingDays / 30
if months == 0 {
return fmt.Sprintf("%d岁", years)
}
return fmt.Sprintf("%d岁%d个月", years, months)
}
func XorEncrypt(phone, key string) string {
result := make([]byte, len(phone))
for i := 0; i < len(phone); i++ {
result[i] = phone[i] ^ key[i%len(key)]
}
return base64.StdEncoding.EncodeToString(result)
}
func XorDecrypt(encrypted, key string) (string, error) {
data, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return "", err
}
result := make([]byte, len(data))
for i := 0; i < len(data); i++ {
result[i] = data[i] ^ key[i%len(key)]
}
return string(result), nil
}