package common import ( "bytes" "crypto/md5" "encoding/hex" "io" "math/rand" "net/http" "os" "path/filepath" "reflect" "regexp" "strconv" "strings" "time" "github.com/shopspring/decimal" "golang.org/x/text/encoding/simplifiedchinese" "golang.org/x/text/transform" ) // @Title 随机数种子 func init() { // 随机数种子 rand.Seed(time.Now().UnixNano()) } // MD5 @Title md5加密 func MD5(str string) string { h := md5.New() h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } // RandStr @Title 生成随机数 func RandStr(n int, str ...string) string { s := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" if len(str) > 0 { s = str[0] } res := "" for i := 0; i < n; i++ { res += string(s[rand.Intn(len(s))]) } return res } // InArray @Title 是否在数组中 func InArray[T comparable](need T, array []T) bool { for _, item := range array { if item == need { return true } } return false } // CreateDateDir 根据当前日期来创建文件夹 func CreateDateDir(Path string) string { folderName := time.Now().Format("20060102") folderPath := filepath.Join(Path, folderName) if _, err := os.Stat(folderPath); os.IsNotExist(err) { os.MkdirAll(folderPath, 0755) } return folderName } // DownloadFormUrl @Title 下载文件 func DownloadFormUrl(src string, filename string) error { res, err := http.Get(src) if err != nil { return err } defer res.Body.Close() // 获得get请求响应的reader对象 body, err := io.ReadAll(res.Body) if err != nil { return err } out, err := os.Create(filename) if err != nil { return err } if _, err := io.Copy(out, bytes.NewReader(body)); err != nil { return err } return nil } // Utf8ToGbk @Title utf8转gbk func Utf8ToGbk(source string) string { result, _, _ := transform.String(simplifiedchinese.GBK.NewEncoder(), source) return result } // GbkToUtf8 @Title gbk转utf8 func GbkToUtf8(source string) string { result, _, _ := transform.String(simplifiedchinese.GBK.NewDecoder(), source) return result } // GetPassword @Title 密码加密 func GetPassword(password, salt string) string { return MD5(salt + MD5(password+salt)) } // IsPhone @Title 是否手机号 func IsPhone(phone string) bool { return regexp.MustCompile(`^1\d{10}$`).MatchString(phone) } // Equal @TITLE 数据比较 func Equal[T any](a, b T, fun func(a, b T) bool) bool { return fun(a, b) } // Ptr @TITLE 返回指针 func Ptr[T any](data T) *T { return &data } // Split @TITLE 字符串分隔 func Split(s, sep string) []string { if s == "" { return nil } return strings.Split(s, sep) } // PtrData @TITLE 指针数据 func PtrData[T any](data *T) T { if data != nil { return *data } return *new(T) } // PtrDecimal @TITLE Decimal比较数据 func PtrDecimal(a *decimal.Decimal, b *decimal.Decimal) bool { if a == b { return true } if a == nil || b == nil { return false } return a.Cmp(*b) == 0 } // PtrCmp @TITLE 客户比较数据引用比较 func PtrCmp[T comparable](a *T, b *T) bool { if a == b { return true } if a == nil || b == nil { return false } return *a == *b } // DefaultData @TITLE 反射创建默认值 func DefaultData(data any) any { var value reflect.Value if reflect.TypeOf(data).Kind() != reflect.Ptr { value = reflect.ValueOf(&data).Elem() } else { value = reflect.ValueOf(data).Elem() } if value.Kind() == reflect.Interface { value = reflect.New(value.Elem().Type()).Elem() } labels := map[string]string{} typeOf := value.Type() for i := 0; i < typeOf.NumField(); i++ { field := typeOf.Field(i) name := field.Name if field.IsExported() { if !field.Anonymous { labels[name] = field.Tag.Get("label") } else { name = "" } if field.Type.Kind() == reflect.Struct { _, valueLabels := DefaultValue(value.Field(i), name) for valueKey, valueLabel := range valueLabels { labels[valueKey] = valueLabel } } if field.Type.Kind() == reflect.Slice { newValue := reflect.New(field.Type.Elem()).Elem() defaultValue, valueLabels := DefaultValue(newValue, name) for valueKey, valueLabel := range valueLabels { labels[valueKey] = valueLabel } value.Field(i).Set(reflect.Append(value.Field(i), defaultValue)) } } } return map[string]interface{}{ "Data": value.Interface(), "Label": labels, } } func DefaultValue(value reflect.Value, name string) (reflect.Value, map[string]string) { typeOf := value.Type() labels := map[string]string{} if typeOf.Kind() == reflect.Struct { for i := 0; i < typeOf.NumField(); i++ { field := typeOf.Field(i) fieldName := field.Name if field.IsExported() { if !field.Anonymous { labels[strings.Trim(name+"."+fieldName, ".")] = field.Tag.Get("label") } else { fieldName = "" } labels[strings.Trim(name+"."+fieldName, ".")] = field.Tag.Get("label") if field.Type.Kind() == reflect.Struct { _, valueLabels := DefaultValue(value.Field(i), fieldName) for valueKey, valueLabel := range valueLabels { labels[strings.Trim(name+"."+valueKey, ".")] = valueLabel } } if field.Type.Kind() == reflect.Slice { newValue := reflect.New(field.Type.Elem()).Elem() defaultValue, valueLabels := DefaultValue(newValue, fieldName) for valueKey, valueLabel := range valueLabels { labels[strings.Trim(name+"."+valueKey, ".")] = valueLabel } value.Field(i).Set(reflect.Append(value.Field(i), defaultValue)) } } } } return value, labels } func wrapIfStruct[T any](data T) T { v := reflect.ValueOf(data) if v.Kind() == reflect.Struct { ptr := reflect.New(v.Type()) ptr.Elem().Set(v) return ptr.Interface().(T) } return data } func DefaultSlice[T any](data T) T { data = wrapIfStruct(data) value := reflect.ValueOf(data).Elem() typeOf := value.Type() switch typeOf.Kind() { case reflect.Struct: DefaultSliceValue(value) case reflect.Slice: if value.IsNil() { value.Set(reflect.MakeSlice(value.Type(), 0, 0)) } for j := 0; j < value.Len(); j++ { DefaultSliceValue(value.Index(j)) } } if reflect.TypeOf(data).Kind() != reflect.Ptr { return value.Interface().(T) } else { return value.Addr().Interface().(T) } } func DefaultSliceValue(value reflect.Value) reflect.Value { typeOf := value.Type() if typeOf.Kind() == reflect.Struct { for i := 0; i < typeOf.NumField(); i++ { DefaultSliceType(value.Field(i)) } } return value } func DefaultSliceType(value reflect.Value) reflect.Value { switch value.Type().Kind() { case reflect.Ptr: if !value.IsNil() { DefaultSliceType(value.Elem()) } else { valueType := value.Type().Elem() if valueType.Kind() == reflect.Slice { slice := reflect.MakeSlice(valueType, 0, 0) ptr := reflect.New(valueType) ptr.Elem().Set(slice) value.Set(ptr) } } case reflect.Struct: DefaultSliceValue(value) case reflect.Slice: if value.IsNil() { if value.CanSet() { value.Set(reflect.MakeSlice(value.Type(), 0, 0)) } } for j := 0; j < value.Len(); j++ { DefaultSliceValue(value.Index(j)) } } return value } // Unique @Title 去重 func Unique[T comparable](array []T) (result []T) { for _, item := range array { if !InArray(item, result) { result = append(result, item) } } return } // InsertSorted @TITLE array插入排序 func InsertSorted[T any](array []T, value T, comp func(int) bool) []T { i, j := 0, len(array) for i < j { h := int(uint(i+j) >> 1) // avoid overflow when computing h // i ≤ h < j if !comp(h) { i = h + 1 // preserves f(i-1) == false } else { j = h // preserves f(j) == true } } // 插入:保持有序 array = append(array, value) // 增加一个空位 copy(array[i+1:], array[i:]) // 后移 array[i] = value // 插入值 return array } // GetGender @TITLE 获取性别 func GetGender(sex string) string { if InArray(sex, []string{"男", "M"}) { return "SEX01_SYS" } else if InArray(sex, []string{"女", "F"}) { return "SEX02_SYS" } return "" } func IntArrayToString(args []int64) string { var result []string for _, item := range args { result = append(result, strconv.FormatInt(item, 10)) } return strings.Join(result, ",") }