初始化
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Encrypt 加密函数
|
||||
func Encrypt(text, key string) (string, error) {
|
||||
plaintext := []byte(text)
|
||||
hashedKey := hashKey(key)
|
||||
|
||||
// 创建一个新的 AES cipher.Block
|
||||
block, err := aes.NewCipher(hashedKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 使用 GCM 模式加密
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nonce := make([]byte, aesGCM.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 加密数据
|
||||
ciphertext := aesGCM.Seal(nonce, nonce, plaintext, nil)
|
||||
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
||||
}
|
||||
|
||||
// Decrypt 解密函数
|
||||
func Decrypt(cryptoText, key string) (string, error) {
|
||||
ciphertext, _ := base64.StdEncoding.DecodeString(cryptoText)
|
||||
hashedKey := hashKey(key)
|
||||
|
||||
// 创建一个新的 AES cipher.Block
|
||||
block, err := aes.NewCipher(hashedKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 使用 GCM 模式解密
|
||||
aesGCM, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nonceSize := aesGCM.NonceSize()
|
||||
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
||||
|
||||
// 解密数据
|
||||
plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
||||
// HashString 使用SHA256算法对字符串进行哈希加密
|
||||
func HashString(s string) string {
|
||||
// 创建一个新的SHA256哈希实例
|
||||
hasher := sha256.New()
|
||||
|
||||
// 写入要哈希的字符串的字节
|
||||
hasher.Write([]byte(s))
|
||||
|
||||
// 获取哈希结果的字节切片
|
||||
hashBytes := hasher.Sum(nil)
|
||||
|
||||
// 将字节切片转换成十六进制字符串表示
|
||||
s = hex.EncodeToString(hashBytes)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// HmacSHA256 计算 HMAC-SHA256 签名
|
||||
func HmacSHA256(data string, key string) string {
|
||||
// 创建新的 HMAC 使用 SHA256 哈希函数
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
// 写入数据
|
||||
h.Write([]byte(data))
|
||||
// 计算 HMAC-SHA256 并返回其字节切片
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// 将任意长度的密钥转换为适合 AES 的长度(32 字节)
|
||||
func hashKey(key string) []byte {
|
||||
hash := sha256.Sum256([]byte(key))
|
||||
return hash[:]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/mojocn/base64Captcha"
|
||||
"image/color"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GenerateCaptcha 生成验证码-base64
|
||||
func GenerateCaptcha() (id, b64s string, err error) {
|
||||
var driver *base64Captcha.DriverString
|
||||
// 配置验证码的参数
|
||||
driverString := &base64Captcha.DriverString{
|
||||
Height: 40,
|
||||
Width: 100,
|
||||
NoiseCount: 0,
|
||||
ShowLineOptions: 0,
|
||||
Length: 4,
|
||||
Source: "1234567890",
|
||||
BgColor: &color.RGBA{R: 3, G: 102, B: 214, A: 125},
|
||||
Fonts: []string{"wqy-microhei.ttc"},
|
||||
}
|
||||
// ConvertFonts 按名称加载字体
|
||||
driver = driverString.ConvertFonts()
|
||||
|
||||
base64Captcha.Expiration = 30 * time.Minute
|
||||
store := base64Captcha.DefaultMemStore
|
||||
|
||||
captcha := base64Captcha.NewCaptcha(driver, store)
|
||||
id, b64s, _, err = captcha.Generate()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return id, b64s, nil
|
||||
}
|
||||
|
||||
// VerifyCaptcha 验证验证码
|
||||
func VerifyCaptcha(id, answer string) bool {
|
||||
// 创建验证码实例
|
||||
base64Captcha.Expiration = 30 * time.Minute
|
||||
store := base64Captcha.DefaultMemStore
|
||||
captcha := base64Captcha.NewCaptcha(nil, store)
|
||||
|
||||
// 验证验证码
|
||||
isValid := captcha.Verify(id, answer, true)
|
||||
if !isValid {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 一些计算
|
||||
|
||||
// ComputeIndividualIncomeTax 计算个人所得税
|
||||
func ComputeIndividualIncomeTax(income float64) float64 {
|
||||
if income <= 800 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if income <= 4000 {
|
||||
income = income - 800
|
||||
}
|
||||
|
||||
// 实际纳税金额
|
||||
if income > 4000 {
|
||||
income = income * 0.8
|
||||
}
|
||||
|
||||
// 税率、速算扣除数
|
||||
var taxRate, quickDeduction float64
|
||||
|
||||
if income <= 20000 {
|
||||
taxRate = 0.2
|
||||
quickDeduction = 0
|
||||
} else if income <= 50000 {
|
||||
taxRate = 0.3
|
||||
quickDeduction = 2000
|
||||
} else {
|
||||
taxRate = 0.4
|
||||
quickDeduction = 7000
|
||||
}
|
||||
|
||||
incomeTax := income*taxRate - quickDeduction
|
||||
|
||||
return incomeTax
|
||||
}
|
||||
|
||||
// CalculateAge 计算年龄
|
||||
func CalculateAge(birthdate string) (int, error) {
|
||||
// 解析出生日期字符串
|
||||
layout := "2006-01-02"
|
||||
birthTime, err := time.Parse(layout, birthdate)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 获取当前时间
|
||||
now := time.Now()
|
||||
|
||||
// 计算年龄
|
||||
years := now.Year() - birthTime.Year()
|
||||
|
||||
// 如果今年的生日还没到,年龄减一
|
||||
if now.Month() < birthTime.Month() || (now.Month() == birthTime.Month() && now.Day() < birthTime.Day()) {
|
||||
years--
|
||||
}
|
||||
|
||||
return years, nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// PathExists 文件是否存在
|
||||
func PathExists(path string) (bool, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err == nil {
|
||||
if fi.IsDir() {
|
||||
return true, nil
|
||||
}
|
||||
return false, errors.New("存在同名文件")
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
+298
@@ -0,0 +1,298 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// func Export(widths []int) (bool, error) {
|
||||
// f := excelize.NewFile()
|
||||
// defer func() {
|
||||
// _ = f.Close()
|
||||
// }()
|
||||
//
|
||||
// // 创建一个工作表
|
||||
// index, err := f.NewSheet("Sheet1")
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// // 设置工作簿的默认工作表
|
||||
// f.SetActiveSheet(index)
|
||||
//
|
||||
// // 单元格对齐样式
|
||||
// alignment := &excelize.Alignment{
|
||||
// Horizontal: "center",
|
||||
// Vertical: "center",
|
||||
// }
|
||||
//
|
||||
// // 单元格颜色填充样式
|
||||
// fill := excelize.Fill{
|
||||
// Type: "pattern",
|
||||
// Pattern: 1,
|
||||
// Color: []string{"#c9daf8"},
|
||||
// Shading: 0,
|
||||
// }
|
||||
//
|
||||
// // 第一行的左、右、下边框
|
||||
// border := []excelize.Border{
|
||||
// {
|
||||
// Type: "left,right,bottom",
|
||||
// Color: "",
|
||||
// Style: 1,
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // 工作表样式
|
||||
// style, err := f.NewStyle(
|
||||
// &excelize.Style{
|
||||
// Fill: fill,
|
||||
// Alignment: alignment,
|
||||
// Border: border,
|
||||
// },
|
||||
// )
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// // 依次设置每一列的列宽
|
||||
// widths = []int{18, 18, 18, 18, 18, 20, 23, 46, 18, 30, 30, 18, 18, 30, 18, 30}
|
||||
// for col, width := range widths {
|
||||
// // 获取列名
|
||||
// colName, err := excelize.ColumnNumberToName(col + 1)
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// // 设置列宽
|
||||
// err = f.SetColWidth("Sheet1", colName, colName, float64(width))
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// // 设置列背景颜色
|
||||
// err = f.SetCellStyle("Sheet1", colName+"1", colName+"1", style)
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 设置行高
|
||||
// err = f.SetRowStyle("Sheet1", 1, 10, style)
|
||||
// if err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// if err := f.SaveAs("output.xlsx"); err != nil {
|
||||
// return false, err
|
||||
// }
|
||||
//
|
||||
// return true, nil
|
||||
// }
|
||||
|
||||
// HeaderCellData 表头内容
|
||||
type HeaderCellData struct {
|
||||
Value string // 值
|
||||
CellType string // 类型
|
||||
NumberFmt string // 格式化方式
|
||||
ColWidth int // 列宽
|
||||
}
|
||||
|
||||
func Export(header []HeaderCellData, data []interface{}) (*bytes.Buffer, error) {
|
||||
sheetName := "Sheet1"
|
||||
|
||||
f := excelize.NewFile()
|
||||
defer func() {
|
||||
_ = f.Close()
|
||||
}()
|
||||
|
||||
// 创建一个工作表
|
||||
index, err := f.NewSheet(sheetName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置工作簿的默认工作表
|
||||
f.SetActiveSheet(index)
|
||||
|
||||
// 设置工作表默认字体
|
||||
err = f.SetDefaultFont("宋体")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 统一单元格对齐样式
|
||||
alignment := &excelize.Alignment{
|
||||
Horizontal: "center",
|
||||
Vertical: "center",
|
||||
}
|
||||
|
||||
// 设置行高 35-第一行
|
||||
err = f.SetRowHeight(sheetName, 1, 35)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 处理工作表表头
|
||||
for c, cell := range header {
|
||||
// 获取列名
|
||||
colName, err := excelize.ColumnNumberToName(c + 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 添加单元格的值
|
||||
err = f.SetCellValue(sheetName, colName+"1", cell.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 单元格颜色填充样式
|
||||
fill := excelize.Fill{
|
||||
Type: "pattern",
|
||||
Pattern: 1,
|
||||
Color: []string{"#c9daf8"},
|
||||
Shading: 0,
|
||||
}
|
||||
|
||||
// 第一行的左、右、下边框
|
||||
border := []excelize.Border{
|
||||
{
|
||||
Type: "left",
|
||||
Color: "#000000",
|
||||
Style: 1,
|
||||
},
|
||||
{
|
||||
Type: "right",
|
||||
Color: "#000000",
|
||||
Style: 1,
|
||||
},
|
||||
{
|
||||
Type: "bottom",
|
||||
Color: "#000000",
|
||||
Style: 1,
|
||||
},
|
||||
}
|
||||
|
||||
// 设置单元格值类型和格式
|
||||
style, _ := f.NewStyle(&excelize.Style{
|
||||
Alignment: alignment, // 字体居中
|
||||
Fill: fill, // 背景颜色
|
||||
Border: border, // 边框
|
||||
})
|
||||
err = f.SetCellStyle(sheetName, colName+"1", colName+"1", style)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置列宽
|
||||
err = f.SetColWidth(sheetName, colName, colName, float64(cell.ColWidth))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 设置单元格格式
|
||||
row := len(data)
|
||||
for i, cell := range header {
|
||||
// 获取列名
|
||||
colName, err := excelize.ColumnNumberToName(i + 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 字体居中
|
||||
style := &excelize.Style{}
|
||||
style = &excelize.Style{
|
||||
Alignment: alignment,
|
||||
}
|
||||
|
||||
if cell.CellType == "float" {
|
||||
style.NumFmt = 2
|
||||
customNumFmt := "0.000"
|
||||
style.CustomNumFmt = &customNumFmt
|
||||
}
|
||||
|
||||
if cell.CellType == "date" {
|
||||
style.NumFmt = 22
|
||||
customNumFmt := "yyyy-mm-dd hh:mm:ss"
|
||||
style.CustomNumFmt = &customNumFmt
|
||||
}
|
||||
|
||||
newStyle, _ := f.NewStyle(style)
|
||||
err = f.SetCellStyle(sheetName, colName+"2", colName+strconv.Itoa(row), newStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 填充数据
|
||||
for r, rowData := range data {
|
||||
rv := reflect.ValueOf(rowData)
|
||||
for c := 0; c < rv.NumField(); c++ {
|
||||
cellValue := rv.Field(c).Interface()
|
||||
// 获取列名
|
||||
colName, err := excelize.ColumnNumberToName(c + 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
axis := colName + fmt.Sprintf("%d", r+2)
|
||||
|
||||
// 设置单元格值
|
||||
err = f.SetCellValue(sheetName, axis, cellValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置单元格值类型
|
||||
cellType := header[c].CellType
|
||||
|
||||
// 字体居中
|
||||
style := &excelize.Style{}
|
||||
style = &excelize.Style{
|
||||
Alignment: alignment,
|
||||
}
|
||||
|
||||
if cellType == "float" {
|
||||
style.NumFmt = 2
|
||||
customNumFmt := "0.000"
|
||||
style.CustomNumFmt = &customNumFmt
|
||||
}
|
||||
|
||||
if cellType == "date" {
|
||||
style.NumFmt = 22
|
||||
customNumFmt := "yyyy-mm-dd hh:mm:ss"
|
||||
style.CustomNumFmt = &customNumFmt
|
||||
}
|
||||
|
||||
newStyle, _ := f.NewStyle(style)
|
||||
err = f.SetCellStyle(sheetName, axis, axis, newStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 设置行高 35-第一行
|
||||
err = f.SetRowHeight(sheetName, r+2, 35)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer, err := f.WriteToBuffer()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buffer, nil
|
||||
|
||||
// 保存文件
|
||||
// if err := f.SaveAs("output.xlsx"); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return nil, errors.New("已导出文件")
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
// Package utils 身份证处理
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// GetCardAge 获取身份证年龄
|
||||
func GetCardAge(cardNum string) (int, error) {
|
||||
// 获取当前时间
|
||||
now := time.Now()
|
||||
|
||||
// 解析身份证号中的出生日期
|
||||
birthDateStr := cardNum[6:14]
|
||||
birthYear, err := strconv.Atoi(birthDateStr[0:4])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
birthMonth, err := strconv.Atoi(birthDateStr[4:6])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 计算年龄
|
||||
age := now.Year() - birthYear
|
||||
if now.Month() < time.Month(birthMonth) {
|
||||
age--
|
||||
}
|
||||
|
||||
return age, nil
|
||||
}
|
||||
|
||||
// CheckCardNum 检测身份证号
|
||||
func CheckCardNum(cardNum string) (bool, error) {
|
||||
fmt.Println(cardNum)
|
||||
regex := `^(?:1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5])\d{4}(?:1[89]|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dxX]$`
|
||||
match, err := regexp.MatchString(regex, cardNum)
|
||||
fmt.Println(match)
|
||||
if !match || err != nil {
|
||||
return false, errors.New("身份证号错误")
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetCardSex 获取身份证性别
|
||||
func GetCardSex(cardNum string) (int, error) {
|
||||
genderStr := cardNum[len(cardNum)-2 : len(cardNum)-1]
|
||||
genderNum, err := strconv.Atoi(genderStr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 判断性别
|
||||
if genderNum%2 == 0 {
|
||||
return 2, nil
|
||||
} else {
|
||||
return 1, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetMaskCardNum 身份证号码脱敏
|
||||
func GetMaskCardNum(cardNum string) string {
|
||||
if len(cardNum) != 18 {
|
||||
return cardNum
|
||||
}
|
||||
|
||||
// 获取身份证号前后部分
|
||||
frontPart := cardNum[0:6]
|
||||
backPart := cardNum[14:]
|
||||
|
||||
// 替换中间部分数字为 *
|
||||
middlePart := "****"
|
||||
|
||||
// 拼接新的身份证号
|
||||
maskedIDCard := frontPart + middlePart + backPart
|
||||
|
||||
return maskedIDCard
|
||||
}
|
||||
|
||||
// GetMaskCardName 身份证名字脱敏
|
||||
func GetMaskCardName(cardName string) string {
|
||||
// 判断姓名长度
|
||||
length := utf8.RuneCountInString(cardName)
|
||||
|
||||
// 判断是否是英文姓名
|
||||
isEnglish := strings.ContainsAny(cardName, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
if length == 2 {
|
||||
// 两个字符的姓名
|
||||
if isEnglish {
|
||||
// 英文姓名
|
||||
return string(cardName[0]) + "*"
|
||||
} else {
|
||||
// 中文姓名
|
||||
return string([]rune(cardName)[0]) + "*"
|
||||
}
|
||||
} else if length == 3 {
|
||||
// 三个字符的姓名
|
||||
if isEnglish {
|
||||
// 英文姓名
|
||||
return string(cardName[0]) + "*" + string(cardName[2])
|
||||
} else {
|
||||
// 中文姓名
|
||||
return string([]rune(cardName)[0]) + "*" + string([]rune(cardName)[2])
|
||||
}
|
||||
} else if length >= 4 {
|
||||
// 四个及以上字符的姓名
|
||||
if isEnglish {
|
||||
// 英文姓名
|
||||
return string(cardName[0]) + "*" + string(cardName[length-1])
|
||||
} else {
|
||||
// 中文姓名
|
||||
return string([]rune(cardName)[0]) + "*" + string([]rune(cardName)[length-1])
|
||||
}
|
||||
}
|
||||
|
||||
return cardName
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package utils
|
||||
|
||||
// OrderCancelReasonToString 订单取消原因(1:主动取消 2:后台取消 3:支付超时取消)
|
||||
func OrderCancelReasonToString(i int) string {
|
||||
switch i {
|
||||
case 1:
|
||||
return "主动取消"
|
||||
case 2:
|
||||
return "后台取消"
|
||||
case 3:
|
||||
return "支付超时取消"
|
||||
default:
|
||||
return "取消"
|
||||
}
|
||||
}
|
||||
|
||||
// OrderSingleStatusToString 订单状态(1:待支付 2:已完成 3:已取消)
|
||||
func OrderSingleStatusToString(i int) string {
|
||||
switch i {
|
||||
case 1:
|
||||
return "待支付"
|
||||
case 2:
|
||||
return "已完成"
|
||||
case 3:
|
||||
return "已取消"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
|
||||
// OrderSingleRefundStatusToString 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款)
|
||||
func OrderSingleRefundStatusToString(i int) string {
|
||||
switch i {
|
||||
case 0:
|
||||
return "无退款"
|
||||
case 1:
|
||||
return "申请退款"
|
||||
case 2:
|
||||
return "退款中"
|
||||
case 3:
|
||||
return "退款成功"
|
||||
case 4:
|
||||
return "拒绝退款"
|
||||
case 5:
|
||||
return "退款关闭"
|
||||
case 6:
|
||||
return "退款异常"
|
||||
case 7:
|
||||
return "部分退款"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
|
||||
// OrderSinglePayStatusToString 订单支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款)
|
||||
func OrderSinglePayStatusToString(i int) string {
|
||||
switch i {
|
||||
case 1:
|
||||
return "未支付"
|
||||
case 2:
|
||||
return "已支付"
|
||||
case 3:
|
||||
return "支付中"
|
||||
case 4:
|
||||
return "支付失败"
|
||||
case 5:
|
||||
return "支付超时"
|
||||
case 6:
|
||||
return "支付关闭"
|
||||
case 7:
|
||||
return "已撤销"
|
||||
case 8:
|
||||
return "转入退款"
|
||||
default:
|
||||
return "未知"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"time"
|
||||
"vote-admin-api/config"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
UserId string `json:"user_id"` // 用户id
|
||||
jwt.RegisteredClaims // v5版本新加的方法
|
||||
}
|
||||
|
||||
// NewJWT GenerateJWT 生成JWT
|
||||
func (t Token) NewJWT() (string, error) {
|
||||
ttl := time.Duration(config.C.Jwt.Ttl)
|
||||
|
||||
t.RegisteredClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(ttl * time.Hour)) // 过期时间24小时
|
||||
t.RegisteredClaims.IssuedAt = jwt.NewNumericDate(time.Now()) // 签发时间
|
||||
t.RegisteredClaims.NotBefore = jwt.NewNumericDate(time.Now()) // 生效时间
|
||||
|
||||
// 使用HS256签名算法
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, t)
|
||||
s, err := token.SignedString([]byte(config.C.Jwt.SignKey))
|
||||
|
||||
return s, err
|
||||
}
|
||||
|
||||
// ParseJwt 解析JWT
|
||||
func ParseJwt(authorization string) (*Token, error) {
|
||||
t, err := jwt.ParseWithClaims(authorization, &Token{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(config.C.Jwt.SignKey), nil
|
||||
})
|
||||
|
||||
if claims, ok := t.Claims.(*Token); ok && t.Valid {
|
||||
return claims, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"vote-admin-api/global"
|
||||
)
|
||||
|
||||
func LogJsonInfo(msg string, v interface{}) {
|
||||
jsonData, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
fmt.Println("Error marshaling struct to JSON:", err)
|
||||
return
|
||||
}
|
||||
|
||||
jsonString := string(jsonData)
|
||||
|
||||
global.Logger.WithFields(logrus.Fields{
|
||||
"data": jsonString,
|
||||
}).Info(msg)
|
||||
}
|
||||
|
||||
func LogJsonErr(msg string, v interface{}) {
|
||||
global.Logger.WithFields(logrus.Fields{
|
||||
"data": v,
|
||||
}).Errorf(msg)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// MaskNameStr 用户名掩码
|
||||
// maskType 加密类型(1:三个字符或三个字符以上掐头取尾,中间用*代替 首字母保留,后两位用*代替)
|
||||
func MaskNameStr(str string, maskType int) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
|
||||
// 使用正则表达式判断是否包含中文字符
|
||||
chinesePattern := "[\u4e00-\u9fa5]+"
|
||||
isChinese, _ := regexp.MatchString(chinesePattern, str)
|
||||
|
||||
// 使用正则表达式判断是否包含英文字母
|
||||
englishPattern := "[A-Za-z]+"
|
||||
isEnglish, _ := regexp.MatchString(englishPattern, str)
|
||||
|
||||
// 判断是否包含中文字符
|
||||
if isChinese {
|
||||
// 按照中文字符计算长度
|
||||
strLen := utf8.RuneCountInString(str)
|
||||
|
||||
if strLen >= 3 {
|
||||
if maskType == 1 {
|
||||
// 三个字符或三个字符以上掐头取尾,中间用*代替
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
lastChar, _ := utf8.DecodeLastRuneInString(str)
|
||||
str = string(firstChar) + "*" + string(lastChar)
|
||||
} else {
|
||||
// 首字母保留,后两位用*代替
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
str = string(firstChar) + "**"
|
||||
}
|
||||
} else if strLen == 2 {
|
||||
// 两个字符
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
str = string(firstChar) + "*"
|
||||
}
|
||||
} else if isEnglish {
|
||||
// 按照英文字串计算长度
|
||||
strLen := utf8.RuneCountInString(str)
|
||||
|
||||
if strLen >= 3 {
|
||||
if maskType == 1 {
|
||||
// 三个字符或三个字符以上掐头取尾,中间用*代替
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
lastChar, _ := utf8.DecodeLastRuneInString(str)
|
||||
str = string(firstChar) + "*" + string(lastChar)
|
||||
} else {
|
||||
// 首字母保留,后两位用*代替
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
str = string(firstChar) + "**"
|
||||
}
|
||||
} else if strLen == 2 {
|
||||
// 两个字符
|
||||
firstChar, _ := utf8.DecodeRuneInString(str)
|
||||
str = string(firstChar) + "*"
|
||||
}
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
// MaskPhoneStr 手机号、固话加密
|
||||
// 固话:0510-89754815 0510-8****815
|
||||
// 手机号:18221234158 18*******58
|
||||
func MaskPhoneStr(phone string) string {
|
||||
if phone == "" {
|
||||
return phone
|
||||
}
|
||||
|
||||
// 使用正则表达式匹配固定电话
|
||||
phonePattern := `(0[0-9]{2,3}[\-]?[2-9][0-9]{6,7}[\-]?[0-9]?)`
|
||||
isFixedLine := regexp.MustCompile(phonePattern).MatchString(phone)
|
||||
|
||||
if isFixedLine {
|
||||
// 匹配到固定电话
|
||||
// 替换匹配的部分为固定格式
|
||||
return regexp.MustCompile(`(0[0-9]{2,3}[\-]?[2-9])[0-9]{3,4}([0-9]{3}[\-]?[0-9]?)`).ReplaceAllString(phone, "$1****$2")
|
||||
} else {
|
||||
// 匹配到手机号
|
||||
// 替换匹配的部分为固定格式
|
||||
return regexp.MustCompile(`(1[0-9]{1})[0-9]{7}([0-9]{2})`).ReplaceAllString(phone, "$1*******$2")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package utils
|
||||
|
||||
import "regexp"
|
||||
|
||||
// RegexpMobile 手机号匹配
|
||||
func RegexpMobile(mobile string) bool {
|
||||
ok, err := regexp.MatchString(`^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$`, mobile)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return ok
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"vote-admin-api/config"
|
||||
)
|
||||
|
||||
// RemoveOssDomain 去除oss地址中的前缀
|
||||
func RemoveOssDomain(url string) string {
|
||||
if url != "" {
|
||||
url = strings.Replace(url, config.C.Oss.OssCustomDomainName, "", 1)
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// AddOssDomain 增加oss地址中的前缀
|
||||
func AddOssDomain(url string) string {
|
||||
if url == "" {
|
||||
return ""
|
||||
}
|
||||
return config.C.Oss.OssCustomDomainName + url
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// StrToFloat32 字符串转float32
|
||||
func StrToFloat32(s string) (f *float32, err error) {
|
||||
f64, err := strconv.ParseFloat(s, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 将float64转换为float32
|
||||
f32 := float32(f64)
|
||||
|
||||
return &f32, nil
|
||||
}
|
||||
|
||||
// StrToFloat64 字符串转float64
|
||||
func StrToFloat64(s string) (f *float64, err error) {
|
||||
f64, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &f64, nil
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
"vote-admin-api/api/model"
|
||||
)
|
||||
|
||||
// StrToLocalTime 字符串时间转localtime
|
||||
func StrToLocalTime(s string) (*model.LocalTime, error) {
|
||||
// 获取本地时区
|
||||
location, err := time.LoadLocation("Local")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeParse, err := time.ParseInLocation("2006-01-02 15:04:05", s, location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t := model.LocalTime(timeParse)
|
||||
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// TimeToAgoString 根据给定的时间返回一个描述性的字符串
|
||||
func TimeToAgoString(t time.Time) string {
|
||||
now := time.Now()
|
||||
diffTime := now.Sub(t)
|
||||
|
||||
switch {
|
||||
case diffTime < time.Minute:
|
||||
return "1分钟前"
|
||||
case diffTime < time.Hour:
|
||||
minutes := int(diffTime.Minutes())
|
||||
return fmt.Sprintf("%d分钟前", minutes)
|
||||
case diffTime < 24*time.Hour:
|
||||
return "一小时前"
|
||||
case diffTime < 48*time.Hour:
|
||||
return "两天前"
|
||||
case diffTime < 72*time.Hour:
|
||||
return "三天前"
|
||||
case diffTime < 10*time.Hour*24:
|
||||
days := int(diffTime.Hours()) / 24
|
||||
return fmt.Sprintf("%d天前", days)
|
||||
default:
|
||||
return "十天前"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/go-playground/validator/v10"
|
||||
"vote-admin-api/global"
|
||||
)
|
||||
|
||||
// Translate 检验并返回检验错误信息
|
||||
func Translate(err error) (errMsg string) {
|
||||
var errs validator.ValidationErrors
|
||||
errors.As(err, &errs)
|
||||
for _, err := range errs {
|
||||
errMsg = err.Translate(global.Trans)
|
||||
}
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user