You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
10 KiB
421 lines
10 KiB
package common
|
|
|
|
import (
|
|
"base/app/config"
|
|
"base/app/constant"
|
|
"bytes"
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"git.oa00.com/go/mysql"
|
|
"git.oa00.com/go/redis"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/shopspring/decimal"
|
|
"golang.org/x/text/encoding/simplifiedchinese"
|
|
"golang.org/x/text/transform"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"math"
|
|
"math/rand"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// @Title 随机数种子
|
|
func init() {
|
|
// 随机数种子
|
|
rand.Seed(time.Now().UnixNano())
|
|
}
|
|
|
|
// @Title md5加密
|
|
func MD5(str string) string {
|
|
h := md5.New()
|
|
h.Write([]byte(str))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
// MD5Byte @Title md5加密
|
|
func MD5Byte(str []byte) string {
|
|
h := md5.New()
|
|
h.Write(str)
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
// @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
|
|
}
|
|
|
|
// @Title 处理验证错误消息
|
|
func GetVerErr(err error) string {
|
|
er, ok := err.(validator.ValidationErrors)
|
|
if ok {
|
|
field := er[0].Field()
|
|
if field == er[0].StructField() {
|
|
field = strings.ToLower(field[0:1]) + field[1:]
|
|
}
|
|
switch er[0].Tag() {
|
|
case "required":
|
|
return field + "不能为空"
|
|
case "min":
|
|
if er[0].Type().String() == "string" {
|
|
return field + "不能小于" + er[0].Param() + "位"
|
|
}
|
|
return field + "不能小于" + er[0].Param()
|
|
}
|
|
return field + "错误"
|
|
} else {
|
|
return "参数格式错误"
|
|
}
|
|
}
|
|
|
|
// @Title 是否在数组中
|
|
func InArray(need interface{}, data interface{}) bool {
|
|
if datas, ok := data.([]int); ok {
|
|
for _, item := range datas {
|
|
if item == need {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
if datas, ok := data.([]uint); ok {
|
|
for _, item := range datas {
|
|
if item == need {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
if datas, ok := data.([]string); ok {
|
|
for _, item := range datas {
|
|
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
|
|
}
|
|
|
|
// @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
|
|
}
|
|
|
|
// @Title utf8转gbk
|
|
func Utf8ToGbk(source string) string {
|
|
result, _, _ := transform.String(simplifiedchinese.GBK.NewEncoder(), source)
|
|
return result
|
|
}
|
|
|
|
// @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))
|
|
}
|
|
|
|
// GetDeviceType @Title 获取设备类型
|
|
func GetDeviceType(c *gin.Context) uint {
|
|
switch strings.ToLower(c.GetHeader("Device-Type")) {
|
|
default:
|
|
return constant.DeviceTypeWeb
|
|
}
|
|
}
|
|
|
|
// FindParents @Title 查询所有上级
|
|
func FindParents(tableName, id, parentId string, findId uint, result interface{}) {
|
|
mysql.Db.Raw(fmt.Sprintf(`SELECT T2.*
|
|
FROM (
|
|
SELECT
|
|
@r AS _id,
|
|
(SELECT @r := %s FROM %s WHERE %s = _id)
|
|
FROM
|
|
(SELECT @r := ?) vars,
|
|
%s h
|
|
WHERE @r <> 0) T1
|
|
JOIN %s T2
|
|
ON T1._id = T2.%s`, parentId, tableName, id, tableName, tableName, id), findId).Scan(result)
|
|
return
|
|
}
|
|
|
|
// GenNo @Title 生成编号
|
|
func GenNo(NoPrefix string) (string, error) {
|
|
date := time.Now().Format("20060102")
|
|
redisKey := fmt.Sprintf("gen:%s:%s", NoPrefix, date)
|
|
result, err := redis.Redis.Incr(redisKey).Result()
|
|
if err != nil {
|
|
return "", errors.New("生成失败")
|
|
}
|
|
redis.Redis.Expire(redisKey, time.Hour*24)
|
|
if result > 9999 {
|
|
return "", errors.New("生成失败")
|
|
}
|
|
if !config.IsProd() {
|
|
date += "test"
|
|
}
|
|
return fmt.Sprintf("%s%s%.4d", NoPrefix, date, result), nil
|
|
}
|
|
|
|
// GenNo6 @Title 生成六位编号
|
|
func GenNo6(number uint) (result string, err error) {
|
|
s := "000000"
|
|
sn := strconv.Itoa(int(number))
|
|
if len(sn) > 6 {
|
|
return result, errors.New("车辆编号溢出六位限制")
|
|
}
|
|
result = s[0:(len(s)-len(sn))] + sn
|
|
return
|
|
}
|
|
|
|
// GetRequestBody @Title 获取请求数据
|
|
func GetRequestBody(request *http.Request) ([]byte, error) {
|
|
body, err := ioutil.ReadAll(request.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read request body err: %v", err)
|
|
}
|
|
|
|
_ = request.Body.Close()
|
|
request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
|
|
|
return body, nil
|
|
}
|
|
|
|
// Ternary @Title 三元运算
|
|
func Ternary(condition bool, resultA, resultB interface{}) interface{} {
|
|
if condition {
|
|
return resultA
|
|
}
|
|
return resultB
|
|
}
|
|
func UintTernary(condition bool, resultA, resultB uint) uint {
|
|
if condition {
|
|
return resultA
|
|
}
|
|
return resultB
|
|
}
|
|
func StringTernary(condition bool, resultA, resultB string) string {
|
|
if condition {
|
|
return resultA
|
|
}
|
|
return resultB
|
|
}
|
|
|
|
// IdCardRegexp @Title 身份证验证
|
|
func IdCardRegexp(idCard string) bool {
|
|
|
|
rgx := "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"
|
|
|
|
//身份证号码: 空格也需要表示出来, 直接打空格是不起作用的 \s表示空字符 [\s]任意空字符 ?出现0次或者次
|
|
//([1-6]\d{5})(19\d{2}|20\d{2})(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])(\d{3}[\dxX])
|
|
// ([1-6]\d{5}) 为一组 第一位表示地区 例如 华中 华南等 数字为1-6 [1-6]表示任意一个 \d{5} 数字共5位
|
|
//(19\d{2}|20\d{2}) 为一组 年的前两位要么为19 要么为20 后两位为\d{2}数字出现两次
|
|
//(0[1-9]|1[012]) 为一组 月第一位为0或者为1 为0的时候 后边为[1-9]任意一个数字 为1的时候 后边为[012]任意一个数字
|
|
//(0[1-9]|[12]\d|3[01]) 为一组 日第一位要么为0要么为1或者2或者3 为0的时候第2位[1-9]任意一个数字 第1位为1或者2的时候 第2位为\d任意一个数字相当于[0-9]
|
|
|
|
reg := regexp.MustCompile(rgx)
|
|
result := reg.MatchString(idCard)
|
|
return result
|
|
}
|
|
|
|
// 人民币大写
|
|
func ConvertDecimalToCny(num decimal.Decimal) string {
|
|
f, _ := num.Float64()
|
|
return ConvertNumToCny(f)
|
|
}
|
|
|
|
// 人民币大写
|
|
func ConvertNumToCny(num float64) string {
|
|
strnum := strconv.FormatFloat(num*100, 'f', 0, 64)
|
|
if strnum == "0" {
|
|
return "零"
|
|
}
|
|
sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"}
|
|
// log.Println(sliceUnit[:len(sliceUnit)-2])
|
|
s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)]
|
|
upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"}
|
|
str := ""
|
|
for k, v := range strnum[:] {
|
|
str = str + upperDigitUnit[string(v)] + s[k]
|
|
}
|
|
reg, err := regexp.Compile(`零角零分$`)
|
|
str = reg.ReplaceAllString(str, "整")
|
|
|
|
reg, err = regexp.Compile(`零角`)
|
|
str = reg.ReplaceAllString(str, "零")
|
|
|
|
reg, err = regexp.Compile(`零分$`)
|
|
str = reg.ReplaceAllString(str, "整")
|
|
|
|
reg, err = regexp.Compile(`零[仟佰拾]`)
|
|
str = reg.ReplaceAllString(str, "零")
|
|
|
|
reg, err = regexp.Compile(`零{2,}`)
|
|
str = reg.ReplaceAllString(str, "零")
|
|
|
|
reg, err = regexp.Compile(`零亿`)
|
|
str = reg.ReplaceAllString(str, "亿")
|
|
|
|
reg, err = regexp.Compile(`零万`)
|
|
str = reg.ReplaceAllString(str, "万")
|
|
|
|
reg, err = regexp.Compile(`零*元`)
|
|
str = reg.ReplaceAllString(str, "元")
|
|
|
|
reg, err = regexp.Compile(`亿零{0, 3}万`)
|
|
str = reg.ReplaceAllString(str, "^元")
|
|
|
|
reg, err = regexp.Compile(`零元`)
|
|
str = reg.ReplaceAllString(str, "零")
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
return str
|
|
}
|
|
|
|
// 截取字符串
|
|
func SliceStr(str string, index int) string {
|
|
if math.Abs(float64(index)) > float64(len(str)) {
|
|
return str
|
|
}
|
|
if index < 0 {
|
|
return string([]rune(str)[len([]rune(str))+index:])
|
|
}
|
|
return string([]rune(str)[:index])
|
|
}
|
|
|
|
// TimeFormat
|
|
func TimeFormat(time time.Time, format string) string {
|
|
if time.IsZero() {
|
|
return "/"
|
|
}
|
|
return time.Format(format)
|
|
}
|
|
|
|
//
|
|
//// Thumb 生成缩略图
|
|
//func Thumb(url string, w, h float64) {
|
|
// filename := filepath.Join(config.Config.Upload.Root, url)
|
|
// saveName := filepath.Join(config.Config.Upload.Thumb, url)
|
|
// if FileExists(saveName) {
|
|
// //c.File(saveName)
|
|
// return
|
|
// }
|
|
//
|
|
// //创建新的MagicWand
|
|
// mw := imagick.NewMagickWand()
|
|
// //读取文件
|
|
// err := mw.ReadImage(filename)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
//
|
|
// if w != 0 || h != 0 {
|
|
// err := reset(w, h, mw)
|
|
// if err != nil {
|
|
// //c.File(filename)
|
|
// return
|
|
// }
|
|
// }
|
|
//
|
|
// //改变图片质量
|
|
// err = mw.SetImageCompressionQuality(85)
|
|
// if err != nil {
|
|
// return
|
|
// }
|
|
// //导出图片
|
|
// if err := os.MkdirAll(filepath.Dir(saveName), os.ModePerm); err != nil {
|
|
// return
|
|
// }
|
|
// err = mw.WriteImage(saveName)
|
|
// //c.File(saveName)
|
|
//}
|
|
//
|
|
//func FileExists(name string) bool {
|
|
// if _, err := os.Stat(name); err != nil {
|
|
// if os.IsNotExist(err) {
|
|
// return false
|
|
// }
|
|
// }
|
|
// return true
|
|
//}
|
|
//
|
|
//func reset(w float64, h float64, mw *imagick.MagickWand) error {
|
|
// width := float64(mw.GetImageWidth())
|
|
// height := float64(mw.GetImageHeight())
|
|
// if w >= width || h >= height {
|
|
// return errors.New("can't max")
|
|
// }
|
|
// var newH, newW, crop_x, crop_y float64
|
|
// if w == 0 {
|
|
// newH = h
|
|
// newW = width / (height / h)
|
|
// } else if h == 0 {
|
|
// newW = w
|
|
// newH = height / (width / w)
|
|
// } else {
|
|
// if width/w < height/h {
|
|
// newW = w
|
|
// newH = height / (width / w)
|
|
// crop_x = 0
|
|
// crop_y = (newH - h) / 2
|
|
// } else {
|
|
// newH = h
|
|
// newW = width / (height / h)
|
|
// crop_x = (newW - w) / 2
|
|
// crop_y = 0
|
|
// }
|
|
// }
|
|
// _ = mw.ResizeImage(uint(newW), uint(newH), imagick.FILTER_LANCZOS)
|
|
// if w != 0 && h != 0 {
|
|
// _ = mw.CropImage(uint(w), uint(h), int(crop_x), int(crop_y))
|
|
// }
|
|
// return nil
|
|
//}
|
|
//
|