248 lines
4.9 KiB
Go
248 lines
4.9 KiB
Go
package pkg
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"math/rand/v2"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
"reflect"
|
||
"time"
|
||
|
||
"github.com/go-viper/mapstructure/v2"
|
||
"github.com/google/uuid"
|
||
)
|
||
|
||
func GetModuleDir() (string, error) {
|
||
dir, err := os.Getwd()
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
for {
|
||
modPath := filepath.Join(dir, "go.mod")
|
||
if _, err := os.Stat(modPath); err == nil {
|
||
return dir, nil // 找到 go.mod
|
||
}
|
||
|
||
// 向上查找父目录
|
||
parent := filepath.Dir(dir)
|
||
if parent == dir {
|
||
break // 到达根目录,未找到
|
||
}
|
||
dir = parent
|
||
}
|
||
|
||
return "", fmt.Errorf("go.mod not found in current directory or parents")
|
||
}
|
||
|
||
// GetCacheDir 用于获取缓存目录路径
|
||
// 如果缓存目录不存在,则会自动创建
|
||
// 返回值:
|
||
// - string: 缓存目录的路径
|
||
// - error: 如果获取模块目录失败或创建缓存目录失败,则返回错误信息
|
||
func GetCacheDir() (string, error) {
|
||
// 获取模块目录
|
||
modDir, err := GetModuleDir()
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
// 拼接缓存目录路径
|
||
path := fmt.Sprintf("%s/cache", modDir)
|
||
// 创建目录(包括所有必要的父目录),权限设置为0755
|
||
err = os.MkdirAll(path, 0755)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建目录失败: %w", err)
|
||
}
|
||
// 返回成功创建的缓存目录路径
|
||
return path, nil
|
||
}
|
||
|
||
func GetTmplDir() (string, error) {
|
||
modDir, err := GetModuleDir()
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
path := fmt.Sprintf("%s/tmpl", modDir)
|
||
err = os.MkdirAll(path, 0755)
|
||
if err != nil {
|
||
return "", fmt.Errorf("创建目录失败: %w", err)
|
||
}
|
||
return path, nil
|
||
}
|
||
|
||
func ReverseSliceNew[T any](s []T) []T {
|
||
result := make([]T, len(s))
|
||
for i := 0; i < len(s); i++ {
|
||
result[i] = s[len(s)-1-i]
|
||
}
|
||
return result
|
||
}
|
||
|
||
func JsonStringIgonErr(data interface{}) string {
|
||
return string(JsonByteIgonErr(data))
|
||
}
|
||
|
||
func JsonByteIgonErr(data interface{}) []byte {
|
||
dataByte, _ := json.Marshal(data)
|
||
return dataByte
|
||
}
|
||
|
||
func IntersectionGeneric[T comparable](slice1, slice2 []T) []T {
|
||
m := make(map[T]bool)
|
||
result := []T{}
|
||
|
||
for _, v := range slice1 {
|
||
m[v] = true
|
||
}
|
||
|
||
for _, v := range slice2 {
|
||
if m[v] {
|
||
result = append(result, v)
|
||
delete(m, v) // 避免重复
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
|
||
func CreateOrderNum(prefix string) string {
|
||
code := fmt.Sprintf("%04d", rand.IntN(10000))
|
||
fmt.Println("4位随机数字:", code) // 输出示例: "0837"
|
||
return prefix + time.Now().Format("20060102150405") + code
|
||
}
|
||
|
||
func BuildUpdateMap(obj interface{}, omitFields ...string) map[string]interface{} {
|
||
result := make(map[string]interface{})
|
||
omitMap := make(map[string]bool)
|
||
for _, f := range omitFields {
|
||
omitMap[f] = true
|
||
}
|
||
|
||
v := reflect.ValueOf(obj)
|
||
if v.Kind() == reflect.Ptr {
|
||
v = v.Elem()
|
||
}
|
||
t := v.Type()
|
||
|
||
for i := 0; i < v.NumField(); i++ {
|
||
field := v.Field(i)
|
||
fieldName := t.Field(i).Name
|
||
|
||
if omitMap[fieldName] {
|
||
continue
|
||
}
|
||
|
||
// 只处理非 nil 的指针字段
|
||
if field.Kind() == reflect.Ptr && !field.IsNil() {
|
||
// 将驼峰转为下划线(可选的,根据你的数据库列名决定)
|
||
colName := CamelToSnake(fieldName)
|
||
result[colName] = field.Elem().Interface()
|
||
}
|
||
}
|
||
return result
|
||
}
|
||
|
||
func CamelToSnake(s string) string {
|
||
var result []rune
|
||
for i, r := range s {
|
||
if i > 0 && r >= 'A' && r <= 'Z' {
|
||
result = append(result, '_')
|
||
}
|
||
result = append(result, r)
|
||
}
|
||
return string(result)
|
||
}
|
||
|
||
func CopyNonNilFields(src, dst interface{}) error {
|
||
config := &mapstructure.DecoderConfig{
|
||
Result: dst,
|
||
TagName: "json",
|
||
ZeroFields: false, // 重要:不清零目标字段
|
||
Squash: false,
|
||
}
|
||
|
||
decoder, err := mapstructure.NewDecoder(config)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return decoder.Decode(src)
|
||
}
|
||
|
||
func DownloadFile(url string, saveDir string, filename string) (string, error) {
|
||
os.MkdirAll(saveDir, 0755)
|
||
|
||
if filename == "" {
|
||
filename = uuid.New().String() + ".docx"
|
||
}
|
||
|
||
filePath := filepath.Join(saveDir, filename)
|
||
|
||
resp, err := http.Get(url)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
out, err := os.Create(filePath)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer out.Close()
|
||
|
||
_, err = io.Copy(out, resp.Body)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
absPath, _ := filepath.Abs(filePath)
|
||
return absPath, nil
|
||
}
|
||
|
||
func DownloadImage(url string, requestID string, dir string) (string, error) {
|
||
os.MkdirAll(dir, 0755)
|
||
|
||
ext := filepath.Ext(url)
|
||
if ext == "" {
|
||
ext = ".jpg"
|
||
}
|
||
filename := requestID + "_" + uuid.New().String() + ext
|
||
filePath := filepath.Join(dir, filename)
|
||
|
||
resp, err := http.Get(url)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
out, err := os.Create(filePath)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
defer out.Close()
|
||
|
||
_, err = io.Copy(out, resp.Body)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
|
||
return filepath.Abs(filePath)
|
||
}
|
||
|
||
func DeleteFile(path string) {
|
||
if path != "" {
|
||
os.Remove(path)
|
||
}
|
||
}
|
||
|
||
func GenerateUUID() string {
|
||
return uuid.New().String()
|
||
}
|
||
|
||
func GenerateUserIndex() string {
|
||
return uuid.New().String()[:20]
|
||
}
|