jiangshuai
2023-11-08 61443bcd5245cd0669f0dedc89243994411a7f66
附件上传接口,交互文件服务器,缩略图制作
3个文件已添加
8个文件已修改
519 ■■■■■ 已修改文件
conf/config.go 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.yaml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
constvar/const.go 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/attachment.go 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.mod 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
go.sum 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/attachment.go 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/db.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
router/router.go 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/image/image.go 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/upload/seaweed.go 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
conf/config.go
@@ -23,11 +23,13 @@
type (
    webConf struct {
        Host      string // 本机ip地址
        Port      string // 端口号
        NodeId    string // 主账户用户名
        OssType   string // 对象存储类型
        JWTSecret string
        Host       string // 本机ip地址
        Port       string // 端口号
        NodeId     string // 主账户用户名
        OssType    string // 对象存储类型
        JWTSecret  string
        FileServer string //文件服务器地址
        ServerId   string //服务ID
    }
    localConf struct {
conf/config.yaml
@@ -3,6 +3,9 @@
  host: 192.168.20.119
  nodeId: wangpengfei
  ossType: local
  #  fileServer: http://172.20.11.129:6333
  fileServer: http://192.168.20.189:6333
  serverId: wms
db:
  #  dsn: root:c++java123@tcp(192.168.20.119:3306)/wms?charset=utf8&parseTime=True&loc=Local
  dsn: root:c++java123@tcp(192.168.20.119:3306)/aps_server2?charset=utf8&parseTime=True&loc=Local
constvar/const.go
@@ -199,3 +199,26 @@
    UserTypePrimary                     // 主账户
    UserTypeSub                         // 子账户
)
type FileType string
const (
    FileType_File      FileType = "file"      //文件
    FileType_Picture   FileType = "picture"   //图片
    FileType_Thumbnail FileType = "thumbnail" //缩略图
)
var FileExtMap = map[string]FileType{
    "doc":  FileType_File,
    "docx": FileType_File,
    "xls":  FileType_File,
    "xlsx": FileType_File,
    "txt":  FileType_File,
}
var PicExtMap = map[string]FileType{
    "jpg":  FileType_Picture,
    "jpeg": FileType_Picture,
    "png":  FileType_Picture,
    "svg":  FileType_Picture,
}
controllers/attachment.go
New file
@@ -0,0 +1,108 @@
package controllers
import (
    "bytes"
    "github.com/gin-gonic/gin"
    "io"
    "path"
    "strings"
    "wms/constvar"
    "wms/extend/code"
    "wms/extend/util"
    "wms/models"
    "wms/pkg/logx"
    "wms/utils/image"
    "wms/utils/upload"
)
type AttachmentController struct {
}
// UploadFiles
//
//    @Tags        附件管理
//    @Summary    上传附件
//    @Success    200        {object}    util.Response     "成功"
//    @Router    /api-wms/v1/attachment/uploadFiles [post]
func (slf AttachmentController) UploadFiles(c *gin.Context) {
    form, err := c.MultipartForm()
    if err != nil {
        logx.Errorf("file upload err: %v", err)
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败")
        return
    }
    files := form.File["files"]
    var attachmentList []*models.Attachment
    for _, fileHeader := range files {
        ext := strings.ToLower(path.Ext(fileHeader.Filename))[1:]
        var fileType constvar.FileType
        if value, ok := constvar.FileExtMap[ext]; ok {
            fileType = value
        }
        if value, ok := constvar.PicExtMap[ext]; ok {
            fileType = value
        }
        if fileType == "" {
            logx.Errorf("file upload err: 不支持上传该格式的文件")
            util.ResponseFormat(c, code.RequestParamError, "不支持上传该格式的文件")
            return
        }
        file, err := fileHeader.Open()
        if err != nil {
            logx.Errorf("file upload err: %v", err)
            util.ResponseFormat(c, code.RequestParamError, "错误文件")
            return
        }
        buffer := new(bytes.Buffer)
        _, _ = io.Copy(buffer, file)
        fileBytes := buffer.Bytes()
        fileUrl, err := upload.UploadFileToSeaWeed(string(fileType), ext, fileBytes)
        if err != nil {
            logx.Errorf("file upload err: %v", err)
            util.ResponseFormat(c, code.RequestParamError, err.Error())
            return
        }
        attachment := &models.Attachment{
            FileName: fileHeader.Filename,
            FileUrl:  fileUrl,
            Ext:      ext,
            FileType: fileType,
        }
        attachmentList = append(attachmentList, attachment)
        if fileType == constvar.FileType_Picture {
            thumbnailBytes, err := image.CreateThumbnail(fileBytes, 0, 600, 800)
            if err != nil {
                logx.Errorf("file upload err: %v", err)
                util.ResponseFormat(c, code.RequestParamError, "生成缩略图失败:"+err.Error())
                return
            }
            thumbnailUrl, err := upload.UploadFileToSeaWeed(string(constvar.FileType_Thumbnail), ext, thumbnailBytes)
            if err != nil {
                logx.Errorf("file upload err: %v", err)
                util.ResponseFormat(c, code.RequestParamError, err.Error())
                return
            }
            thumbAttach := &models.Attachment{
                FileName: fileHeader.Filename,
                FileUrl:  thumbnailUrl,
                Ext:      ext,
                FileType: constvar.FileType_Thumbnail,
            }
            attachmentList = append(attachmentList, thumbAttach)
        }
    }
    if len(attachmentList) > 0 {
        if attachmentList, err = models.NewAttachmentSearch().CreateBatchWithResp(attachmentList); err != nil {
            logx.Errorf("attachment create err: %v", err)
            util.ResponseFormat(c, code.SaveFail, "文件保存失败")
            return
        }
    }
    util.ResponseFormat(c, code.Success, attachmentList)
}
go.mod
@@ -4,6 +4,7 @@
require (
    basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25
    basic.com/fileserver/WeedFSClient.git v0.0.0-20210224075854-9e78086ab4bf
    github.com/dgrijalva/jwt-go v3.2.0+incompatible
    github.com/gin-gonic/gin v1.9.0
    github.com/golang-jwt/jwt/v4 v4.5.0
@@ -57,6 +58,7 @@
    github.com/jinzhu/now v1.1.5 // indirect
    github.com/josharian/intern v1.0.0 // indirect
    github.com/json-iterator/go v1.1.12 // indirect
    github.com/kirinlabs/HttpRequest v1.1.1 // indirect
    github.com/klauspost/cpuid/v2 v2.2.5 // indirect
    github.com/leodido/go-urn v1.2.4 // indirect
    github.com/magiconair/properties v1.8.7 // indirect
@@ -66,12 +68,14 @@
    github.com/mitchellh/mapstructure v1.5.0 // indirect
    github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
    github.com/modern-go/reflect2 v1.0.2 // indirect
    github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
    github.com/pelletier/go-toml/v2 v2.0.9 // indirect
    github.com/prometheus/client_golang v1.16.0 // indirect
    github.com/prometheus/client_model v0.3.0 // indirect
    github.com/prometheus/common v0.42.0 // indirect
    github.com/prometheus/procfs v0.10.1 // indirect
    github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
    github.com/satori/go.uuid v1.2.0 // indirect
    github.com/sirupsen/logrus v1.9.3 // indirect
    github.com/spf13/afero v1.9.3 // indirect
    github.com/spf13/jwalterweatherman v1.1.0 // indirect
go.sum
@@ -1,5 +1,7 @@
basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25 h1:sZyNfIISgP1eoY94LG48Kav6HYVLem6EzaEbCeXlcXQ=
basic.com/aps/nsqclient.git v0.0.0-20230517072415-37491f4a5d25/go.mod h1:1RnwEtePLR7ATQorQTxdgvs1o7uuUy1Vw8W7GYtVnoY=
basic.com/fileserver/WeedFSClient.git v0.0.0-20210224075854-9e78086ab4bf h1:HGhtGSBibh1OV4oUe1SWw8DLfL4hXGGBFNW3dpcr+70=
basic.com/fileserver/WeedFSClient.git v0.0.0-20210224075854-9e78086ab4bf/go.mod h1:oiXPn3wwwOi/Sbm6cDWpNWofoG5iV2Nb1V/DxLEAqYY=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -230,6 +232,8 @@
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kirinlabs/HttpRequest v1.1.1 h1:eBbFzpRd/Y7vQhRY30frHK3yAJiT1wDlB31Ryzyklc0=
github.com/kirinlabs/HttpRequest v1.1.1/go.mod h1:XV38fA4rXZox83tlEV9KIQ7Cdsut319x6NGzVLuRlB8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -264,6 +268,8 @@
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsqio/go-nsq v1.1.0 h1:PQg+xxiUjA7V+TLdXw7nVrJ5Jbl3sN86EhGCQj4+FYE=
github.com/nsqio/go-nsq v1.1.0/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY=
@@ -290,6 +296,8 @@
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
models/attachment.go
New file
@@ -0,0 +1,256 @@
package models
import (
    "fmt"
    "gorm.io/gorm"
    "wms/constvar"
    "wms/pkg/mysqlx"
)
type (
    Attachment struct {
        WmsModel
        Id       int               `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
        FileName string            `json:"fileName" gorm:"type:varchar(127);comment:文件名"`
        FileUrl  string            `json:"FileUrl" gorm:"type:varchar(255);comment:文件地址"`
        Ext      string            `json:"ext" gorm:"type:varchar(15);comment:文件后缀名"`
        FileType constvar.FileType `json:"fileType" gorm:"type:varchar(31);comment:文件类型 pic:图片;thumbnail:缩略图;file:文件"`
    }
    AttachmentSearch struct {
        Attachment
        Order    string
        PageNum  int
        PageSize int
        Keyword  string
        Orm      *gorm.DB
        Preload  bool
    }
)
func (slf *Attachment) TableName() string {
    return "wms_attachment"
}
func NewAttachmentSearch() *AttachmentSearch {
    return &AttachmentSearch{Orm: mysqlx.GetDB()}
}
func (slf *AttachmentSearch) SetOrm(tx *gorm.DB) *AttachmentSearch {
    slf.Orm = tx
    return slf
}
func (slf *AttachmentSearch) SetPage(page, size int) *AttachmentSearch {
    slf.PageNum, slf.PageSize = page, size
    return slf
}
func (slf *AttachmentSearch) SetOrder(order string) *AttachmentSearch {
    slf.Order = order
    return slf
}
func (slf *AttachmentSearch) SetID(ID int) *AttachmentSearch {
    slf.Id = ID
    return slf
}
func (slf *AttachmentSearch) SetKeyword(keyword string) *AttachmentSearch {
    slf.Keyword = keyword
    return slf
}
func (slf *AttachmentSearch) SetPreload(preload bool) *AttachmentSearch {
    slf.Preload = preload
    return slf
}
func (slf *AttachmentSearch) build() *gorm.DB {
    var db = slf.Orm.Model(&Attachment{})
    if slf.Id != 0 {
        db = db.Where("id = ?", slf.Id)
    }
    if slf.Order != "" {
        db = db.Order(slf.Order)
    }
    if slf.Keyword != "" {
        db = db.Where("number like ? or source_number like ?", fmt.Sprintf("%%%v%%", slf.Keyword), fmt.Sprintf("%%%v%%", slf.Keyword))
    }
    //if slf.Preload {
    //    db = db.Model(&Attachment{}).Preload("Details").Preload("Details.Product").Preload("FromLocation").Preload("ToLocation")
    //}
    return db
}
// Create 单条插入
func (slf *AttachmentSearch) Create(record *Attachment) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return err
    }
    return nil
}
// CreateBatch 批量插入
func (slf *AttachmentSearch) CreateBatch(records []*Attachment) error {
    var db = slf.build()
    if err := db.Create(&records).Error; err != nil {
        return fmt.Errorf("create batch err: %v, records: %+v", err, records)
    }
    return nil
}
func (slf *AttachmentSearch) Save(record *Attachment) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Save(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *AttachmentSearch) Update(record *Attachment) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Updates(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *AttachmentSearch) UpdateByMap(upMap map[string]interface{}) error {
    var (
        db = slf.build()
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by map err: %v, upMap: %+v", err, upMap)
    }
    return nil
}
func (slf *AttachmentSearch) UpdateByQuery(query string, args []interface{}, upMap map[string]interface{}) error {
    var (
        db = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by query err: %v, query: %s, args: %+v, upMap: %+v", err, query, args, upMap)
    }
    return nil
}
func (slf *AttachmentSearch) Delete() error {
    var db = slf.build()
    return db.Delete(&Attachment{}).Error
}
func (slf *AttachmentSearch) First() (*Attachment, error) {
    var (
        record = new(Attachment)
        db     = slf.build()
    )
    if err := db.First(record).Error; err != nil {
        return record, err
    }
    return record, nil
}
func (slf *AttachmentSearch) Find() ([]*Attachment, int64, error) {
    var (
        records = make([]*Attachment, 0)
        total   int64
        db      = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Order("created_at desc").Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find records err: %v", err)
    }
    return records, total, nil
}
func (slf *AttachmentSearch) FindNotTotal() ([]*Attachment, error) {
    var (
        records = make([]*Attachment, 0)
        db      = slf.build()
    )
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Preload("FromLocation").Preload("ToLocation").Find(&records).Error; err != nil {
        return records, fmt.Errorf("find records err: %v", err)
    }
    return records, nil
}
// FindByQuery 指定条件查询.
func (slf *AttachmentSearch) FindByQuery(query string, args []interface{}) ([]*Attachment, int64, error) {
    var (
        records = make([]*Attachment, 0)
        total   int64
        db      = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find by query count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find by query records err: %v, query: %s, args: %+v", err, query, args)
    }
    return records, total, nil
}
// FindByQueryNotTotal 指定条件查询&不查询总条数.
func (slf *AttachmentSearch) FindByQueryNotTotal(query string, args []interface{}) ([]*Attachment, error) {
    var (
        records = make([]*Attachment, 0)
        db      = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find by query records err: %v, query: %s, args: %+v", err, query, args)
    }
    return records, nil
}
func (slf *AttachmentSearch) CreateBatchWithResp(records []*Attachment) ([]*Attachment, error) {
    var db = slf.build()
    if err := db.Create(&records).Error; err != nil {
        return nil, fmt.Errorf("create batch err: %v, records: %+v", err, records)
    }
    return records, nil
}
models/db.go
@@ -86,6 +86,7 @@
        LocationProduct{},
        LocationProductAmount{},
        ReorderRule{},
        Attachment{},
    )
    return err
}
router/router.go
@@ -155,5 +155,11 @@
        reorderRuleAPI.POST("orderAgain", reorderRuleController.OrderAgain)                         //再订一次
    }
    attachmentController := new(controllers.AttachmentController)
    attachmentAPI := r.Group(urlPrefix + "/attachment")
    {
        attachmentAPI.POST("uploadFiles", attachmentController.UploadFiles) //上传文件
    }
    return r
}
utils/image/image.go
New file
@@ -0,0 +1,74 @@
package image
import (
    "bytes"
    "errors"
    "github.com/nfnt/resize"
    "image"
    "image/jpeg"
    "image/png"
    "strings"
)
func CreateThumbnail(fileBytes []byte, side, width, height int) ([]byte, error) {
    img, format, err := image.Decode(bytes.NewReader(fileBytes))
    if err != nil {
        return nil, err
    }
    var thumbnailImg image.Image
    if side > 0 {
        var canvas image.Image
        s := side
        sz := img.Bounds().Size()
        if sz.X > sz.Y {
            canvas = resize.Thumbnail(uint(sz.X), uint(s), img, resize.Lanczos2)
        } else {
            canvas = resize.Thumbnail(uint(s), uint(sz.Y), img, resize.Lanczos2)
        }
        sz = canvas.Bounds().Size()
        var l, t, r, b int
        if sz.X > s {
            l = (sz.X - s) / 2
            r = l + s
        } else {
            l = 0
            r = sz.X
        }
        if sz.Y > s {
            t = (sz.Y - s) / 2
            b = t + s
        } else {
            t = 0
            b = sz.Y
        }
        thumbnailImg = canvas.(*image.YCbCr).SubImage(image.Rect(l, t, r, b)).(*image.YCbCr)
    } else {
        w := width
        h := height
        if w > 0 && h > 0 {
        } else if w > 0 {
            h = img.Bounds().Dy()
        } else {
            w = img.Bounds().Dx()
        }
        thumbnailImg = resize.Thumbnail(uint(w), uint(h), img, resize.Lanczos2)
    }
    buffer := new(bytes.Buffer)
    format = strings.ToLower(format)
    if format == "jpg" || format == "jpeg" {
        if err := jpeg.Encode(buffer, thumbnailImg, nil); err != nil {
            return nil, err
        }
    } else if format == "png" {
        if err := png.Encode(buffer, thumbnailImg); err != nil {
            return nil, err
        }
    } else {
        return nil, errors.New("不支持的文件格式")
    }
    return buffer.Bytes(), nil
}
utils/upload/seaweed.go
@@ -1 +1,25 @@
package upload
import (
    "basic.com/fileserver/WeedFSClient.git"
    uuid "github.com/satori/go.uuid"
    "strconv"
    "time"
    "wms/conf"
    "wms/pkg/logx"
)
func UploadFileToSeaWeed(fileType, ext string, fileBytes []byte) (string, error) {
    //assignUrl := conf.WebConf.FileServer + "/dir/assign?collection=" + time.Now().Format("2006-01-02 15:04:05")[:10] + "-" + conf.WebConf.ServerId + "-" + fileType
    assignUrl := conf.WebConf.FileServer + "/dir/assign?collection=" + strconv.FormatInt(time.Now().Unix(), 10) + "-" + conf.WebConf.ServerId + "-" + fileType
    picUrl, err := WeedFSClient.GetFid(assignUrl)
    if err != nil {
        logx.Error(err.Error())
        return picUrl, err
    }
    picFileName := uuid.NewV4().String() + "." + ext
    go WeedFSClient.UploadFile(picUrl, picFileName, fileBytes, 3*time.Second)
    return picUrl, nil
}