fix 附件管理器,上传功能优化,富文本附件选择接口,移除旧版大文件上传,合并至附件管理器,优化通知图标列表,升级gf2.8

This commit is contained in:
yxh
2024-11-19 10:28:50 +08:00
parent ef357ea7e3
commit ac3f801d4f
65 changed files with 2210 additions and 1434 deletions

View File

@@ -1,38 +0,0 @@
package system
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/library/upload_chunk"
)
// 上传文件
type BigUploadReq struct {
g.Meta `path:"/bigUpload/upload" tags:"系统后台/后台大文件上传" method:"post" summary:"上传文件"`
upload_chunk.UploadReq
}
type BigUploadRes struct {
upload_chunk.UpLoadRes
}
// 上传文件检查
type BigUploadCheckReq struct {
g.Meta `path:"/bigUpload/upload" tags:"系统后台/后台大文件上传" method:"get" summary:"上传文件检查"`
upload_chunk.UploadReq
}
type BigUploadCheckRes struct {
upload_chunk.CheckRes
Identifier string `json:"identifier"` // 标识
TotalChunks int `json:"totalChunks"` // 分片总数
}
// 上传文件合并
type BigUploadMergeReq struct {
g.Meta `path:"/bigUpload/uploadMerge" tags:"系统后台/后台大文件上传" method:"post" summary:"上传文件合并"`
upload_chunk.UploadReq
}
type BigUploadMergeRes struct {
upload_chunk.MergeRes
}

View File

@@ -0,0 +1,89 @@
// ==========================================================================
// GFast自动生成api操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: api/v1/system/sys_attachment.go
// 生成人gfast
// desc:附件管理相关参数
// company:云南奇讯科技有限公司
// ==========================================================================
package system
import (
"github.com/gogf/gf/v2/frame/g"
commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
)
// SysAttachmentSearchReq 分页请求参数
type SysAttachmentSearchReq struct {
g.Meta `path:"/list" tags:"附件管理" method:"get" summary:"附件管理列表"`
commonApi.Author
model.SysAttachmentSearchReq
}
// SysAttachmentSearchRes 列表返回结果
type SysAttachmentSearchRes struct {
g.Meta `mime:"application/json"`
*model.SysAttachmentSearchRes
}
// SysAttachmentAddReq 添加操作请求参数
type SysAttachmentAddReq struct {
g.Meta `path:"/add" tags:"附件管理" method:"post" summary:"附件管理添加"`
commonApi.Author
*model.SysAttachmentAddReq
}
// SysAttachmentAddRes 添加操作返回结果
type SysAttachmentAddRes struct {
commonApi.EmptyRes
}
// SysAttachmentEditReq 修改操作请求参数
type SysAttachmentEditReq struct {
g.Meta `path:"/edit" tags:"附件管理" method:"put" summary:"附件管理修改"`
commonApi.Author
*model.SysAttachmentEditReq
}
// SysAttachmentEditRes 修改操作返回结果
type SysAttachmentEditRes struct {
commonApi.EmptyRes
}
// SysAttachmentGetReq 获取一条数据请求
type SysAttachmentGetReq struct {
g.Meta `path:"/get" tags:"附件管理" method:"get" summary:"获取附件管理信息"`
commonApi.Author
Id int64 `p:"id" v:"required#主键必须"` //通过主键获取
}
// SysAttachmentGetRes 获取一条数据结果
type SysAttachmentGetRes struct {
g.Meta `mime:"application/json"`
*model.SysAttachmentInfoRes
}
// SysAttachmentDeleteReq 删除数据请求
type SysAttachmentDeleteReq struct {
g.Meta `path:"/delete" tags:"附件管理" method:"delete" summary:"删除附件管理"`
commonApi.Author
Ids []int64 `p:"ids" v:"required#主键必须"` //通过主键删除
}
// SysAttachmentDeleteRes 删除数据返回
type SysAttachmentDeleteRes struct {
commonApi.EmptyRes
}
// 附件管理状态修改(状态)
type SysAttachmentStatusSwitchReq struct {
g.Meta `path:"/changeStatus" tags:"附件管理" method:"put" summary:"修改状态"`
commonApi.Author
Id int64 `p:"id" v:"required#主键必须"` //通过主键修改
Status bool `p:"status" v:"required#状态必须"` //通过主键获取
}
type SysAttachmentStatusSwitchRes struct {
commonApi.EmptyRes
}

View File

@@ -30,7 +30,7 @@ type RuleAddReq struct {
g.Meta `path:"/menu/add" tags:"系统后台/菜单管理" method:"post" summary:"添加菜单"`
commonApi.Author
MenuType uint `p:"menuType" v:"min:0|max:2#菜单类型最小值为:min|菜单类型最大值为:max"`
Pid uint `p:"parentId" v:"min:0"`
Pid uint `p:"pid" v:"min:0"`
Name string `p:"name" v:"required#请填写规则名称"`
Title string `p:"menuName" v:"required|length:1,100#请填写标题|标题长度在:min到:max位"`
Icon string `p:"icon"`
@@ -80,7 +80,7 @@ type RuleUpdateReq struct {
commonApi.Author
Id uint `p:"id" v:"required#id必须"`
MenuType uint `p:"menuType" v:"min:0|max:2#菜单类型最小值为:min|菜单类型最大值为:max"`
Pid uint `p:"parentId" v:"min:0"`
Pid uint `p:"pid" v:"min:0"`
Name string `p:"name" v:"required#请填写规则名称"`
Title string `p:"menuName" v:"required|length:1,100#请填写标题|标题长度在:min到:max位"`
Icon string `p:"icon"`

View File

@@ -1,66 +0,0 @@
package system
import (
"github.com/gogf/gf/v2/frame/g"
commonApi "github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
)
type BigFileSearchReq struct {
g.Meta `path:"/bigFile/list" tags:"大文件管理" method:"get" summary:"大文件管理"`
Name string `p:"name"` //文件名称
commonApi.PageReq
}
type BigFileSearchRes struct {
g.Meta `mime:"application/json"`
List []*entity.BigFile `json:"list"`
commonApi.ListRes
}
type BigFileForm struct {
Name string `p:"name" v:"required#文件名称必须"`
Size int `p:"size" v:"required#文件大小必须"`
Path string `p:"path" v:"required#文件路径必须"`
FullPath string `p:"fullPath"`
MimeType string `p:"mimeType"`
Source int `p:"source"`
Describe string `p:"describe"`
Md5 string `p:"md5"`
}
type BigFileGetReq struct {
g.Meta `path:"/bigFile/get" tags:"系统后台/大文件管理" method:"get" summary:"获取大文件信息"`
Id uint64 `p:"id"`
}
type BigFileGetRes struct {
g.Meta `mime:"application/json"`
entity.BigFile
}
type BigFileAddReq struct {
g.Meta `path:"/bigFile/add" tags:"系统后台/大文件管理" method:"post" summary:"大文件新增"`
BigFileForm
}
type BigFileAddRes struct {
}
type BigFileEditReq struct {
g.Meta `path:"/bigFile/edit" tags:"系统后台/大文件管理" method:"put" summary:"大文件新增"`
Id uint64 `p:"id" v:"required|min:1#主键ID不能为空|主键ID参数错误"`
Name string `p:"name" v:"required#标题必须"`
Describe string `p:"describe"`
}
type BigFileEditRes struct {
}
type BigFileDeleteReq struct {
g.Meta `path:"/bigFile/delete" tags:"系统后台/大文件管理" method:"delete" summary:"大文件删除"`
Ids []uint64 `p:"ids"`
}
type BigFileDeleteRes struct {
}

View File

@@ -56,7 +56,7 @@ type RoleAddRes struct {
type RoleGetReq struct {
g.Meta `path:"/role/get" tags:"系统后台/角色管理" method:"get" summary:"获取角色信息"`
commonApi.Author
Id uint `p:"id" v:"required#角色id不能为空""`
Id uint `p:"id" v:"required#角色id不能为空"`
}
type RoleGetRes struct {

View File

@@ -26,6 +26,8 @@ type UEditorReq struct {
Action string `p:"action"`
Callback string `p:"callback"`
File *ghttp.UploadFile `p:"upfile" type:"file"`
Start int `p:"start"`
Size int `p:"size"`
}
type UEditorRes struct {

View File

@@ -3,6 +3,8 @@ package system
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/api/v1/common"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
)
// 单图上传
@@ -19,7 +21,7 @@ type UploadSingleFileReq struct {
type UploadSingleRes struct {
g.Meta `mime:"application/json"`
UploadResponse
*model.UploadResponse
}
// 多图上传
@@ -34,12 +36,30 @@ type UploadMultipleFileReq struct {
File ghttp.UploadFiles `p:"file" type:"file" dc:"选择上传文件" v:"required#上传文件必须"`
}
type UploadMultipleRes []*UploadResponse
type UploadMultipleRes []*model.UploadResponse
type UploadResponse struct {
Size int64 `json:"size" dc:"文件大小"`
Path string `json:"path" dc:"文件相对路径"`
FullPath string `json:"fullPath" dc:"文件绝对路径"`
Name string `json:"name" dc:"文件名称"`
Type string `json:"type" dc:"文件类型"`
*model.UploadResponse
}
type CheckMultipartReq struct {
g.Meta `path:"/upload/checkMultipart" tags:"系统后台/后台文件上传" method:"post" summary:"检查分片"`
common.Author
*model.CheckMultipartReq
}
type CheckMultipartRes struct {
g.Meta `mime:"application/json"`
*model.CheckMultipartRes
}
type UploadPartReq struct {
g.Meta `path:"/upload/uploadPart" tags:"系统后台/后台文件上传" method:"post" summary:"分片上传"`
common.Author
*model.UploadPartReq
}
type UploadPartRes struct {
g.Meta `mime:"application/json"`
*model.UploadPartRes
}

14
go.mod
View File

@@ -10,10 +10,10 @@ require (
github.com/apache/rocketmq-client-go/v2 v2.1.1
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
github.com/casbin/casbin/v2 v2.42.0
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.4
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.7.4
github.com/gogf/gf/contrib/nosql/redis/v2 v2.7.4
github.com/gogf/gf/v2 v2.7.4
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.0
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.0
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.0
github.com/gogf/gf/v2 v2.8.0
github.com/gorilla/websocket v1.5.3
github.com/mojocn/base64Captcha v1.3.6
github.com/mssola/user_agent v0.5.3
@@ -22,10 +22,11 @@ require (
github.com/shirou/gopsutil/v3 v3.23.2
github.com/sony/sonyflake v1.2.0
github.com/tencentyun/cos-go-sdk-v5 v0.7.34
github.com/tiger1103/gfast-cache v1.0.7
github.com/tiger1103/gfast-token v1.0.7
github.com/tiger1103/gfast-cache v1.0.8
github.com/tiger1103/gfast-token v1.0.8
github.com/wenlng/go-captcha v1.2.5
github.com/xuri/excelize/v2 v2.7.1
golang.org/x/net v0.28.0
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
)
@@ -104,7 +105,6 @@ require (
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/image v0.16.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect

24
go.sum
View File

@@ -69,14 +69,14 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.4 h1:Rhv48tVnl+o5qyd1hTLxKStWT7MEqP0zrEXKa/t4VLg=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.7.4/go.mod h1:V6eAZVlFWv4AgDK7VzLbwMZiOygcu/374Rcyhv9hSEM=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.7.4 h1:6eaV81MUtE7NUqYR95wOLQcdZ+OlLxn2GEs+rN+wtrM=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.7.4/go.mod h1:JjZO8Ic5UxnFVtEY4cDkpFQQ1tx7pX7ZAQnlJ8ux0Kc=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.7.4 h1:7KS3/mBBLfROPUKjIa8M7umxzajqBA27/CIhWdKAxNc=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.7.4/go.mod h1:B1/0sQcdCpGfpiljng2osL2hoGZkpOXPa+CAvzdoYMw=
github.com/gogf/gf/v2 v2.7.4 h1:cGHUBO5Jr8ty21GN5EO+S2rFYhprdcqnwS7PnWL7+t4=
github.com/gogf/gf/v2 v2.7.4/go.mod h1:EBXneAg/wes86rfeh68XC0a2JBNQylmT7Sp6/8Axk88=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.0 h1:Foyx+sGaHAfLXxbTc4xULyO+jaPmQO7puq2rius0pIQ=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.0/go.mod h1:JuRwELQEatN+KrcumDhSd5nEysyD8Dh3voXjjuKs+Gk=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.0 h1:4BVMHFtMGc+l0T+QjDFQsc09fIX4qf0zPWKsb+wxVpI=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.0/go.mod h1:nZ5VGwXMT4GRow6IK/1VVcPArQtukcF+49kNOwvZT98=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.0 h1:12l4LDn/ENMwG//tl6ICXfrAY+9vRy4kzi23H1MSkCI=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.8.0/go.mod h1:8Jp8s33CX4yPajGv5NVUlYHPi5Pru81HUKQv+ccS4/o=
github.com/gogf/gf/v2 v2.8.0 h1:CgNDoLFQCBxQaWOoGMzgU068T+tm0t/eNUgLV2wPJag=
github.com/gogf/gf/v2 v2.8.0/go.mod h1:6iYuZZ+A0ZcH8+4MDS/P0SvTPCvKzRvyAsY1kbkJYJc=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
@@ -235,10 +235,10 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tiger1103/gfast-cache v1.0.7 h1:ocGP7Z7BKpk2OPfNBhOGyuWOKwyDZxtqmqL1GiGGTaw=
github.com/tiger1103/gfast-cache v1.0.7/go.mod h1:ZTR64Ad6YHM2fehOg9yE3ysdWxq+aAxXKpmTlVCB2nw=
github.com/tiger1103/gfast-token v1.0.7 h1:xvFN4tQecaHghrAnb/DzcRk8jQjLwn3Tk3GirR/vcoE=
github.com/tiger1103/gfast-token v1.0.7/go.mod h1:gHgyf+25+tt4AbfrAtC+EM/SgM55wgPkLQiksLP/5+4=
github.com/tiger1103/gfast-cache v1.0.8 h1:RK8VM3mS+H/D2uvhgNJnHtU2E7RuIlwW0yKvBQzuaHg=
github.com/tiger1103/gfast-cache v1.0.8/go.mod h1:SNNHfEexumeIXSKz7f/ais+Fi97+TeJvT3r92MqlNk0=
github.com/tiger1103/gfast-token v1.0.8 h1:hRNoGna8ji2lPZjMnpaJgZxh2EP3oAVFUSxEaMy79dY=
github.com/tiger1103/gfast-token v1.0.8/go.mod h1:gHgyf+25+tt4AbfrAtC+EM/SgM55wgPkLQiksLP/5+4=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=

View File

@@ -8,4 +8,7 @@ const (
FileSizeKey = "sys.uploadFile.fileSize"
CheckFileTypeImg = "img" // 文件类型(图片)
CheckFileTypeFile = "file" // 文件类型(任意)
UploadDriverLocal = 0 // 本地上传
)

View File

@@ -0,0 +1,103 @@
// ==========================================================================
// GFast自动生成dao internal操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/dao/internal/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysAttachmentDao is the manager for logic model data accessing and custom defined data operations functions management.
type SysAttachmentDao struct {
table string // Table is the underlying table name of the DAO.
group string // Group is the database configuration group name of current DAO.
columns SysAttachmentColumns // Columns is the short type for Columns, which contains all the column names of Table for convenient usage.
}
// SysAttachmentColumns defines and stores column names for table sys_attachment.
type SysAttachmentColumns struct {
Id string // 文件ID
AppId string // 应用ID
Drive string // 上传驱动
Name string // 文件原始名
Kind string // 上传类型
MimeType string // 扩展类型
Path string // 本地路径
Size string // 文件大小
Ext string // 扩展名
Md5 string // md5校验码
CreatedBy string // 上传人ID
Status string // 状态
CreatedAt string // 创建时间
UpdatedAt string // 修改时间
}
var sysAttachmentColumns = SysAttachmentColumns{
Id: "id",
AppId: "app_id",
Drive: "drive",
Name: "name",
Kind: "kind",
MimeType: "mime_type",
Path: "path",
Size: "size",
Ext: "ext",
Md5: "md5",
CreatedBy: "created_by",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
// NewSysAttachmentDao creates and returns a new DAO object for table data access.
func NewSysAttachmentDao() *SysAttachmentDao {
return &SysAttachmentDao{
group: "default",
table: "sys_attachment",
columns: sysAttachmentColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysAttachmentDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysAttachmentDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysAttachmentDao) Columns() SysAttachmentColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysAttachmentDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysAttachmentDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *SysAttachmentDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@@ -0,0 +1,29 @@
// ==========================================================================
// GFast自动生成dao操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/dao/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package dao
import (
"github.com/tiger1103/gfast/v3/internal/app/common/dao/internal"
)
// sysAttachmentDao is the manager for logic model data accessing and custom defined data operations functions management.
// You can define custom methods on it to extend its functionality as you wish.
type sysAttachmentDao struct {
*internal.SysAttachmentDao
}
var (
// SysAttachment is globally public accessible object for table tools_gen_table operations.
SysAttachment = sysAttachmentDao{
internal.NewSysAttachmentDao(),
}
)
// Fill with you ideas below.

View File

@@ -1,74 +0,0 @@
/*
* @desc:大文件上传
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2022/9/27 16:25
*/
package bigUpload
import (
"context"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/library/upload_chunk"
)
func init() {
service.RegisterBigUpload(New())
}
func New() service.IBigUpload {
return &sBigUpload{}
}
type sBigUpload struct{}
// Upload 上传分片文件
func (s *sBigUpload) Upload(ctx context.Context, req *system.BigUploadReq) (res *system.BigUploadRes, err error) {
uploadChunk := &upload_chunk.UploadChunk{}
result, err := uploadChunk.Upload(req.UploadReq)
if err != nil {
return
}
res = new(system.BigUploadRes)
res.UpLoadRes = *result
return
}
// UploadCheck 上传文件检查
func (s *sBigUpload) UploadCheck(ctx context.Context, req *system.BigUploadCheckReq) (res *system.BigUploadCheckRes, err error) {
uploadChunk := &upload_chunk.UploadChunk{}
result, err := uploadChunk.CheckChunk(req.UploadReq)
if err != nil {
return
}
//res = new(common.BigUploadCheckRes)
//res.CheckRes = *result
res = &system.BigUploadCheckRes{
CheckRes: *result,
Identifier: req.Identifier,
TotalChunks: req.TotalChunks,
}
return
}
// UploadMerge 上传文件合并
func (s *sBigUpload) UploadMerge(ctx context.Context, req *system.BigUploadMergeReq) (res *system.BigUploadRes, err error) {
uploadChunk := &upload_chunk.UploadChunk{}
result, err := uploadChunk.MergeChunk(req.UploadReq)
if err != nil {
return
}
res = &system.BigUploadRes{
UpLoadRes: upload_chunk.UpLoadRes{
BaseRes: result.BaseRes,
NeedMerge: false,
Identifier: req.Identifier,
TotalChunks: req.TotalChunks,
},
}
return
}

View File

@@ -5,12 +5,12 @@
package logic
import (
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/bigUpload"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/cache"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/captcha"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/eventBus"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/middleware"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/snowIDGen"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/sysAttachment"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/sysConfig"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/sysDictData"
_ "github.com/tiger1103/gfast/v3/internal/app/common/logic/sysDictType"

View File

@@ -0,0 +1,300 @@
// ==========================================================================
// GFast自动生成logic操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/logic/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package sysAttachment
import (
"context"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/internal/app/common/dao"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/internal/app/common/model/do"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/library/liberr"
)
var fileKind = map[string]*gset.StrSet{
//图片
"image": gset.NewStrSetFrom([]string{
"jpeg",
"jpg",
"png",
"gif",
"webp",
"cr2",
"tif",
"bmp",
"heif",
"jxr",
"psd",
"ico",
"dwg",
}),
//文档
"doc": gset.NewStrSetFrom([]string{
"doc",
"docx",
"dot",
"xls",
"xlt",
"xlsx",
"xltx",
"ppt",
"pptx",
"pdf",
"txt",
"csv",
"html",
"xml",
"pptm",
"pot",
"wpd",
"md",
"json",
"yaml",
"markdown",
"asciidoc",
"xsl",
"wps",
"sxi",
"sti",
"odp",
}),
//视频
"video": gset.NewStrSetFrom([]string{
"mp4",
"m4v",
"mkv",
"webm",
"mov",
"avi",
"wmv",
"mpg",
"flv",
"3gp",
}),
//音频
"audio": gset.NewStrSetFrom([]string{
"mid",
"mp3",
"m4a",
"ogg",
"flac",
"wav",
"amr",
"aac",
"aiff",
}),
//压缩包
"zip": gset.NewStrSetFrom([]string{
"zip",
"rar",
"tar",
"gz",
"7z",
"tar.gz",
}),
//其它
"other": gset.NewStrSetFrom([]string{
"dwf",
"ics",
"vcard",
"apk",
"ipa",
}),
}
func init() {
service.RegisterSysAttachment(New())
}
func New() service.ISysAttachment {
return &sSysAttachment{}
}
type sSysAttachment struct{}
type AddHandler = func(ctx context.Context) (err error)
func (s *sSysAttachment) List(ctx context.Context, req *model.SysAttachmentSearchReq) (listRes *model.SysAttachmentSearchRes, err error) {
listRes = new(model.SysAttachmentSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.SysAttachment.Ctx(ctx).WithAll()
if req.AppId != "" {
m = m.Where(dao.SysAttachment.Columns().AppId+" = ?", req.AppId)
}
if req.Drive != "" {
m = m.Where(dao.SysAttachment.Columns().Drive+" = ?", req.Drive)
}
if req.Name != "" {
m = m.Where(dao.SysAttachment.Columns().Name+" like ?", "%"+req.Name+"%")
}
if req.Kind != "" {
m = m.Where(dao.SysAttachment.Columns().Kind+" = ?", req.Kind)
}
if req.MimeType != "" {
m = m.Where(dao.SysAttachment.Columns().MimeType+" like ?", "%"+req.MimeType+"%")
}
if req.Status != "" {
m = m.Where(dao.SysAttachment.Columns().Status+" = ?", gconv.Bool(req.Status))
}
if req.CreatedAt != nil && len(req.CreatedAt) > 0 {
if req.CreatedAt[0] != "" {
m = m.Where(dao.SysAttachment.Columns().UpdatedAt+" >= ?", gconv.Time(req.CreatedAt[0]))
}
if len(req.CreatedAt) > 1 && req.CreatedAt[1] != "" {
m = m.Where(dao.SysAttachment.Columns().UpdatedAt+" < ?", gconv.Time(req.CreatedAt[1]))
}
}
listRes.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取总行数失败")
if req.PageNum == 0 {
req.PageNum = 1
}
listRes.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = consts.PageSize
}
order := "updated_at desc,id desc"
if req.OrderBy != "" {
order = req.OrderBy
}
var res []*model.SysAttachmentListRes
err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
listRes.List = make([]*model.SysAttachmentListRes, len(res))
for k, v := range res {
listRes.List[k] = &model.SysAttachmentListRes{
Id: v.Id,
AppId: v.AppId,
Drive: v.Drive,
Name: v.Name,
Kind: v.Kind,
Path: v.Path,
Size: v.Size,
Ext: v.Ext,
Status: v.Status,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
}
}
})
return
}
func (s *sSysAttachment) GetById(ctx context.Context, id int64) (res *model.SysAttachmentInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysAttachment.Ctx(ctx).WithAll().Where(dao.SysAttachment.Columns().Id, id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
})
return
}
func (s *sSysAttachment) GetByMd5(ctx context.Context, md5 string) (res *model.SysAttachmentInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysAttachment.Ctx(ctx).WithAll().Where(dao.SysAttachment.Columns().Md5, md5).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取信息失败")
if res != nil {
_, _ = dao.SysAttachment.Ctx(ctx).Unscoped().WherePri(res.Id).Update(do.SysAttachment{
UpdatedAt: gtime.Now(),
})
}
})
return
}
func (s *sSysAttachment) AddUpload(ctx context.Context, req *model.UploadResponse, attr *model.SysAttachmentAddAttribute) (err error) {
ext := gstr.SubStrRune(req.Name, gstr.PosRRune(req.Name, ".")+1, gstr.LenRune(req.Name)-1)
err = s.Add(ctx, &model.SysAttachmentAddReq{
AppId: attr.AppId,
Drive: attr.Driver,
Name: req.Name,
Kind: s.getFileKind(ext),
MimeType: req.Type,
Path: req.Path,
Size: req.Size,
Ext: ext,
Md5: attr.Md5,
Status: true,
CreatedBy: attr.UserId,
})
return
}
func (s *sSysAttachment) Add(ctx context.Context, req *model.SysAttachmentAddReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysAttachment.Ctx(ctx).Insert(do.SysAttachment{
AppId: req.AppId,
Drive: req.Drive,
Name: req.Name,
Kind: req.Kind,
MimeType: req.MimeType,
Path: req.Path,
Size: req.Size,
Ext: req.Ext,
Md5: req.Md5,
Status: req.Status,
CreatedBy: req.CreatedBy,
})
liberr.ErrIsNil(ctx, err, "添加失败")
})
return
}
func (s *sSysAttachment) Edit(ctx context.Context, req *model.SysAttachmentEditReq) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysAttachment.Ctx(ctx).WherePri(req.Id).Update(do.SysAttachment{
AppId: req.AppId,
Drive: req.Drive,
Name: req.Name,
Kind: req.Kind,
MimeType: req.MimeType,
Path: req.Path,
Size: req.Size,
Ext: req.Ext,
Md5: req.Md5,
Status: req.Status,
})
liberr.ErrIsNil(ctx, err, "修改失败")
})
return
}
func (s *sSysAttachment) Delete(ctx context.Context, ids []int64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysAttachment.Ctx(ctx).Delete(dao.SysAttachment.Columns().Id+" in (?)", ids)
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}
// 附件管理状态修改(状态)
func (s *sSysAttachment) ChangeStatus(ctx context.Context, id int64, status bool) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.SysAttachment.Ctx(ctx).WherePri(id).
Update(do.SysAttachment{
Status: status,
})
liberr.ErrIsNil(ctx, err, "修改失败")
})
return
}
func (s *sSysAttachment) getFileKind(ext string) string {
for k, v := range fileKind {
if v.ContainsI(ext) {
return k
}
}
return "other"
}

View File

@@ -9,6 +9,8 @@ package upload
import (
"context"
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
@@ -17,11 +19,14 @@ import (
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/consts"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/internal/app/common/model/entity"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
"github.com/tiger1103/gfast/v3/library/upload"
"io"
)
func init() {
@@ -35,42 +40,68 @@ func New() service.IUpload {
type sUpload struct{}
// UploadFiles 上传多文件
func (s *sUpload) UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result system.UploadMultipleRes, err error) {
func (s *sUpload) UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int, userId uint64, appId string) (result []*model.UploadResponse, err error) {
for _, item := range files {
f, e := s.UploadFile(ctx, item, checkFileType, source)
f, e := s.UploadFile(ctx, item, checkFileType, source, userId, appId)
if e != nil {
return
}
result = append(result, &f)
result = append(result, f)
}
return
}
// UploadFile 上传单文件
func (s *sUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result system.UploadResponse, err error) {
func (s *sUpload) UploadFile(ctx context.Context,
file *ghttp.UploadFile, checkFileType string, source int,
userId uint64, appId string) (result *model.UploadResponse, err error) {
err = g.Try(ctx, func(ctx context.Context) {
// 检查文件类型
err = s.CheckType(ctx, checkFileType, file)
if err != nil {
return
}
err = s.CheckType(ctx, checkFileType, file.Filename)
liberr.ErrIsNil(ctx, err)
// 检查文件大小
err = s.CheckSize(ctx, checkFileType, file)
if err != nil {
err = s.CheckSize(ctx, checkFileType, file.Size)
liberr.ErrIsNil(ctx, err)
//判断该文件是否已经上传过,上传过则不再上传
var (
md5 = ""
existsFile *model.SysAttachmentInfoRes
)
md5, err = s.computeMD5(file)
liberr.ErrIsNil(ctx, err)
existsFile, err = service.SysAttachment().GetByMd5(ctx, md5)
liberr.ErrIsNil(ctx, err, "获取文件信息失败")
if existsFile != nil {
result = &model.UploadResponse{
Size: existsFile.Size,
Path: existsFile.Path,
FullPath: libUtils.GetDomain(ctx, true) + "/" + existsFile.Path,
Name: existsFile.Name,
Type: existsFile.MimeType,
}
return
}
uploader := upload.GetUploader(upload.UploaderType(source))
if uploader == nil {
err = errors.New("没有找到上传适配器")
return
liberr.ErrIsNil(ctx, errors.New("没有找到上传适配器"))
}
return uploader.Upload(ctx, file)
result, err = uploader.Upload(ctx, file)
liberr.ErrIsNil(ctx, err)
//保存上传文件到数据库
err = service.SysAttachment().AddUpload(ctx, result, &model.SysAttachmentAddAttribute{
Md5: md5,
Driver: gconv.Uint(source),
UserId: userId,
AppId: appId,
})
liberr.ErrIsNil(ctx, err)
})
return
}
// CheckSize 检查上传文件大小
func (s *sUpload) CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) {
func (s *sUpload) CheckSize(ctx context.Context, checkFileType string, fileSize int64) (err error) {
var (
configSize *entity.SysConfig
@@ -95,7 +126,7 @@ func (s *sUpload) CheckSize(ctx context.Context, checkFileType string, file *ght
}
var rightSize bool
rightSize, err = s.checkSize(configSize.ConfigValue, file.Size)
rightSize, err = s.checkSize(configSize.ConfigValue, fileSize)
if err != nil {
return
}
@@ -107,7 +138,7 @@ func (s *sUpload) CheckSize(ctx context.Context, checkFileType string, file *ght
}
// CheckType 检查上传文件类型
func (s *sUpload) CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error) {
func (s *sUpload) CheckType(ctx context.Context, checkFileType string, fileName string) (err error) {
var (
configType *entity.SysConfig
@@ -130,7 +161,7 @@ func (s *sUpload) CheckType(ctx context.Context, checkFileType string, file *ght
return errors.New(fmt.Sprintf("文件检查类型错误:%s|%s", consts.CheckFileTypeFile, consts.CheckFileTypeImg))
}
rightType := s.checkFileType(file.Filename, configType.ConfigValue)
rightType := s.checkFileType(fileName, configType.ConfigValue)
if !rightType {
err = gerror.New("上传文件类型错误,只能包含后缀为:" + configType.ConfigValue + "的文件。")
return
@@ -199,3 +230,80 @@ func (s *sUpload) getStaticPath(ctx context.Context) string {
}
return ""
}
// computeMD5 计算给定文件的 MD5 值
func (s *sUpload) computeMD5(upFile *ghttp.UploadFile) (string, error) {
file, err := upFile.Open()
if err != nil {
return "", err
}
defer file.Close()
// 创建一个新的 MD5 哈希对象
hash := md5.New()
// 逐块读取文件内容并更新哈希
if _, err := io.Copy(hash, file); err != nil {
return "", err
}
// 将 MD5 值转换为十六进制字符串
return hex.EncodeToString(hash.Sum(nil)), nil
}
func (s *sUpload) CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
// 检查文件类型
err = s.CheckType(ctx, req.UploadType, req.FileName)
liberr.ErrIsNil(ctx, err)
// 检查文件大小
err = s.CheckSize(ctx, req.UploadType, req.Size)
liberr.ErrIsNil(ctx, err)
//检查文件是否已经上传
var existsFile *model.SysAttachmentInfoRes
existsFile, err = service.SysAttachment().GetByMd5(ctx, req.Md5)
liberr.ErrIsNil(ctx, err, "获取文件信息失败")
res = new(model.CheckMultipartRes)
if existsFile != nil {
res.Attachment = &model.UploadResponse{
Size: existsFile.Size,
Path: existsFile.Path,
FullPath: libUtils.GetDomain(ctx, true) + "/" + existsFile.Path,
Name: existsFile.Name,
Type: existsFile.MimeType,
}
return
}
uploader := upload.GetUploader(upload.UploaderType(req.DriverType))
if uploader == nil {
liberr.ErrIsNil(ctx, errors.New("没有找到上传适配器"))
}
res, err = uploader.CheckMultipart(ctx, req)
liberr.ErrIsNil(ctx, err)
})
return
}
func (s *sUpload) UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
uploader := upload.GetUploader(upload.UploaderType(req.DriverType))
if uploader == nil {
liberr.ErrIsNil(ctx, errors.New("没有找到上传适配器"))
}
res, err = uploader.UploadPart(ctx, req)
liberr.ErrIsNil(ctx, err)
//保存上传文件到数据库
if res != nil && res.Finish {
err = service.SysAttachment().AddUpload(ctx, res.Attachment, &model.SysAttachmentAddAttribute{
Md5: req.Md5,
Driver: gconv.Uint(req.DriverType),
UserId: req.UserId,
AppId: req.AppId,
})
liberr.ErrIsNil(ctx, err)
}
})
return
}

View File

@@ -0,0 +1,34 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/model/entity/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package do
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysAttachment is the golang structure for table sys_attachment.
type SysAttachment struct {
gmeta.Meta `orm:"table:sys_attachment, do:true"`
Id interface{} `orm:"id,primary" json:"id"` // 文件ID
AppId interface{} `orm:"app_id" json:"appId"` // 应用ID
Drive interface{} `orm:"drive" json:"drive"` // 上传驱动
Name interface{} `orm:"name" json:"name"` // 文件原始名
Kind interface{} `orm:"kind" json:"kind"` // 上传类型
MimeType interface{} `orm:"mime_type" json:"mimeType"` // 扩展类型
Path interface{} `orm:"path" json:"path"` // 本地路径
Size interface{} `orm:"size" json:"size"` // 文件大小
Ext interface{} `orm:"ext" json:"ext"` // 扩展名
Md5 interface{} `orm:"md5" json:"md5"` // md5校验码
CreatedBy interface{} `orm:"created_by" json:"createdBy"` // 上传人ID
Status interface{} `orm:"status" json:"status"` // 状态
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 修改时间
}

View File

@@ -0,0 +1,34 @@
// ==========================================================================
// GFast自动生成model entity操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/model/entity/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysAttachment is the golang structure for table sys_attachment.
type SysAttachment struct {
gmeta.Meta `orm:"table:sys_attachment"`
Id int64 `orm:"id,primary" json:"id"` // 文件ID
AppId string `orm:"app_id" json:"appId"` // 应用ID
Drive string `orm:"drive" json:"drive"` // 上传驱动
Name string `orm:"name" json:"name"` // 文件原始名
Kind string `orm:"kind" json:"kind"` // 上传类型
MimeType string `orm:"mime_type" json:"mimeType"` // 扩展类型
Path string `orm:"path" json:"path"` // 本地路径
Size int64 `orm:"size" json:"size"` // 文件大小
Ext string `orm:"ext" json:"ext"` // 扩展名
Md5 string `orm:"md5" json:"md5"` // md5校验码
CreatedBy int64 `orm:"created_by" json:"createdBy"` // 上传人ID
Status bool `orm:"status" json:"status"` // 状态
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"` // 修改时间
}

View File

@@ -0,0 +1,110 @@
// ==========================================================================
// GFast自动生成model操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/model/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package model
import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gmeta"
)
// SysAttachmentInfoRes is the golang structure for table sys_attachment.
type SysAttachmentInfoRes struct {
gmeta.Meta `orm:"table:sys_attachment"`
Id int64 `orm:"id,primary" json:"id" dc:"文件ID"` // 文件ID
AppId string `orm:"app_id" json:"appId" dc:"应用ID"` // 应用ID
Drive uint `orm:"drive" json:"drive" dc:"上传驱动"` // 上传驱动
Name string `orm:"name" json:"name" dc:"文件原始名"` // 文件原始名
Kind string `orm:"kind" json:"kind" dc:"上传类型"` // 上传类型
MimeType string `orm:"mime_type" json:"mimeType" dc:"扩展类型"` // 扩展类型
Path string `orm:"path" json:"path" dc:"本地路径"` // 本地路径
Size int64 `orm:"size" json:"size" dc:"文件大小"` // 文件大小
Ext string `orm:"ext" json:"ext" dc:"扩展名"` // 扩展名
Md5 string `orm:"md5" json:"md5" dc:"md5校验码"` // md5校验码
CreatedBy int64 `orm:"created_by" json:"createdBy" dc:"上传人ID"` // 上传人ID
CreatedUser LinkUserRes `orm:"with:id=created_by" json:"createdUser"`
Status bool `orm:"status" json:"status" dc:"状态"` // 状态
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt" dc:"创建时间"` // 创建时间
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt" dc:"修改时间"` // 修改时间
}
type LinkUserRes struct {
gmeta.Meta `orm:"table:sys_user"`
Id uint64 `orm:"id" json:"id"`
UserNickname string `orm:"user_nickname" json:"userNickname"`
}
type SysAttachmentListRes struct {
Id int64 `json:"id" dc:"文件ID"`
AppId string `json:"appId" dc:"应用ID"`
Drive uint `json:"drive" dc:"上传驱动"`
Name string `json:"name" dc:"文件原始名"`
Kind string `json:"kind" dc:"上传类型"`
Path string `json:"path" dc:"本地路径"`
Size int64 `json:"size" dc:"文件大小"`
Ext string `json:"ext" dc:"扩展名"`
Status bool `json:"status" dc:"状态"`
CreatedAt *gtime.Time `json:"createdAt" dc:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" dc:"修改时间"`
}
// SysAttachmentSearchReq 分页请求参数
type SysAttachmentSearchReq struct {
PageReq
AppId string `p:"appId" dc:"应用ID"` //应用ID
Drive string `p:"drive" dc:"上传驱动"` //上传驱动
Name string `p:"name" dc:"文件原始名"` //文件原始名
Kind string `p:"kind" dc:"上传类型"` //上传类型
MimeType string `p:"mimeType" dc:"扩展类型"` //扩展类型
Status string `p:"status" v:"status@boolean#状态需为true/false" dc:"状态"` //状态
CreatedAt []string `p:"createdAt" v:"createdAt@datetime-array#创建时间需为YYYY-MM-DD hh:mm:ss格式" dc:"创建时间"` //创建时间
}
// SysAttachmentSearchRes 列表返回结果
type SysAttachmentSearchRes struct {
ListRes
List []*SysAttachmentListRes `json:"list"`
}
// SysAttachmentAddReq 添加操作请求参数
type SysAttachmentAddReq struct {
AppId string `p:"appId" v:"required#应用ID不能为空" dc:"应用ID"`
Drive uint `p:"drive" dc:"上传驱动"`
Name string `p:"name" v:"required#文件原始名不能为空" dc:"文件原始名"`
Kind string `p:"kind" dc:"上传类型"`
MimeType string `p:"mimeType" dc:"扩展类型"`
Path string `p:"path" dc:"本地路径"`
Size int64 `p:"size" dc:"文件大小"`
Ext string `p:"ext" dc:"扩展名"`
Md5 string `p:"md5" dc:"md5校验码"`
Status bool `p:"status" v:"required#状态不能为空" dc:"状态"`
CreatedBy uint64
}
type SysAttachmentAddAttribute struct {
Md5 string
Driver uint
UserId uint64
AppId string
}
// SysAttachmentEditReq 修改操作请求参数
type SysAttachmentEditReq struct {
Id int64 `p:"id" v:"required#主键ID不能为空" dc:"文件ID"`
AppId uint `p:"appId" v:"required#应用ID不能为空" dc:"应用ID"`
Drive string `p:"drive" dc:"上传驱动"`
Name string `p:"name" v:"required#文件原始名不能为空" dc:"文件原始名"`
Kind string `p:"kind" dc:"上传类型"`
MimeType string `p:"mimeType" dc:"扩展类型"`
Path string `p:"path" dc:"本地路径"`
Size int64 `p:"size" dc:"文件大小"`
Ext string `p:"ext" dc:"扩展名"`
Md5 string `p:"md5" dc:"md5校验码"`
Status bool `p:"status" v:"required#状态不能为空" dc:"状态"`
}

View File

@@ -7,9 +7,60 @@
package model
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
)
type UpFile struct {
Name string `json:"name"`
Url string `json:"url"`
FileType string `json:"fileType"`
Size uint64 `json:"size"`
}
type UploadResponse struct {
Size int64 `json:"size" dc:"文件大小"`
Path string `json:"path" dc:"文件相对路径"`
FullPath string `json:"fullPath" dc:"文件绝对路径"`
Name string `json:"name" dc:"文件名称"`
Type string `json:"type" dc:"文件类型"`
}
// CheckMultipartReq 检查文件分片
type CheckMultipartReq struct {
UploadType string `p:"uploadType" dc:"文件类型"`
FileName string `p:"fileName" dc:"文件名称"`
Size int64 `p:"size" dc:"文件大小"`
Md5 string `p:"md5" dc:"文件md5值"`
ShardsCount int `p:"shardsCount" dc:"分片数量"`
DriverType int //上传驱动
UserId uint64
AppId string
}
type CheckMultipartRes struct {
Attachment *UploadResponse `json:"attachment" dc:"附件"`
WaitUploadIndex []int `json:"waitUploadIndex" dc:"等待上传的分片索引"`
Progress float64 `json:"progress" dc:"上传进度"`
}
// UploadPartReq 分片上传
type UploadPartReq struct {
*CheckMultipartReq
Index int `p:"index" dc:"分片索引"`
File *ghttp.UploadFile `p:"file" type:"file" dc:"分片文件"`
}
type UploadPartRes struct {
Attachment *UploadResponse `json:"attachment" dc:"附件"`
Finish bool `json:"finish" dc:"是否完成"`
}
// MultipartProgress 分片进度
type MultipartProgress struct {
UploadId string `json:"uploadId"` // 上传事件ID
ShardCount int `json:"shardCount"` // 分片数量
UploadedIndex []int `json:"uploadedIndex"` // 已上传的分片索引
CreatedAt *gtime.Time `json:"createdAt"` // 创建时间
}

View File

@@ -1,30 +0,0 @@
// ================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package service
import (
"context"
"github.com/tiger1103/gfast/v3/api/v1/system"
)
type IBigUpload interface {
Upload(ctx context.Context, req *system.BigUploadReq) (res *system.BigUploadRes, err error)
UploadCheck(ctx context.Context, req *system.BigUploadCheckReq) (res *system.BigUploadCheckRes, err error)
UploadMerge(ctx context.Context, req *system.BigUploadMergeReq) (res *system.BigUploadRes, err error)
}
var localBigUpload IBigUpload
func BigUpload() IBigUpload {
if localBigUpload == nil {
panic("implement not found for interface IBigUpload, forgot register?")
}
return localBigUpload
}
func RegisterBigUpload(i IBigUpload) {
localBigUpload = i
}

View File

@@ -0,0 +1,40 @@
// ==========================================================================
// GFast自动生成service操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/service/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package service
import (
"context"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
)
type ISysAttachment interface {
List(ctx context.Context, req *model.SysAttachmentSearchReq) (res *model.SysAttachmentSearchRes, err error)
GetById(ctx context.Context, Id int64) (res *model.SysAttachmentInfoRes, err error)
GetByMd5(ctx context.Context, md5 string) (res *model.SysAttachmentInfoRes, err error)
AddUpload(ctx context.Context, req *model.UploadResponse, attr *model.SysAttachmentAddAttribute) (err error)
Add(ctx context.Context, req *model.SysAttachmentAddReq) (err error)
Edit(ctx context.Context, req *model.SysAttachmentEditReq) (err error)
Delete(ctx context.Context, Id []int64) (err error)
// 附件管理状态修改(状态)
ChangeStatus(ctx context.Context, id int64, status bool) (err error)
}
var localSysAttachment ISysAttachment
func SysAttachment() ISysAttachment {
if localSysAttachment == nil {
panic("implement not found for interface ISysAttachment, forgot register?")
}
return localSysAttachment
}
func RegisterSysAttachment(i ISysAttachment) {
localSysAttachment = i
}

View File

@@ -7,16 +7,18 @@ package service
import (
"context"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/gogf/gf/v2/net/ghttp"
)
type IUpload interface {
UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int) (result system.UploadMultipleRes, err error)
UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int) (result system.UploadResponse, err error)
CheckSize(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error)
CheckType(ctx context.Context, checkFileType string, file *ghttp.UploadFile) (err error)
UploadFiles(ctx context.Context, files []*ghttp.UploadFile, checkFileType string, source int, userId uint64, appId string) (result []*model.UploadResponse, err error)
UploadFile(ctx context.Context, file *ghttp.UploadFile, checkFileType string, source int, userId uint64, appId string) (result *model.UploadResponse, err error)
CheckSize(ctx context.Context, checkFileType string, fileSize int64) (err error)
CheckType(ctx context.Context, checkFileType string, fileName string) (err error)
CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error)
UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error)
}
var localUpload IUpload

View File

@@ -17,4 +17,7 @@ const (
WebsocketTypeTokenUpdated = "tokenUpdated"
// WebsocketTypeNotice websocket通知类型-系统通知
WebsocketTypeNotice = "notice"
// UploadAppId 上传应用ID
UploadAppId = "system"
)

View File

@@ -1,38 +0,0 @@
package controller
import (
"context"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
type bigFile struct{}
var BigFile = new(bigFile)
func (c *bigFile) List(ctx context.Context, req *system.BigFileSearchReq) (res *system.BigFileSearchRes, err error) {
return service.BigFile().List(ctx, req)
}
// Add 添加系统参数
func (c *bigFile) Add(ctx context.Context, req *system.BigFileAddReq) (res *system.BigFileAddRes, err error) {
err = service.BigFile().Add(ctx, req, service.Context().GetUserId(ctx))
return
}
// Get 获取文件信息
func (c *bigFile) Get(ctx context.Context, req *system.BigFileGetReq) (res *system.BigFileGetRes, err error) {
return service.BigFile().Get(ctx, req.Id)
}
// Edit 修改系统参数
func (c *bigFile) Edit(ctx context.Context, req *system.BigFileEditReq) (res *system.BigFileEditRes, err error) {
err = service.BigFile().Edit(ctx, req, service.Context().GetUserId(ctx))
return
}
// Delete 删除系统参数
func (c *bigFile) Delete(ctx context.Context, req *system.BigFileDeleteReq) (res *system.BigFileDeleteRes, err error) {
err = service.BigFile().Delete(ctx, req.Ids)
return
}

View File

@@ -1,45 +0,0 @@
package controller
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
)
var BigUpload = new(bigUploadController)
type bigUploadController struct{}
// 上传分片文件
func (c *bigUploadController) Upload(ctx context.Context, req *system.BigUploadReq) (res *system.BigUploadRes, err error) {
r := g.RequestFromCtx(ctx)
req = new(system.BigUploadReq)
err = req.Bind(r.Request)
if err != nil {
return
}
return service.BigUpload().Upload(ctx, req)
}
// 上传文件检查
func (c *bigUploadController) UploadCheck(ctx context.Context, req *system.BigUploadCheckReq) (res *system.BigUploadCheckRes, err error) {
r := g.RequestFromCtx(ctx)
req = new(system.BigUploadCheckReq)
err = req.Bind(r.Request)
if err != nil {
return
}
return service.BigUpload().UploadCheck(ctx, req)
}
// 上传文件合并
func (c *bigUploadController) UploadMerge(ctx context.Context, req *system.BigUploadMergeReq) (res *system.BigUploadRes, err error) {
r := g.RequestFromCtx(ctx)
req = new(system.BigUploadMergeReq)
err = req.Bind(r.Request)
if err != nil {
return
}
return service.BigUpload().UploadMerge(ctx, req)
}

View File

@@ -0,0 +1,67 @@
// ==========================================================================
// GFast自动生成controller操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/controller/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package controller
import (
"context"
"errors"
"github.com/tiger1103/gfast/v3/api/v1/system"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
type sysAttachmentController struct {
BaseController
}
var SysAttachment = new(sysAttachmentController)
// List 列表
func (c *sysAttachmentController) List(ctx context.Context, req *system.SysAttachmentSearchReq) (res *system.SysAttachmentSearchRes, err error) {
res = new(system.SysAttachmentSearchRes)
res.SysAttachmentSearchRes, err = commonService.SysAttachment().List(ctx, &req.SysAttachmentSearchReq)
return
}
// Get 获取附件管理
func (c *sysAttachmentController) Get(ctx context.Context, req *system.SysAttachmentGetReq) (res *system.SysAttachmentGetRes, err error) {
res = new(system.SysAttachmentGetRes)
res.SysAttachmentInfoRes, err = commonService.SysAttachment().GetById(ctx, req.Id)
return
}
// Add 添加附件管理
func (c *sysAttachmentController) Add(ctx context.Context, req *system.SysAttachmentAddReq) (res *system.SysAttachmentAddRes, err error) {
req.CreatedBy = service.Context().GetUserId(ctx)
err = commonService.SysAttachment().Add(ctx, req.SysAttachmentAddReq)
return
}
// Edit 修改附件管理
func (c *sysAttachmentController) Edit(ctx context.Context, req *system.SysAttachmentEditReq) (res *system.SysAttachmentEditRes, err error) {
err = commonService.SysAttachment().Edit(ctx, req.SysAttachmentEditReq)
return
}
// Delete 删除附件管理
func (c *sysAttachmentController) Delete(ctx context.Context, req *system.SysAttachmentDeleteReq) (res *system.SysAttachmentDeleteRes, err error) {
err = commonService.SysAttachment().Delete(ctx, req.Ids)
return
}
// 附件管理状态修改(状态)
func (c *sysAttachmentController) ChangeStatus(ctx context.Context, req *system.SysAttachmentStatusSwitchReq) (res *system.SysAttachmentStatusSwitchRes, err error) {
if !service.SysUser().AccessRule(ctx, service.Context().GetUserId(ctx), "api/v1/system/sysAttachment/edit") {
err = errors.New("没有修改权限")
return
}
err = commonService.SysAttachment().ChangeStatus(ctx, req.Id, req.Status)
return
}

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/model/entity"
@@ -136,6 +137,6 @@ func (c *userController) GetUserSelector(ctx context.Context, req *system.UserSe
// GetByIds 根据id 获取用户信息
func (c *userController) GetByIds(ctx context.Context, req *system.UserByIdsReq) (res *system.UserByIdsRes, err error) {
res = new(system.UserByIdsRes)
res.UserList, err = service.SysUser().GetUsers(ctx, req.Ids)
res.UserList, err = service.SysUser().GetUsers(ctx, gconv.Interfaces(req.Ids))
return
}

View File

@@ -15,8 +15,13 @@ import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/consts"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
commonConsts "github.com/tiger1103/gfast/v3/internal/app/common/consts"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libUtils"
"math"
)
var UEditor = new(uEditorController)
@@ -49,13 +54,43 @@ func (c *uEditorController) action(ctx context.Context, req *system.UEditorReq)
//上传视频 上传文件
case "uploadvideo", "uploadfile":
c.uEditorUpload(ctx, req.File, "file")
//列出图片 列出文件
case "listimage", "listfile":
//列出图片
case "listimage":
var (
list g.List
total interface{} = 0
)
list, total, err = c.getFileList(ctx, req.Start, req.Size, "image")
if err != nil {
r.Response.WriteJson(g.Map{
"state": err.Error(),
})
r.Exit()
}
r.Response.WriteJson(g.Map{
"state": "SUCCESS",
"total": 0,
"start": 0,
"list": g.Slice{},
"total": total,
"start": req.Start,
"list": list,
})
//列出文件
case "listfile":
var (
list g.List
total interface{} = 0
)
list, total, err = c.getFileList(ctx, req.Start, req.Size, "")
if err != nil {
r.Response.WriteJson(g.Map{
"state": err.Error(),
})
r.Exit()
}
r.Response.WriteJson(g.Map{
"state": "SUCCESS",
"total": total,
"start": req.Start,
"list": list,
})
//抓取远端图片
case "catchimage":
@@ -67,6 +102,7 @@ func (c *uEditorController) action(ctx context.Context, req *system.UEditorReq)
"state": "请求地址出错",
})
}
r.Exit()
return
}
@@ -172,15 +208,15 @@ func (c *uEditorController) ueditorConfig(ctx context.Context, callback string)
// ueditor上传图片
func (c *uEditorController) uEditorUpload(ctx context.Context, upFile *ghttp.UploadFile, fType string) {
var (
info system.UploadResponse
info *model.UploadResponse
err error
r = g.RequestFromCtx(ctx)
)
v, _ := g.Cfg().Get(ctx, "upload.default")
if fType == "image" {
info, err = service.Upload().UploadFile(ctx, upFile, consts.CheckFileTypeImg, v.Int())
info, err = commonService.Upload().UploadFile(ctx, upFile, commonConsts.CheckFileTypeImg, v.Int(), service.Context().Get(ctx).User.Id, consts.UploadAppId)
} else if fType == "file" {
info, err = service.Upload().UploadFile(ctx, upFile, consts.CheckFileTypeFile, v.Int())
info, err = commonService.Upload().UploadFile(ctx, upFile, commonConsts.CheckFileTypeFile, v.Int(), service.Context().Get(ctx).User.Id, consts.UploadAppId)
}
if err != nil {
@@ -197,3 +233,37 @@ func (c *uEditorController) uEditorUpload(ctx context.Context, upFile *ghttp.Upl
}
r.Exit()
}
func (c *uEditorController) getFileList(ctx context.Context, start int, size int, kind string) (list g.List, total interface{}, err error) {
var res *model.SysAttachmentSearchRes
pageNum := gconv.Int(math.Ceil(gconv.Float64(start)/gconv.Float64(size)) + 1)
res, err = commonService.SysAttachment().List(ctx, &model.SysAttachmentSearchReq{
PageReq: model.PageReq{
PageNum: pageNum,
PageSize: size,
},
Kind: kind,
Status: "true",
})
if err != nil {
return
}
if res != nil {
total = res.Total
list = make(g.List, len(res.List))
for k, v := range res.List {
path := ""
if v.Drive == commonConsts.UploadDriverLocal {
path = libUtils.GetDomain(ctx, true) + "/" + v.Path
} else {
path = v.Path
}
list[k] = g.Map{
"url": path,
"mtime": v.UpdatedAt.Timestamp(),
}
}
}
return
}

View File

@@ -4,8 +4,10 @@ import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/consts"
"github.com/tiger1103/gfast/v3/internal/app/common/service"
commonConsts "github.com/tiger1103/gfast/v3/internal/app/common/consts"
commonService "github.com/tiger1103/gfast/v3/internal/app/common/service"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
)
var Upload = new(uploadController)
@@ -16,26 +18,28 @@ type uploadController struct{}
func (c *uploadController) SingleImg(ctx context.Context, req *system.UploadSingleImgReq) (res *system.UploadSingleRes, err error) {
file := req.File
v, _ := g.Cfg().Get(ctx, "upload.default")
response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeImg, v.Int())
response, err := commonService.Upload().UploadFile(ctx, file, commonConsts.CheckFileTypeImg, v.Int(), service.Context().Get(ctx).User.Id, consts.UploadAppId)
if err != nil {
return
}
res = &system.UploadSingleRes{
UploadResponse: response,
}
// 上传第三方
return
}
// 上传多图
func (c *uploadController) MultipleImg(ctx context.Context, req *system.UploadMultipleImgReq) (res *system.UploadMultipleRes, err error) {
func (c *uploadController) MultipleImg(ctx context.Context, req *system.UploadMultipleImgReq) (res system.UploadMultipleRes, err error) {
files := req.File
v, _ := g.Cfg().Get(ctx, "upload.default")
mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeImg, v.Int())
res, err = commonService.Upload().UploadFiles(ctx,
files,
commonConsts.CheckFileTypeImg,
g.Cfg().MustGet(ctx, "upload.default").Int(),
service.Context().Get(ctx).User.Id,
consts.UploadAppId)
if err != nil {
return
}
res = &mf
return
}
@@ -43,7 +47,7 @@ func (c *uploadController) MultipleImg(ctx context.Context, req *system.UploadMu
func (c *uploadController) SingleFile(ctx context.Context, req *system.UploadSingleFileReq) (res *system.UploadSingleRes, err error) {
file := req.File
v, _ := g.Cfg().Get(ctx, "upload.default")
response, err := service.Upload().UploadFile(ctx, file, consts.CheckFileTypeFile, v.Int())
response, err := commonService.Upload().UploadFile(ctx, file, commonConsts.CheckFileTypeFile, v.Int(), service.Context().Get(ctx).User.Id, consts.UploadAppId)
if err != nil {
return
}
@@ -54,13 +58,36 @@ func (c *uploadController) SingleFile(ctx context.Context, req *system.UploadSin
}
// 上传多文件
func (c *uploadController) MultipleFile(ctx context.Context, req *system.UploadMultipleFileReq) (res *system.UploadMultipleRes, err error) {
func (c *uploadController) MultipleFile(ctx context.Context, req *system.UploadMultipleFileReq) (res system.UploadMultipleRes, err error) {
files := req.File
v, _ := g.Cfg().Get(ctx, "upload.default")
mf, err := service.Upload().UploadFiles(ctx, files, consts.CheckFileTypeFile, v.Int())
res, err = commonService.Upload().UploadFiles(ctx,
files,
commonConsts.CheckFileTypeFile,
g.Cfg().MustGet(ctx, "upload.default").Int(),
service.Context().Get(ctx).User.Id,
consts.UploadAppId)
if err != nil {
return
}
res = &mf
return
}
func (c *uploadController) CheckMultipart(ctx context.Context, req *system.CheckMultipartReq) (res *system.CheckMultipartRes, err error) {
req.DriverType = g.Cfg().MustGet(ctx, "upload.default").Int()
req.UploadType = commonConsts.CheckFileTypeFile
req.UserId = service.Context().Get(ctx).User.Id
req.AppId = consts.UploadAppId
res = new(system.CheckMultipartRes)
res.CheckMultipartRes, err = commonService.Upload().CheckMultipart(ctx, req.CheckMultipartReq)
return
}
func (c *uploadController) UploadPart(ctx context.Context, req *system.UploadPartReq) (res *system.UploadPartRes, err error) {
res = new(system.UploadPartRes)
req.DriverType = g.Cfg().MustGet(ctx, "upload.default").Int()
req.UploadType = commonConsts.CheckFileTypeFile
req.UserId = service.Context().Get(ctx).User.Id
req.AppId = consts.UploadAppId
res.UploadPartRes, err = commonService.Upload().UploadPart(ctx, req.UploadPartReq)
return
}

View File

@@ -1,27 +0,0 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"github.com/tiger1103/gfast/v3/internal/app/system/dao/internal"
)
// internalBigFileDao is internal type for wrapping internal DAO implements.
type internalBigFileDao = *internal.BigFileDao
// bigFileDao is the data access object for table big_file.
// You can define custom methods on it to extend its functionality as you wish.
type bigFileDao struct {
internalBigFileDao
}
var (
// BigFile is globally public accessible object for table big_file operations.
BigFile = bigFileDao{
internal.NewBigFileDao(),
}
)
// Fill with you ideas below.

View File

@@ -1,98 +0,0 @@
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// BigFileDao is the data access object for table big_file.
type BigFileDao struct {
table string // table is the underlying table name of the DAO.
group string // group is the database configuration group name of current DAO.
columns BigFileColumns // columns contains all the column names of Table for convenient usage.
}
// BigFileColumns defines and stores column names for table big_file.
type BigFileColumns struct {
Id string //
Name string // 文件名称
Size string // 文件大小
Path string // 文件相对路径
FullPath string // 文件绝对路径
MimeType string // 文件类型
Source string // 文件来源 0 - 本地1 - 腾讯云 2 - 七牛云
Describe string // 描述
Md5 string // md5
CreatedBy string //
UpdatedBy string //
CreatedAt string //
UpdatedAt string //
DeletedAt string //
}
// bigFileColumns holds the columns for table big_file.
var bigFileColumns = BigFileColumns{
Id: "id",
Name: "name",
Size: "size",
Path: "path",
FullPath: "full_path",
MimeType: "mime_type",
Source: "source",
Describe: "describe",
Md5: "md5",
CreatedBy: "created_by",
UpdatedBy: "updated_by",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewBigFileDao creates and returns a new DAO object for table data access.
func NewBigFileDao() *BigFileDao {
return &BigFileDao{
group: "default",
table: "big_file",
columns: bigFileColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *BigFileDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *BigFileDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *BigFileDao) Columns() BigFileColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *BigFileDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *BigFileDao) Ctx(ctx context.Context) *gdb.Model {
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
}
// Transaction wraps the transaction logic using function f.
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
// It commits the transaction and returns nil if function f returns nil.
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *BigFileDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@@ -10,12 +10,14 @@
package logic
import (
"bytes"
"context"
"database/sql"
"errors"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
@@ -25,6 +27,9 @@ import (
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/library/libWebsocket"
"github.com/tiger1103/gfast/v3/library/liberr"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
"strings"
)
func init() {
@@ -144,10 +149,79 @@ func (s *sSysNotice) ListShow(ctx context.Context, req *model.SysNoticeSearchReq
err = m.Page(req.PageNum, req.PageSize).Fields("" +
"n.*,nr.id IS NOT NULL as isRead").Order(order).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
if req.IsTrim {
for k, v := range res {
v.Content = s.extractTextFromHTML(v.Content)
if gstr.LenRune(v.Content) > 90 {
res[k].Content = gstr.SubStrRune(v.Content, 0, 90) + "..."
}
}
}
listRes.List = res
})
return
}
// extractParagraphsFromHTML extracts text from all <p> tags in the HTML, ignoring <img> and other non-text nodes, and decodes HTML entities.
func (s *sSysNotice) extractTextFromHTML(htmlStr string) string {
// Parse the HTML
doc, err := html.Parse(strings.NewReader(htmlStr))
if err != nil {
return htmlStr
}
// Create a slice to store the extracted paragraphs
var paragraphs []string
// Helper function to recursively traverse nodes and collect text content into a buffer
var collectText func(*html.Node, *bytes.Buffer)
collectText = func(n *html.Node, buf *bytes.Buffer) {
switch n.Type {
case html.TextNode:
// Append the text content to the buffer
buf.WriteString(n.Data)
case html.ElementNode:
// Recursively traverse child nodes, but ignore <img> and other non-text-producing elements
// Note: In a more sophisticated implementation, you might want to handle other elements like <br>, <strong>, etc.
if n.DataAtom != atom.Img && n.DataAtom != atom.Script && n.DataAtom != atom.Style {
for c := n.FirstChild; c != nil; c = c.NextSibling {
collectText(c, buf)
}
}
}
}
// Define a function to recursively traverse nodes and collect text from <p> tags
var traverseNodes func(*html.Node)
traverseNodes = func(n *html.Node) {
// Check the type of the node
switch n.Type {
case html.ElementNode:
// Check if the node is a <p> tag
if n.DataAtom == atom.P {
// Create a buffer to store the text content of the <p> tag
var textBuf bytes.Buffer
collectText(n, &textBuf)
// Decode HTML entities in the collected text and add it to the paragraphs slice
paragraphs = append(paragraphs, html.UnescapeString(strings.TrimSpace(textBuf.String())))
} else {
// For other tags, just recursively traverse their children
for c := n.FirstChild; c != nil; c = c.NextSibling {
traverseNodes(c)
}
}
}
}
for n := doc; n != nil; n = n.NextSibling {
if n.Type == html.DocumentNode {
traverseNodes(n.FirstChild) // Start traversal from the first child of the document node (which is usually the <html> tag)
break
}
}
return strings.Join(paragraphs, "")
}
func (s *sSysNotice) GetById(ctx context.Context, id int64) (res *model.SysNoticeInfoRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysNotice.Ctx(ctx).WithAll().Where(dao.SysNotice.Columns().Id, id).Scan(&res)

View File

@@ -908,13 +908,13 @@ func (s *sSysUser) Delete(ctx context.Context, ids []int) (err error) {
}
// GetUsers 通过用户ids查询多个用户信息
func (s *sSysUser) GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error) {
func (s *sSysUser) GetUsers(ctx context.Context, ids []interface{}) (users []*model.SysUserSimpleRes, err error) {
if len(ids) == 0 {
return
}
idsSet := gset.NewIntSetFrom(ids).Slice()
idsSet := gset.NewFrom(ids).Slice()
err = g.Try(ctx, func(ctx context.Context) {
err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id+" in(?)", idsSet).
err = dao.SysUser.Ctx(ctx).Where(dao.SysUser.Columns().Id, idsSet).
Order(dao.SysUser.Columns().Id + " ASC").Scan(&users)
})
return
@@ -1182,7 +1182,7 @@ func (s *sSysUser) GetAuthDeptDataWhere(ctx context.Context, m *gdb.Model, userI
deptIdArr.Add(gconv.Int64(li["id"]))
}
case 5: //仅本人数据权限
whereJustMe = g.Map{deptField: userInfo.Id, createdUserField: userInfo.Id}
whereJustMe = g.Map{deptField: userInfo.DeptId, createdUserField: userInfo.Id}
}
}
}

View File

@@ -176,7 +176,9 @@ func (s *sToolsGenTable) SelectDbTableListByNames(ctx context.Context, tableName
err := db.GetScan(ctx, &result, sqlStr)
liberr.ErrIsNil(ctx, err, "获取表格信息失败")
} else if s.IsPg() {
sqlStr = "select * from information_schema.tables WHERE table_schema = current_schema() " +
sqlStr = "select information_schema.tables.*,obj_description(pg_class.oid) AS table_comment " +
" from information_schema.tables JOIN pg_class ON pg_class.relname = table_name " +
" WHERE table_schema = current_schema() " +
"AND table_name NOT LIKE 'tools_gen_%' "
if len(tableNames) > 0 {
in := gstr.TrimRight(gstr.Repeat("?,", len(tableNames)), ",")

View File

@@ -1,29 +0,0 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// BigFile is the golang structure of table big_file for DAO operations like Where/Data.
type BigFile struct {
g.Meta `orm:"table:big_file, do:true"`
Id interface{} //
Name interface{} // 文件名称
Size interface{} // 文件大小
Path interface{} // 文件相对路径
FullPath interface{} // 文件绝对路径
MimeType interface{} // 文件类型
Source interface{} // 文件来源 0 - 本地1 - 腾讯云 2 - 七牛云
Describe interface{} // 描述
Md5 interface{} // md5
CreatedBy interface{} //
UpdatedBy interface{} //
CreatedAt *gtime.Time //
UpdatedAt *gtime.Time //
DeletedAt *gtime.Time //
}

View File

@@ -1,27 +0,0 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// BigFile is the golang structure for table big_file.
type BigFile struct {
Id uint64 `json:"id" description:""`
Name string `json:"name" description:"文件名称"`
Size int `json:"size" description:"文件大小"`
Path string `json:"path" description:"文件相对路径"`
FullPath string `json:"fullPath" description:"文件绝对路径"`
MimeType string `json:"mimeType" description:"文件类型"`
Source int `json:"source" description:"文件来源 0 - 本地1 - 腾讯云 2 - 七牛云"`
Describe string `json:"describe" description:"描述"`
Md5 string `json:"md5" description:"md5"`
CreatedBy uint64 `json:"createdBy" description:""`
UpdatedBy uint64 `json:"updatedBy" description:""`
CreatedAt *gtime.Time `json:"createdAt" description:""`
UpdatedAt *gtime.Time `json:"updatedAt" description:""`
DeletedAt *gtime.Time `json:"deletedAt" description:""`
}

View File

@@ -62,6 +62,7 @@ type SysNoticeSearchReq struct {
Tag string `p:"tag" v:"tag@integer#标签需为整数" dc:"标签"` //标签
Status string `p:"status" v:"status@integer#状态需为整数" dc:"状态"` //状态
CreatedAt string `p:"createdAt" v:"createdAt@datetime#创建时间需为YYYY-MM-DD hh:mm:ss格式" dc:"创建时间"` //创建时间
IsTrim bool `p:"isTrim"`
}
// SysNoticeSearchRes 列表返回结果

View File

@@ -48,13 +48,11 @@ func (router *Router) BindController(ctx context.Context, group *ghttp.RouterGro
controller.Monitor,
controller.LoginLog,
controller.OperLog,
controller.BigFile,
controller.ToolsGenTable,
controller.Personal,
controller.UserOnline,
controller.Cache, // 缓存处理
controller.Upload, // 普通文件上传
controller.BigUpload, // 大文件上传
controller.UEditor, //编辑器
)
//自动绑定定义的控制器

View File

@@ -0,0 +1,25 @@
// ==========================================================================
// GFast自动生成router操作代码。
// 生成日期2024-10-23 16:10:12
// 生成路径: internal/app/system/router/sys_attachment.go
// 生成人gfast
// desc:附件管理
// company:云南奇讯科技有限公司
// ==========================================================================
package router
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/internal/app/system/controller"
)
func (router *Router) BindSysAttachmentController(ctx context.Context, group *ghttp.RouterGroup) {
group.Group("/sysAttachment", func(group *ghttp.RouterGroup) {
group.Bind(
controller.SysAttachment,
)
})
}

View File

@@ -1,101 +0,0 @@
package service
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
systemConsts "github.com/tiger1103/gfast/v3/internal/app/system/consts"
"github.com/tiger1103/gfast/v3/library/liberr"
)
type IBigFile interface {
List(ctx context.Context, req *system.BigFileSearchReq) (res *system.BigFileSearchRes, err error)
Add(ctx context.Context, req *system.BigFileAddReq, userId uint64) (err error)
Get(ctx context.Context, id uint64) (res *system.BigFileGetRes, err error)
Edit(ctx context.Context, req *system.BigFileEditReq, userId uint64) (err error)
Delete(ctx context.Context, ids []uint64) (err error)
}
func BigFile() IBigFile {
return new(bigFileTmpl)
}
type bigFileTmpl struct{}
func (s *bigFileTmpl) List(ctx context.Context, req *system.BigFileSearchReq) (res *system.BigFileSearchRes, err error) {
res = new(system.BigFileSearchRes)
err = g.Try(ctx, func(ctx context.Context) {
m := dao.BigFile.Ctx(ctx)
if req != nil {
if req.Name != "" {
m = m.Where("name like ?", "%"+req.Name+"%")
}
}
res.Total, err = m.Count()
liberr.ErrIsNil(ctx, err, "获取数据失败")
if req.PageNum == 0 {
req.PageNum = 1
}
res.CurrentPage = req.PageNum
if req.PageSize == 0 {
req.PageSize = systemConsts.PageSize
}
var orderBy string = "id asc"
if req.OrderBy != "" {
orderBy = req.OrderBy
}
err = m.Page(req.PageNum, req.PageSize).Order(orderBy).Scan(&res.List)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
func (s *bigFileTmpl) Add(ctx context.Context, req *system.BigFileAddReq, userId uint64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.BigFile.Ctx(ctx).Insert(do.BigFile{
Name: req.Name,
Size: req.Size,
Path: req.Path,
FullPath: req.FullPath,
MimeType: req.MimeType,
Source: req.Source,
Describe: req.Describe,
Md5: req.Md5,
})
liberr.ErrIsNil(ctx, err, "添加失败")
})
return
}
func (s *bigFileTmpl) Get(ctx context.Context, id uint64) (res *system.BigFileGetRes, err error) {
res = new(system.BigFileGetRes)
err = g.Try(ctx, func(ctx context.Context) {
err = dao.BigFile.Ctx(ctx).WherePri(id).Scan(&res)
liberr.ErrIsNil(ctx, err, "获取数据失败")
})
return
}
func (s *bigFileTmpl) Edit(ctx context.Context, req *system.BigFileEditReq, userId uint64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.BigFile.Ctx(ctx).WherePri(req.Id).Update(do.BigFile{
Name: req.Name,
Describe: req.Describe,
})
liberr.ErrIsNil(ctx, err, "修改错误")
})
return
}
func (s *bigFileTmpl) Delete(ctx context.Context, ids []uint64) (err error) {
err = g.Try(ctx, func(ctx context.Context) {
_, err = dao.BigFile.Ctx(ctx).WherePri(ids).Delete()
liberr.ErrIsNil(ctx, err, "删除失败")
})
return
}

View File

@@ -51,7 +51,7 @@ type (
ResetUserPwd(ctx context.Context, req *system.UserResetPwdReq) (err error)
ChangeUserStatus(ctx context.Context, req *system.UserStatusReq) (err error)
Delete(ctx context.Context, ids []int) (err error)
GetUsers(ctx context.Context, ids []int) (users []*model.SysUserSimpleRes, err error)
GetUsers(ctx context.Context, ids []interface{}) (users []*model.SysUserSimpleRes, err error)
// Deprecated : 此方法已废弃请使用更简单的GetAuthWhere方法或GetAuthDeptWhere方法
GetDataWhere(ctx context.Context, userInfo *model.ContextUser, entityData interface{}, menuId uint) (where g.Map, err error)
HasAccessByDataWhere(ctx context.Context, where g.Map, uid interface{}) bool

View File

@@ -11,10 +11,8 @@ import (
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/text/gstr"
"github.com/tiger1103/gfast/v3/internal/consts"
"github.com/tiger1103/gfast/v3/internal/mounter"
"github.com/tiger1103/gfast/v3/internal/router"
"github.com/tiger1103/gfast/v3/library/libValidate"
"github.com/tiger1103/gfast/v3/library/upload"
"github.com/tiger1103/gfast/v3/task"
)
var (
@@ -26,6 +24,8 @@ var (
g.Log().SetFlags(glog.F_ASYNC | glog.F_TIME_DATE | glog.F_TIME_TIME | glog.F_FILE_LONG)
g.Log().Info(ctx, gbase64.MustDecodeString(consts.Logo), "Version:", consts.Version)
s := g.Server()
//调用注册已挂载相关组件
mounter.DoMount(ctx, s)
s.Group("/", func(group *ghttp.RouterGroup) {
router.R.BindController(ctx, group)
})
@@ -43,24 +43,12 @@ var (
}
//重新配置swaggerUI静态页面--end--
enhanceOpenAPIDoc(s)
//注册相关组件
register()
s.Run()
return nil
},
}
)
// 相关组件注册
func register() {
//注册上传组件
upload.Register()
//注册自定义验证规则
libValidate.Register()
//执行计划任务
task.Run()
}
func enhanceOpenAPIDoc(s *ghttp.Server) {
openapi := s.GetOpenApi()
openapi.Config.CommonResponse = ghttp.DefaultHandlerResponse{}

View File

@@ -9,5 +9,5 @@ package consts
const (
Logo = `CiAgIF9fX19fX19fX19fXyAgICAgICAgICAgX18gCiAgLyBfX19fLyBfX19fL19fXyBfX19fX18vIC9fCiAvIC8gX18vIC9fICAvIF9fIGAvIF9fXy8gX18vCi8gL18vIC8gX18vIC8gL18vIChfXyAgKSAvXyAgClxfX19fL18vICAgIFxfXyxfL19fX18vXF9fLyAg`
Version = "3.2.32"
Version = "3.3.0"
)

33
internal/mounter/mount.go Normal file
View File

@@ -0,0 +1,33 @@
/*
* @desc:组件挂载器
* @company:云南奇讯科技有限公司
* @Author: yixiaohu<yxh669@qq.com>
* @Date: 2024/10/25 08:36
*/
package mounter
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"sync"
)
type MountHandler func(ctx context.Context, s *ghttp.Server)
var (
funcOptions = make([]MountHandler, 0)
fLock sync.Mutex
)
func Mount(handler MountHandler) {
fLock.Lock()
defer fLock.Unlock()
funcOptions = append(funcOptions, handler)
}
func DoMount(ctx context.Context, s *ghttp.Server) {
for _, fn := range funcOptions {
fn(ctx, s)
}
}

View File

@@ -32,7 +32,7 @@ func EncryptPassword(password, salt string) string {
}
// GetDomain 获取当前请求接口域名
func GetDomain(ctx context.Context) string {
func GetDomain(ctx context.Context, hasUri ...bool) string {
r := g.RequestFromCtx(ctx)
host := r.Header.Get("X-Forwarded-Host")
if host == "" {
@@ -41,10 +41,21 @@ func GetDomain(ctx context.Context) string {
if host == "" {
host = r.Host
}
host = gstr.ReplaceByArray(host, []string{":80", "", ":443", ""})
scheme := r.Header.Get("X-Scheme")
if scheme == "" {
scheme = r.GetSchema()
}
if len(hasUri) > 0 && hasUri[0] {
uri := r.Header.Get("X-Original-URI")
if uri != "" {
pos := gstr.PosI(uri, "/api/v1")
if pos >= 0 {
uri = gstr.SubStr(uri, 1, pos)
}
}
return fmt.Sprintf("%s://%s%s", scheme, host, uri)
}
return fmt.Sprintf("%s://%s", scheme, host)
}
@@ -185,7 +196,7 @@ func GetType(p string) (result string, err error) {
// GetFilesPath 获取附件相对路径
func GetFilesPath(ctx context.Context, fileUrl string) (path string, err error) {
upType := g.Cfg().MustGet(ctx, "upload.default").Int()
if upType != 0 || (upType == 0 && !gstr.ContainsI(fileUrl, consts.UploadPath)) {
if upType != 0 || (!gstr.ContainsI(fileUrl, consts.UploadPath)) {
path = fileUrl
return
}
@@ -215,3 +226,22 @@ func SliceUnique[T comparable](slice []T) []T {
}
return result
}
// DiffSlice 比较两个切片,返回他们的差集
// slice1 := []int{1, 2, 3, 4, 5}
// slice2 := []int{4, 5, 6, 7, 8}
// fmt.Println(Difference(slice1, slice2)) // Output: [1 2 3]
func DiffSlice[T comparable](s1, s2 []T) []T {
m := make(map[T]bool)
for _, item := range s1 {
m[item] = true
}
var diff []T
for _, item := range s2 {
if _, ok := m[item]; !ok {
diff = append(diff, item)
}
}
return diff
}

View File

@@ -3,14 +3,22 @@ package libValidate
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gvalid"
"github.com/tiger1103/gfast/v3/internal/mounter"
"strconv"
"strings"
)
func init() {
mounter.Mount(func(ctx context.Context, s *ghttp.Server) {
Register()
})
}
func Register() {
gvalid.RegisterRule("integer-array", IntegerArray)
gvalid.RegisterRule("float-array", FloatArray)

View File

@@ -3,7 +3,8 @@ package upload
import (
"context"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/internal/mounter"
)
const (
@@ -16,7 +17,9 @@ const (
type UploaderType int
type IUpload interface {
Upload(ctx context.Context, file *ghttp.UploadFile) (result system.UploadResponse, err error)
Upload(ctx context.Context, file *ghttp.UploadFile) (result *model.UploadResponse, err error)
CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error)
UploadPart(ctx context.Context, req *model.UploadPartReq) (*model.UploadPartRes, error)
}
var uploadCollection map[UploaderType]IUpload
@@ -46,3 +49,8 @@ func Register() {
RegisterUploader(SourceQiniu, &Qiniou{})
RegisterUploader(SourceOss, &OSS{})
}
func init() {
mounter.Mount(func(ctx context.Context, s *ghttp.Server) {
Register()
})
}

View File

@@ -6,9 +6,17 @@ import (
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/tiger1103/gfast/v3/internal/app/common/consts"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/library/libUtils"
"github.com/tiger1103/gfast/v3/library/liberr"
"sort"
"strconv"
"strings"
"time"
)
@@ -16,28 +24,12 @@ import (
type Local struct {
}
func (s *Local) Upload(ctx context.Context, file *ghttp.UploadFile) (result system.UploadResponse, err error) {
func (s *Local) Upload(ctx context.Context, file *ghttp.UploadFile) (result *model.UploadResponse, err error) {
if file == nil {
err = errors.New("文件必须!")
return
}
r := g.RequestFromCtx(ctx)
host := r.Header.Get("X-Forwarded-Host")
scheme := r.Header.Get("X-Scheme")
if host == "" {
host = r.Host
}
if scheme == "" {
scheme = r.GetSchema()
}
uri := r.Header.Get("X-Original-URI")
if uri != "" {
pos := gstr.PosI(uri, "/api/v1")
if pos >= 0 {
uri = gstr.SubStr(uri, 1, pos)
}
}
urlPerfix := fmt.Sprintf("%s://%s/%s", scheme, host, uri)
urlPerfix := libUtils.GetDomain(ctx, true)
p := strings.Trim(consts.UploadPath, "/")
sp := s.getStaticPath(ctx)
if sp != "" {
@@ -52,11 +44,10 @@ func (s *Local) Upload(ctx context.Context, file *ghttp.UploadFile) (result syst
}
// 不含静态文件夹的路径
fullPath := p + "/" + nowData + "/" + fileName
result = system.UploadResponse{
result = &model.UploadResponse{
Size: file.Size,
Path: fullPath,
FullPath: urlPerfix + fullPath,
FullPath: urlPerfix + "/" + fullPath,
Name: file.Filename,
Type: file.Header.Get("Content-type"),
}
@@ -71,3 +62,147 @@ func (s *Local) getStaticPath(ctx context.Context) string {
}
return ""
}
func (s *Local) CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
res = new(model.CheckMultipartRes)
//计算分片数
for i := 0; i < req.ShardsCount; i++ {
res.WaitUploadIndex = append(res.WaitUploadIndex, i+1)
}
var progress *model.MultipartProgress
progress, err = s.GetMultipartProgress(ctx, req)
liberr.ErrIsNil(ctx, err)
if progress != nil && len(progress.UploadedIndex) > 0 {
res.WaitUploadIndex = libUtils.DiffSlice(progress.UploadedIndex, res.WaitUploadIndex)
}
})
return
}
func (s *Local) UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error) {
err = g.Try(ctx, func(ctx context.Context) {
pq := &model.CheckMultipartReq{
UploadType: req.UploadType,
FileName: req.FileName,
Size: req.Size,
Md5: req.Md5,
ShardsCount: req.ShardsCount,
DriverType: req.DriverType,
UserId: req.UserId,
AppId: req.AppId,
}
var progress *model.MultipartProgress
progress, err = s.GetMultipartProgress(ctx, pq)
liberr.ErrIsNil(ctx, err)
if progress == nil {
liberr.ErrIsNil(ctx, errors.New("分片上传信息不存在"))
}
for _, i := range progress.UploadedIndex {
if req.Index == i {
liberr.ErrIsNil(ctx, errors.New("分片已上传"))
}
}
uploadId := s.GenUploadId(req.CheckMultipartReq)
fullPath := s.getPartPath(ctx, uploadId)
//保存分片
req.File.Filename = gconv.String(req.Index) + ".part"
_, err = req.File.Save(fullPath)
liberr.ErrIsNil(ctx, err, "写入分片文件内容失败")
res = new(model.UploadPartRes)
//已上传完毕
if req.ShardsCount == req.Index {
res.Finish = true
//合并文件
sp := s.getStaticPath(ctx)
if sp != "" {
sp = strings.TrimRight(sp, "/")
}
nowData := time.Now().Format("2006-01-02")
// 包含静态文件夹的路径
sp = sp + "/" + strings.Trim(consts.UploadPath, "/") + "/" + nowData
fileName := s.GenNewFileName(req.FileName)
err = s.MergerPath(fullPath, sp+"/"+fileName)
liberr.ErrIsNil(ctx, err, "合并分片失败")
//删除临时文件
gfile.Remove(fullPath)
path := gstr.SubStr(sp, strings.Index(sp, "/"+consts.UploadPath+"/")+1)
res.Attachment = &model.UploadResponse{
Size: req.Size,
Path: path + "/" + fileName,
FullPath: libUtils.GetDomain(ctx, true) + "/" + path + "/" + fileName,
Name: req.FileName,
Type: req.File.FileHeader.Header.Get("Content-type"),
}
}
})
return
}
func (s *Local) GenNewFileName(oldFileName string) string {
ext := gfile.Ext(oldFileName)
fileName := strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6)
return strings.ToLower(fileName + ext)
}
func (s *Local) MergerPath(src string, dst string) error {
parts, err := gfile.ScanDirFile(src, "*.part")
if err != nil {
return err
}
sort.Slice(parts, func(i, j int) bool {
fileI := gfile.Basename(parts[i])
fileJ := gfile.Basename(parts[j])
return gconv.Int(gstr.TrimRight(fileI, ".part")) < gconv.Int(gstr.TrimRight(fileJ, ".part"))
})
for _, file := range parts {
if err = gfile.PutBytesAppend(dst, gfile.GetBytes(file)); err != nil {
return err
}
}
return nil
}
// GenUploadId 生成上传ID
func (s *Local) GenUploadId(req *model.CheckMultipartReq) string {
return fmt.Sprintf("%s_%d_%s_%d", req.Md5, req.UserId, req.AppId, req.DriverType)
}
func (s *Local) getPartPath(ctx context.Context, uploadId string) string {
p := strings.Trim(consts.UploadPath, "/")
sp := s.getStaticPath(ctx)
if sp != "" {
sp = strings.TrimRight(sp, "/")
}
// 包含静态文件夹的路径
return sp + "/" + p + "/tmp/" + uploadId
}
// GetMultipartProgress 获取或创建分片上传事件进度
func (s *Local) GetMultipartProgress(ctx context.Context, req *model.CheckMultipartReq) (res *model.MultipartProgress, err error) {
err = g.Try(ctx, func(ctx context.Context) {
uploadId := s.GenUploadId(req)
fullDirPath := s.getPartPath(ctx, uploadId)
res = &model.MultipartProgress{
UploadId: uploadId,
CreatedAt: gtime.Now(),
ShardCount: req.ShardsCount,
UploadedIndex: []int{},
}
//路径不存在说明不存在分片信息
if !gfile.Exists(fullDirPath) {
return
}
//读取路径下的分片
var filePath []string
filePath, err = gfile.ScanDirFile(fullDirPath, "*.part")
liberr.ErrIsNil(ctx, err, "获取分片文件失败")
for _, v := range filePath {
index := gfile.Basename(v)
index = strings.TrimSuffix(index, ".part")
i := gconv.Int(index)
res.UploadedIndex = append(res.UploadedIndex, i)
}
})
return
}

View File

@@ -10,12 +10,13 @@ package upload
import (
"context"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"github.com/tiger1103/gfast/v3/library/liberr"
"mime/multipart"
"strconv"
@@ -31,7 +32,7 @@ type OSS struct {
Path string `json:"path"`
}
func (s *OSS) Upload(ctx context.Context, file *ghttp.UploadFile) (result system.UploadResponse, err error) {
func (s *OSS) Upload(ctx context.Context, file *ghttp.UploadFile) (result *model.UploadResponse, err error) {
err = g.Try(ctx, func(ctx context.Context) {
var (
client *oss.Client
@@ -57,7 +58,7 @@ func (s *OSS) Upload(ctx context.Context, file *ghttp.UploadFile) (result system
schema = "https"
}
url := schema + "://" + s.EndPoint + "/" + name
result = system.UploadResponse{
result = &model.UploadResponse{
Size: file.Size,
Path: url,
FullPath: url,
@@ -91,3 +92,13 @@ func (s *OSS) getClient() (client *oss.Client, err error) {
conn, time, cname, userAgent, verifySsl, redirect, crc, logLevel)
return
}
func (s *OSS) CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}
func (s *OSS) UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}

View File

@@ -2,24 +2,24 @@ package upload
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/util/guid"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"path"
)
type Qiniou struct{}
func (s *Qiniou) Upload(ctx context.Context, file *ghttp.UploadFile) (result system.UploadResponse, err error) {
func (s *Qiniou) Upload(ctx context.Context, file *ghttp.UploadFile) (result *model.UploadResponse, err error) {
url, err := s.toQiniou(ctx, file)
if err != nil {
return
}
result = system.UploadResponse{
result = &model.UploadResponse{
Size: file.Size,
Path: url,
FullPath: url,
@@ -73,3 +73,13 @@ func (s *Qiniou) toQiniou(ctx context.Context, f *ghttp.UploadFile) (url string,
return url, nil
}
func (s *Qiniou) CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}
func (s *Qiniou) UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}

View File

@@ -2,6 +2,7 @@ package upload
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
@@ -9,7 +10,7 @@ import (
"github.com/gogf/gf/v2/util/grand"
"github.com/tencentyun/cos-go-sdk-v5"
"github.com/tencentyun/cos-go-sdk-v5/debug"
"github.com/tiger1103/gfast/v3/api/v1/system"
"github.com/tiger1103/gfast/v3/internal/app/common/model"
"io"
"net/http"
"net/url"
@@ -20,7 +21,7 @@ import (
type Tencent struct {
}
func (s *Tencent) Upload(ctx context.Context, file *ghttp.UploadFile) (result system.UploadResponse, err error) {
func (s *Tencent) Upload(ctx context.Context, file *ghttp.UploadFile) (result *model.UploadResponse, err error) {
v, err := g.Cfg().Get(ctx, "upload.tencentCOS")
if err != nil {
return
@@ -36,7 +37,7 @@ func (s *Tencent) Upload(ctx context.Context, file *ghttp.UploadFile) (result sy
name = strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
name = name + gfile.Ext(file.Filename)
path := upPath + name
path := upPath + gtime.Date() + "/" + name
url, _ := url.Parse(rawUrl)
b := &cos.BaseURL{BucketURL: url}
@@ -64,7 +65,7 @@ func (s *Tencent) Upload(ctx context.Context, file *ghttp.UploadFile) (result sy
}
defer f.Close()
_, err = client.Object.Put(context.Background(), path, f, opt)
result = system.UploadResponse{
result = &model.UploadResponse{
Size: file.Size,
Path: rawUrl + path,
FullPath: rawUrl + path,
@@ -73,3 +74,13 @@ func (s *Tencent) Upload(ctx context.Context, file *ghttp.UploadFile) (result sy
}
return
}
func (s *Tencent) CheckMultipart(ctx context.Context, req *model.CheckMultipartReq) (res *model.CheckMultipartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}
func (s *Tencent) UploadPart(ctx context.Context, req *model.UploadPartReq) (res *model.UploadPartRes, err error) {
err = gerror.New("当前驱动暂不支持分片上传!")
return
}

View File

@@ -1,6 +0,0 @@
package upload_chunk
const (
RelativePath = "big_file/" // 返回前端的相对路径
FileName = "upfile" // 上传文件的文件名
)

View File

@@ -1,81 +0,0 @@
package upload_chunk
import (
"errors"
"fmt"
"os"
"path"
"strings"
)
// 解析文件目录,文件前缀及文件后缀
func parseFilePath(filename string) (dir, prefix, suffix string) {
filenameall := path.Base(filename) //不含目录的文件名
filesuffix := path.Ext(filename) // 后缀
fileprefix := strings.TrimSuffix(filenameall, filesuffix) // 前缀
dir = strings.TrimRight(filename, filenameall) // 文件目录
prefix = fileprefix // 文件前缀
suffix = filesuffix // 文件后缀
return
}
// 创建文件
func createFile(fullFilePath string) (ok bool, err error) {
ok = fileExists(fullFilePath)
if ok {
return
}
dir, _, _ := parseFilePath(fullFilePath)
if dir != "" {
err = mkDir(dir)
if err != nil {
return
}
}
newFile, err := os.Create(fullFilePath)
defer newFile.Close()
if err != nil {
return
}
return
}
// 创建文件夹
func mkDir(path string) (err error) {
if !fileExists(path) {
if err = os.MkdirAll(path, os.ModePerm); err != nil {
return errors.New(fmt.Sprintf(`os.MkdirAll failed for path "%s" with perm "%d" , err : %v`, path, os.ModePerm, err))
}
return nil
}
return
}
// 判断所给路径是否为文件夹
func IsDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}
// 是否文件
func IsFile(path string) bool {
return !IsDir(path)
}
// 判断文件或文件夹是否存在
func fileExists(path string) bool {
if stat, err := os.Stat(path); stat != nil && !os.IsNotExist(err) {
return true
}
return false
}
// 生成分片文件名
func getChunkFilename(identifier, chunkNumber string) string {
return fmt.Sprintf("uploader-%s.%s", identifier, chunkNumber)
}

View File

@@ -1,241 +0,0 @@
package upload_chunk
import (
"encoding/json"
"errors"
"io"
"mime/multipart"
"net/http"
"strconv"
)
type checkErr func() error
type UploadReq struct {
ChunkNumber int `json:"chunkNumber"` // 分片序列号
ChunkSize int `json:"chunkSize"` // 分片大小
CurrentChunkSize int `json:"currentChunkSize"` // 当前分片大小
TotalSize int64 `json:"totalSize"` // 文件总大小
Identifier string `json:"identifier"` // 标识
Filename string `json:"filename"` // 文件名
RelativePath string `json:"relativePath"` //文件夹上传的时候文件的相对路径属性
TotalChunks int `json:"totalChunks"` // 分片总数
File multipart.File
FileHeader *multipart.FileHeader
verification map[interface{}][]checkErr
}
func (u *UploadReq) verificationInit() {
if u.verification == nil {
u.verification = make(map[interface{}][]checkErr)
}
}
func (u *UploadReq) MustChunkNumber() *UploadReq {
u.verificationInit()
u.verification["ChunkNumber"] = append(u.verification["ChunkNumber"], func() error {
if u.ChunkNumber == 0 {
return errors.New("ChunkNumber不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustChunkSize() *UploadReq {
u.verificationInit()
u.verification["ChunkSize"] = append(u.verification["ChunkSize"], func() error {
if u.ChunkSize == 0 {
return errors.New("ChunkSize不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustCurrentChunkSize() *UploadReq {
u.verificationInit()
u.verification["CurrentChunkSize"] = append(u.verification["CurrentChunkSize"], func() error {
if u.CurrentChunkSize == 0 {
return errors.New("CurrentChunkSize不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustTotalSize() *UploadReq {
u.verificationInit()
u.verification["TotalSize"] = append(u.verification["TotalSize"], func() error {
if u.TotalSize == 0 {
return errors.New("TotalSize不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustIdentifier() *UploadReq {
u.verificationInit()
u.verification["Identifier"] = append(u.verification["Identifier"], func() error {
if u.Identifier == "" {
return errors.New("Identifier不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustFilename() *UploadReq {
u.verificationInit()
u.verification["Filename"] = append(u.verification["Filename"], func() error {
if u.Filename == "" {
return errors.New("Filename不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustTotalChunks() *UploadReq {
u.verificationInit()
u.verification["TotalChunks"] = append(u.verification["TotalChunks"], func() error {
if u.TotalChunks == 0 {
return errors.New("TotalChunks不能为空")
}
return nil
})
return u
}
func (u *UploadReq) MustFile() *UploadReq {
u.verificationInit()
u.verification["File"] = append(u.verification["File"], func() error {
if u.File == nil || u.FileHeader == nil {
return errors.New("File不能为空")
}
return nil
})
return u
}
func (u *UploadReq) Check() (err error) {
for _, item := range u.verification {
for _, fn := range item {
err = fn()
if err != nil {
return
}
}
}
return
}
func (u *UploadReq) Bind(r *http.Request) (err error) {
if r.Header.Get("Content-Type") == "application/json" {
l := r.ContentLength
if l == 0 {
return
}
buf := make([]byte, l)
_, err = r.Body.Read(buf)
if err != nil && err != io.EOF {
return
}
err = json.Unmarshal(buf, u)
if err != nil {
return
}
} else {
chunkNumber := r.FormValue("chunkNumber")
if chunkNumber != "" {
u.ChunkNumber, _ = strconv.Atoi(chunkNumber)
}
chunkSize := r.FormValue("chunkSize")
if chunkSize != "" {
u.ChunkSize, _ = strconv.Atoi(chunkSize)
}
currentChunkSize := r.FormValue("currentChunkSize")
if currentChunkSize != "" {
u.CurrentChunkSize, _ = strconv.Atoi(currentChunkSize)
}
totalSize := r.FormValue("totalSize")
if totalSize != "" {
u.TotalSize, _ = strconv.ParseInt(totalSize, 10, 64)
}
identifier := r.FormValue("identifier")
if identifier != "" {
u.Identifier = identifier
}
filename := r.FormValue("filename")
if filename != "" {
u.Filename = filename
}
relativePath := r.FormValue("relativePath")
if relativePath != "" {
u.RelativePath = relativePath
}
totalChunks := r.FormValue("totalChunks")
if totalChunks != "" {
u.TotalChunks, _ = strconv.Atoi(totalChunks)
}
}
u.File, u.FileHeader, _ = r.FormFile(FileName)
return
}
type BaseRes struct {
Filename string `json:"filename"` // 文件名
TotalSize int64 `json:"totalSize"` // 文件总大小
Url string `json:"url"` // 上传文件路径
}
// 返回前端的相对路径
func (b *BaseRes) RelativePath() {
_, prefix, suffix := parseFilePath(b.Url)
b.Url = RelativePath + prefix + suffix
}
type UpLoadRes struct {
BaseRes
NeedMerge bool `json:"needMerge"` // 是否合并文件
Identifier string `json:"identifier"` // 标识
TotalChunks int `json:"totalChunks"` // 分片总数
}
type CheckRes struct {
SkipUpload bool `json:"skipUpload"` // 秒传
Uploaded []int `json:"uploaded"` // 已上传过的分片
BaseRes
}
func (r *CheckRes) HasUploaded(i int) (ok bool) {
for _, item := range r.Uploaded {
if item == i {
return true
}
}
return
}
func (r *CheckRes) HasFirst() (ok bool) {
return r.HasUploaded(1)
}
type MergeRes struct {
BaseRes
}

View File

@@ -1,311 +0,0 @@
package upload_chunk
import (
"errors"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"io"
"log"
"mime/multipart"
"os"
"strconv"
"strings"
"sync"
)
type UploadChunk struct{}
// 检查分片
func (u *UploadChunk) CheckChunk(uploadReq UploadReq) (result *CheckRes, err error) {
err = uploadReq.MustIdentifier().MustTotalChunks().MustFilename().MustTotalSize().Check()
if err != nil {
return
}
identifier, totalChunks, filename, totalSize := uploadReq.Identifier, uploadReq.TotalChunks, uploadReq.Filename, uploadReq.TotalSize
dir, prefix, suffix := parseFilePath(filename)
_, _, _ = dir, prefix, suffix
if !strings.Contains(suffix, ".") {
err = errors.New("文件名解析错误")
return
}
result = &CheckRes{}
// 秒传
resultFilePath := u.Tmp() + identifier + suffix
if fileExists(resultFilePath) {
result.SkipUpload = true
result.Url = resultFilePath
result.Filename = filename
result.TotalSize = totalSize
result.RelativePath()
return
}
// 断点续传
for i := 1; i <= totalChunks; i++ {
chunkFilePath := u.chunkPath(identifier, strconv.FormatInt(int64(i), 10))
if fileExists(chunkFilePath) {
result.Uploaded = append(result.Uploaded, i)
}
}
return
}
// 合并文件
func (u *UploadChunk) MergeChunk(uploadReq UploadReq) (result *MergeRes, err error) {
err = uploadReq.MustIdentifier().MustTotalChunks().MustTotalSize().MustFilename().Check()
if err != nil {
return
}
identifier, totalChunks, totalSize, filename := uploadReq.Identifier, uploadReq.TotalChunks, uploadReq.TotalSize, uploadReq.Filename
_, _, suffix := parseFilePath(filename)
if !strings.Contains(suffix, ".") {
return nil, errors.New("文件名解析错误")
}
// 合并后的文件
resultFilePath := u.Tmp() + identifier + suffix
ok, err := createFile(resultFilePath)
if err != nil {
return
}
result = new(MergeRes)
// 文件已存在
if ok {
result.Url = resultFilePath
result.Filename = filename
result.TotalSize = totalSize
result.RelativePath()
return
}
// 检查分片文件是否完整
ok, err = u.checkChunkAll(identifier, totalChunks, totalSize)
if err != nil {
err = fmt.Errorf("分片文件检查错误:%s", err)
return
}
if !ok {
err = errors.New("分片文件不完整")
return
}
var chunkSize int64
var wg sync.WaitGroup
ch := make(chan struct{}, 10)
for i := 1; i <= totalChunks; i++ {
// 分片文件
filePath := u.chunkPath(identifier, fmt.Sprintf("%d", i))
if chunkSize == 0 {
fi, _ := os.Stat(filePath)
if chunkSize = fi.Size(); chunkSize == 0 {
err = errors.New("分片文件大小为0")
return
}
}
ch <- struct{}{}
wg.Add(1)
go func(i int) {
defer func() {
<-ch
wg.Done()
}()
uploadChunk := &UploadChunk{}
err = uploadChunk.mergeFile(filePath, resultFilePath, chunkSize*int64(i-1))
if err != nil {
log.Println(err)
return
}
}(i)
}
wg.Wait()
result.Url = resultFilePath
result.Filename = filename
result.TotalSize = totalSize
result.RelativePath()
return
}
// 上传分片文件
func (u *UploadChunk) Upload(uploadReq UploadReq) (result *UpLoadRes, err error) {
err = uploadReq.MustTotalChunks().MustChunkNumber().MustIdentifier().MustFile().MustTotalSize().MustFilename().Check()
if err != nil {
return
}
totalChunks, chunkNumber, identifier, upFile, filename := uploadReq.TotalChunks, uploadReq.ChunkNumber, uploadReq.Identifier, uploadReq.File, uploadReq.Filename
var fullFilePath string
if totalChunks > 1 {
// 分片文件路径
fullFilePath = u.chunkPath(identifier, strconv.Itoa(chunkNumber))
} else {
_, _, suffix := parseFilePath(filename)
if !strings.Contains(suffix, ".") {
return nil, errors.New("文件名解析错误")
}
fullFilePath = u.Tmp() + identifier + suffix
}
// 创建文件
ok, err := createFile(fullFilePath)
if err != nil {
return
}
if ok {
// 文件已经存在
result = &UpLoadRes{
BaseRes: BaseRes{
Filename: uploadReq.Filename,
TotalSize: uploadReq.TotalSize,
Url: fullFilePath,
},
NeedMerge: totalChunks > 1,
Identifier: uploadReq.Identifier,
TotalChunks: uploadReq.TotalChunks,
}
result.RelativePath()
return
}
// 打开分片文件
file, err := os.OpenFile(fullFilePath, os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return
}
defer file.Close()
// 文件偏移量
var fi os.FileInfo
fi, err = os.Stat(fullFilePath)
if err != nil {
return
}
start := fi.Size()
// 写入分片文件
_, err = u.writeFile(upFile, start, file, start)
if err != nil {
return
}
result = &UpLoadRes{
BaseRes: BaseRes{
Filename: uploadReq.Filename,
TotalSize: uploadReq.TotalSize,
Url: fullFilePath,
},
NeedMerge: totalChunks > 1,
Identifier: uploadReq.Identifier,
TotalChunks: uploadReq.TotalChunks,
}
result.RelativePath()
return
}
func (u *UploadChunk) Tmp() string {
return g.Cfg().MustGet(gctx.New(), "server.serverRoot").String() + "/big_file/" // 文件保存目录
}
// 合并文件
func (u *UploadChunk) mergeFile(chunkFile, mergeFile string, offset int64) (err error) {
// 合并后的文件
file, err := os.OpenFile(mergeFile, os.O_CREATE|os.O_WRONLY, os.ModePerm)
if err != nil {
return
}
defer file.Close()
_, err = file.Seek(offset, 0)
if err != nil {
return
}
// 分片文件
chunkFileObj, err := os.Open(chunkFile)
if err != nil {
return
}
defer chunkFileObj.Close()
// 写入数据
data := make([]byte, 1024, 1024)
for {
tal, e := chunkFileObj.Read(data)
if e == io.EOF {
chunkFileObj.Close()
os.Remove(chunkFile)
break
}
_, e = file.Write(data[:tal])
if e != nil {
return e
}
}
return
}
// 检查分片文件是否完整
func (u *UploadChunk) checkChunkAll(identifier string, totalChunks int, totalSize int64) (ok bool, err error) {
if identifier == "" || totalChunks == 0 {
return false, errors.New("checkChunkAll 参数错误")
}
var _totalSize int64
for i := 1; i <= totalChunks; i++ {
filePath := u.chunkPath(identifier, fmt.Sprintf("%d", i))
fi, e := os.Stat(filePath)
if e != nil {
return false, e
}
_totalSize += fi.Size()
}
return _totalSize == totalSize, nil
}
// 获取分片文件路径
func (u *UploadChunk) chunkPath(identifier string, chunkNumber string) string {
return fmt.Sprintf("%s%s", u.Tmp(), getChunkFilename(identifier, chunkNumber))
}
// 检查文件完整性
func (u *UploadChunk) verifyFileSize(fullFilePath string, size int64) (ok bool, err error) {
fi, err := os.Stat(fullFilePath)
if err != nil {
return
}
if fi.Size() == size {
return true, nil
}
return false, nil
}
// 写入文件
func (u *UploadChunk) writeFile(upfile multipart.File, upSeek int64, file *os.File, fSeek int64) (result int, err error) {
// 上传文件大小记录
fileSzie := 0
// 设置上传偏移量
upfile.Seek(upSeek, 0)
// 设置文件偏移量
file.Seek(fSeek, 0)
data := make([]byte, 1024, 1024)
for {
total, e := upfile.Read(data)
if e == io.EOF {
// 文件复制完毕
break
}
l, e := file.Write(data[:total])
if e != nil {
return 0, errors.New("文件上传失败")
}
// 记录上传长度
fileSzie += l
}
return fileSzie, nil
}

View File

@@ -18,13 +18,21 @@ package {{$structName}}
{{$gstr:=false}}
{{$hasLinkTable:=false}}
{{$useCommonService:=false}}
{{$hasDeptSelector:=false}}
{{$usedSystemModel := false}}
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "images" "file" "files"}}
{{if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}
{{$libUtils = true}}
{{end}}
{{if and (eq $column.HtmlField "createdBy" "updatedBy" "deletedBy" "deptId") (ne $.table.ModuleName "system")}}
{{if eq $column.HtmlType "deptSelectorMultiple" "deptSelectorSingle"}}
{{$hasDeptSelector = true}}
{{end}}
{{if and (or (eq $column.HtmlField "createdBy" "updatedBy" "deletedBy" "deptId") (eq $column.HtmlType "userSelectorSingle" "userSelectorMultiple" "deptSelectorMultiple" "deptSelectorSingle")) (ne $.table.ModuleName "system")}}
{{$usedSystemModule = true}}
{{end}}
{{if and (eq $column.HtmlType "userSelectorSingle" "userSelectorMultiple" "deptSelectorMultiple" "deptSelectorSingle") (ne $.table.ModuleName "system")}}
{{$usedSystemModel = true}}
{{end}}
{{if eq $column.HtmlType "selects" "checkbox"}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
@@ -66,6 +74,9 @@ import (
{{if $usedSystemModule}}
systemService "{{.goModName}}/internal/app/system/service"
{{end}}
{{if $usedSystemModel}}
systemModel "{{.goModName}}/internal/app/system/model"
{{end}}
{{if or (eq .table.TplCategory "tree") $libUtils}}
"{{.goModName}}/library/libUtils"
{{end}}
@@ -125,7 +136,19 @@ func (s *s{{.table.ClassName}})List(ctx context.Context, req *model.{{.table.Cla
m = m.Where(dao.{{$.table.ClassName}}.Columns().{{$column.GoField}}+" like ?", "%"+req.{{$column.GoField}}+"%")
}
{{else if eq $column.QueryType "EQ"}}
{{if eq $column.GoType "string"}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
if len(req.{{$column.GoField}}) > 0 {
if systemService.ToolsGenTable().IsMysql() {
for _, v := range req.{{$column.GoField}} {
m = m.Where("JSON_CONTAINS(`{{$column.ColumnName}}`,?)", gconv.String(v))
}
}else{
for _, v := range req.{{$column.GoField}} {
m = m.Where(`"{{$column.ColumnName}}" @> '[?]'::jsonb`, v)
}
}
}
{{else if eq $column.GoType "string"}}
if req.{{$column.GoField}} != "" {
m = m.Where(dao.{{$.table.ClassName}}.Columns().{{$column.GoField}}+" = ?", {{if ne $column.FieldConversion ""}}{{$column.FieldConversion}}({{end}}req.{{$column.GoField}}{{if ne $column.FieldConversion ""}}){{end}})
}
@@ -183,6 +206,17 @@ func (s *s{{.table.ClassName}})List(ctx context.Context, req *model.{{.table.Cla
listRes.List = make([]*model.{{.table.ClassName}}ListRes,len(res))
for k,v:=range res{
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
var linked{{$column.GoField}} []*{{if $usedSystemModel}}systemModel{{else}}model{{end}}.SysUserSimpleRes
linked{{$column.GoField}}, err = {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysUser().GetUsers(ctx, gconv.Interfaces(v.{{$column.GoField}}))
liberr.ErrIsNil(ctx, err)
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
linked{{$column.GoField}} := make([]*{{if $usedSystemModel}}systemModel{{else}}model{{end}}.LinkDeptRes, len(v.{{$column.GoField}}))
for lk, lv := range v.{{$column.GoField}} {
linked{{$column.GoField}}[lk] = {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysDept().GetByDept(ctx, lv)
}
{{end}}
{{if eq $column.HtmlType "selects" "checkbox" "treeSelects"}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
@@ -214,8 +248,6 @@ func (s *s{{.table.ClassName}})List(ctx context.Context, req *model.{{.table.Cla
{{if and $column.IsList (eq $column.HtmlField "UpdatedBy")}}
UpdatedUser:v.UpdatedUser,
{{end}}
{{end}}
{{range $index, $column := .table.Columns}}
{{if and $column.IsList (ne $column.HtmlField $.table.TreeCode) (ne $column.HtmlField $.table.TreeParentCode) (ne $column.HtmlField $.table.TreeName) }}
{{if eq $column.HtmlType "images" "file" "files"}}
{{$column.GoField}} : v.{{$column.GoField}},
@@ -228,6 +260,18 @@ func (s *s{{.table.ClassName}})List(ctx context.Context, req *model.{{.table.Cla
{{end}}
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
Linked{{$column.GoField}} : v.Linked{{$column.GoField}},
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
Linked{{$column.GoField}} : linked{{$column.GoField}},
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
Linked{{$column.GoField}}: {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysDept().GetByDept(ctx, v.{{$column.GoField}}),
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
Linked{{$column.GoField}}: linked{{$column.GoField}},
{{end}}
{{end}}
{{else}}
{{if not .table.IsPkListable}}
@@ -257,6 +301,18 @@ func (s *s{{.table.ClassName}})List(ctx context.Context, req *model.{{.table.Cla
{{end}}
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
Linked{{$column.GoField}} : v.Linked{{$column.GoField}},
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
Linked{{$column.GoField}} : linked{{$column.GoField}},
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
Linked{{$column.GoField}}: {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysDept().GetByDept(ctx, v.{{$column.GoField}}),
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
Linked{{$column.GoField}}: linked{{$column.GoField}},
{{end}}
{{end}}
{{end}}
}
@@ -276,7 +332,19 @@ func (s *s{{.table.ClassName}})GetExportData(ctx context.Context, req *model.{{.
m = m.Where(dao.{{$.table.ClassName}}.Columns().{{$column.GoField}}+" like ?", "%"+req.{{$column.GoField}}+"%")
}
{{else if eq $column.QueryType "EQ"}}
{{if eq $column.GoType "string"}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
if len(req.{{$column.GoField}}) > 0 {
if systemService.ToolsGenTable().IsMysql() {
for _, v := range req.{{$column.GoField}} {
m = m.Where("JSON_CONTAINS(`{{$column.ColumnName}}`,?)", gconv.String(v))
}
}else{
for _, v := range req.{{$column.GoField}} {
m = m.Where(`"{{$column.ColumnName}}" @> '[?]'::jsonb`, v)
}
}
}
{{else if eq $column.GoType "string"}}
if req.{{$column.GoField}} != "" {
m = m.Where(dao.{{$.table.ClassName}}.Columns().{{$column.GoField}}+" = ?", {{if ne $column.FieldConversion ""}}{{$column.FieldConversion}}({{end}}req.{{$column.GoField}}{{if ne $column.FieldConversion ""}}){{end}})
}
@@ -384,7 +452,7 @@ func(s *s{{.table.ClassName}})Import(ctx context.Context,file *ghttp.UploadFile)
{{$add = true}}
{{else if and $column.IsPk $.table.UseSnowId}}
{{$.table.PkColumn.GoField}}:{{$.table.PkColumn.HtmlField}},
{{else if and (ne $column.IsPk true) (ne $column.HtmlType "imagefile") (ne $column.HtmlType "images") (ne $column.HtmlType "file") (ne $column.HtmlType "files")}}
{{else if and (ne $column.IsPk true) (ne $column.HtmlType "imagefile") (ne $column.HtmlType "images") (ne $column.HtmlType "file") (ne $column.HtmlType "files") (ne $column.HtmlType "imageSelector") (ne $column.HtmlType "fileSelector")}}
{{$add = true}}
{{if eq $column.GoType "int" "uint" "int64" "uint64" "bool" }}
{{$column.GoField}}:gconv.Int64(d[{{$i}}]),
@@ -440,13 +508,27 @@ func (s *s{{.table.ClassName}})GetBy{{$pkGoField}}(ctx context.Context, {{$.tabl
err =g.Try(ctx, func(ctx context.Context){
err = dao.{{.table.ClassName}}.Ctx(ctx).WithAll().Where(dao.{{.table.ClassName}}.Columns().{{$pkGoField}}, {{$.table.PkColumn.HtmlField}}).Scan(&res)
liberr.ErrIsNil(ctx,err,"获取信息失败")
{{if $.table.HasDeptId}}
{{if or $.table.HasDeptId $hasDeptSelector}}
if res!=nil{
{{if $.table.HasDeptId}}
{{if $usedSystemModule}}
res.DeptInfo = systemService.SysDept().GetByDept(ctx, res.DeptId)
{{else}}
res.DeptInfo = service.SysDept().GetByDept(ctx, res.DeptId)
{{end}}
{{end}}
{{if $hasDeptSelector}}
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
res.Linked{{$column.GoField}} = {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysDept().GetByDept(ctx, res.{{$column.GoField}})
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
res.Linked{{$column.GoField}} = make([]*{{if $usedSystemModel}}systemModel{{else}}model{{end}}.LinkDeptRes, len(res.{{$column.GoField}}))
for k, v := range res.{{$column.GoField}} {
res.Linked{{$column.GoField}}[k] = {{if $usedSystemModule}}systemService{{else}}service{{end}}.SysDept().GetByDept(ctx, v)
}
{{end}}
{{end}}
{{end}}
}
{{end}}
{{range $index, $column := .table.Columns}}
@@ -480,7 +562,7 @@ func (s *s{{.table.ClassName}})Add(ctx context.Context, req *model.{{.table.Clas
if !req.{{$column.GoField}}.IsEmpty(){
{{$column.HtmlField}}=req.{{$column.GoField}}.Join(",")
}
{{else if eq $column.HtmlType "images" "file" "files"}}
{{else if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}
for _,obj:=range req.{{$column.GoField}}{
obj.Url,err = libUtils.GetFilesPath(ctx,obj.Url)
liberr.ErrIsNil(ctx, err)
@@ -529,7 +611,7 @@ func (s *s{{.table.ClassName}})Edit(ctx context.Context, req *model.{{.table.Cla
if !req.{{$column.GoField}}.IsEmpty(){
{{$column.HtmlField}}=req.{{$column.GoField}}.Join(",")
}
{{else if eq $column.HtmlType "images" "file" "files"}}
{{else if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}
for _,obj:=range req.{{$column.GoField}}{
obj.Url,err = libUtils.GetFilesPath(ctx,obj.Url)
liberr.ErrIsNil(ctx, err)

View File

@@ -17,10 +17,10 @@ package model
{{range $index,$column :=.table.Columns}}
{{if and (eq $column.HtmlField "createdBy" "updatedBy" "deptId") (ne $.table.ModuleName "system")}}
{{if and (or (eq $column.HtmlField "createdBy" "updatedBy" "deptId") (eq $column.HtmlType "userSelectorSingle" "userSelectorMultiple" "deptSelectorMultiple" "deptSelectorSingle")) (ne $.table.ModuleName "system")}}
{{$hasUser = true}}
{{end}}
{{if eq $column.HtmlType "imagefile" "images" "file" "files" }}
{{if eq $column.HtmlType "imagefile" "images" "file" "files" "imageSelector" "fileSelector"}}
{{$hasUpFile = true}}
{{end}}
{{if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}
@@ -28,7 +28,7 @@ package model
{{end}}
{{end}}
{{range $index,$column :=.table.EditColumns}}
{{if and (eq $column.HtmlField "createdBy" "updatedBy" "deptId") (ne $.table.ModuleName "system")}}
{{if and (or (eq $column.HtmlField "createdBy" "updatedBy" "deptId") (eq $column.HtmlType "userSelectorMultiple" "userSelectorSingle" "deptSelectorMultiple" "deptSelectorSingle")) (ne $.table.ModuleName "system")}}
{{$hasUser = true}}
{{end}}
{{if eq $column.GoType "Time"}}
@@ -54,7 +54,7 @@ import (
type {{.table.ClassName}}InfoRes struct {
gmeta.Meta `orm:"table:{{.table.TableName}}"`
{{range $index, $column := .table.Columns}}
{{if $column.IsPk}}{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}} `orm:"{{$column.ColumnName}},primary" json:"{{$column.HtmlField}}{{if $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"` // {{$column.ColumnComment}} {{else}}{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}} `orm:"{{$column.ColumnName}}" json:"{{$column.HtmlField}}" dc:"{{$column.ColumnComment}}"` // {{$column.ColumnComment}} {{end}}
{{if $column.IsPk}}{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `orm:"{{$column.ColumnName}},primary" json:"{{$column.HtmlField}}{{if $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"` // {{$column.ColumnComment}} {{else}}{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `orm:"{{$column.ColumnName}}" json:"{{$column.HtmlField}}" dc:"{{$column.ColumnComment}}"` // {{$column.ColumnComment}} {{end}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
Linked{{$column.GoField}} {{if eq $column.HtmlType "selects" "checkbox" "treeSelects"}}[]{{end}}*Linked{{$.table.ClassName}}{{$linkedTable.ClassName}} `{{if not (eq $column.HtmlType "selects" "checkbox" "treeSelects")}}orm:"with:{{$column.LinkLabelId}}={{$column.ColumnName}}" {{end}}json:"linked{{$column.GoField}}"`
@@ -69,6 +69,18 @@ type {{.table.ClassName}}InfoRes struct {
{{if eq $column.HtmlField "updatedBy"}}
UpdatedUser *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id=updated_by" json:"updatedUser"`
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id={{$column.ColumnName}}" json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id={{$column.ColumnName}}" json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{end}}
}
@@ -76,7 +88,7 @@ type {{.table.ClassName}}InfoRes struct {
type Linked{{$.table.ClassName}}{{$linkedTable.ClassName}} struct {
gmeta.Meta `orm:"table:{{$linkedTable.TableName}}"`
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.GoField}} {{if eq $linkedColumn.GoType "Time"}}*gtime.Time{{else}}{{$linkedColumn.GoType}}{{end}} `orm:"{{$linkedColumn.ColumnName}}" json:"{{$linkedColumn.HtmlField}}" dc:"{{$linkedColumn.ColumnComment}}"` // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.GoField}} {{if eq $linkedColumn.GoType "Time"}}*gtime.Time{{else if eq $linkedColumn.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$linkedColumn.GoType}}{{end}} `orm:"{{$linkedColumn.ColumnName}}" json:"{{$linkedColumn.HtmlField}}" dc:"{{$linkedColumn.ColumnComment}}"` // {{$linkedColumn.ColumnComment}}
{{end}}
{{if eq $linkedTable.TplCategory "tree"}}
{{$linkedTable.OptionsStruct.ColumnAttr.GoField}} {{$linkedTable.OptionsStruct.ColumnAttr.GoType}} `orm:"{{$linkedTable.OptionsStruct.ColumnAttr.ColumnName}}" json:"{{$linkedTable.OptionsStruct.ColumnAttr.HtmlField}}"`
@@ -90,12 +102,12 @@ type {{.table.ClassName}}ListRes struct{
{{if eq .table.TplCategory "tree"}}
{{range $index, $column := .table.Columns}}
{{if or (eq $column.HtmlField $.table.TreeCode) (eq $column.HtmlField $.table.TreeParentCode) (eq $column.HtmlField $.table.TreeName) }}
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}{{if and $column.IsPk $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"`
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}{{if and $column.IsPk $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{end}}
{{range $index, $column := .table.Columns}}
{{if and $column.IsList (ne $column.HtmlField $.table.TreeCode) (ne $column.HtmlField $.table.TreeParentCode) (ne $column.HtmlField $.table.TreeName) }}
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}" dc:"{{$column.ColumnComment}}"`
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}" dc:"{{$column.ColumnComment}}"`
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
Linked{{$column.GoField}} {{if eq $column.HtmlType "selects" "checkbox" "treeSelects"}}[]{{end}}*Linked{{$.table.ClassName}}{{$linkedTable.ClassName}} `{{if not (eq $column.HtmlType "selects" "checkbox" "treeSelects")}}orm:"with:{{$column.LinkLabelId}}={{$column.ColumnName}}" {{end}}json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
@@ -111,6 +123,18 @@ type {{.table.ClassName}}ListRes struct{
UpdatedUser *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id=updated_by" json:"updatedUser"`
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id={{$column.ColumnName}}" json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}SysUserSimpleRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{end}}
{{else}}
{{if not .table.IsPkListable }}
@@ -126,12 +150,24 @@ type {{.table.ClassName}}ListRes struct{
{{if eq $column.HtmlField "updatedBy"}}
UpdatedUser *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id=updated_by" json:"updatedBy"`
{{end}}
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}{{if and $column.IsPk $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"`
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `json:"{{$column.HtmlField}}{{if and $column.IsPk $.table.UseSnowId}},string{{end}}" dc:"{{$column.ColumnComment}}"`
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
Linked{{$column.GoField}} {{if eq $column.HtmlType "selects" "checkbox" "treeSelects"}}[]{{end}}*Linked{{$.table.ClassName}}{{$linkedTable.ClassName}} `{{if not (eq $column.HtmlType "selects" "checkbox" "treeSelects")}}orm:"with:{{$column.LinkLabelId}}={{$column.ColumnName}}" {{end}}json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkUserRes `orm:"with:id={{$column.ColumnName}}" json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}SysUserSimpleRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
Linked{{$column.GoField}} *{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
Linked{{$column.GoField}} []*{{if $hasUser}}systemModel.{{end}}LinkDeptRes `json:"linked{{$column.GoField}}" dc:"{{$column.ColumnComment}}"`
{{end}}
{{end}}
{{end}}
}
@@ -143,7 +179,7 @@ type {{.table.ClassName}}SearchReq struct {
comModel.PageReq
{{end}}
{{range $index, $column := .table.QueryColumns}}
{{$column.GoField}} {{if eq $column.GoType "Time" "int" "int64" "uint" "uint64" "float" "float64" "bool"}}{{if eq $column.QueryType "BETWEEN"}}[]{{end}}string{{else}}{{if eq $column.QueryType "BETWEEN"}}[]{{end}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}"{{if ne $column.FieldValidation ""}} v:"{{$column.FieldValidation}}"{{end}} dc:"{{$column.ColumnComment}}"` //{{$column.ColumnComment}}
{{$column.GoField}} {{if eq $column.GoType "Time" "int" "int64" "uint" "uint64" "float" "float64" "bool"}}{{if eq $column.QueryType "BETWEEN"}}[]{{end}}string{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{if eq $column.QueryType "BETWEEN"}}[]{{end}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}"{{if ne $column.FieldValidation ""}} v:"{{$column.FieldValidation}}"{{end}} dc:"{{$column.ColumnComment}}"` //{{$column.ColumnComment}}
{{end}}
}
@@ -172,7 +208,7 @@ type {{.table.ClassName}}AddReq struct {
{{.table.PkColumn.GoField}} {{.table.PkColumn.GoType}} `p:"{{.table.PkColumn.HtmlField}}" v:"required#主键ID不能为空" dc:"{{.table.PkColumn.ColumnComment}}"`
{{end}}
{{range $index, $column := .table.EditColumns}}
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "images" "file" "files"}}[]*comModel.UpFile{{else if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}garray.StrArray{{else}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}" {{if $column.IsRequired}}v:"required#{{$column.ColumnComment}}不能为空"{{end}} dc:"{{$column.ColumnComment}}"`
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}[]*comModel.UpFile{{else if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}garray.StrArray{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}" {{if $column.IsRequired}}v:"required#{{$column.ColumnComment}}不能为空"{{end}} dc:"{{$column.ColumnComment}}"`
{{end}}
{{if .table.HasCreatedBy}}
CreatedBy uint64
@@ -187,7 +223,7 @@ type {{.table.ClassName}}AddReq struct {
type {{.table.ClassName}}EditReq struct {
{{.table.PkColumn.GoField}} {{.table.PkColumn.GoType}} `p:"{{.table.PkColumn.HtmlField}}" v:"required#主键ID不能为空" dc:"{{.table.PkColumn.ColumnComment}}"`
{{range $index, $column := .table.EditColumns}}
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "images" "file" "files"}}[]*comModel.UpFile{{else if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}garray.StrArray{{else}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}" {{if $column.IsRequired}}v:"required#{{$column.ColumnComment}}不能为空"{{end}} dc:"{{$column.ColumnComment}}"`
{{$column.GoField}} {{if eq $column.GoType "Time"}}*gtime.Time{{else if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}[]*comModel.UpFile{{else if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}garray.StrArray{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}[]uint64{{else}}{{$column.GoType}}{{end}} `p:"{{$column.HtmlField}}" {{if $column.IsRequired}}v:"required#{{$column.ColumnComment}}不能为空"{{end}} dc:"{{$column.ColumnComment}}"`
{{end}}
{{if .table.HasUpdatedBy}}
UpdatedBy uint64

View File

@@ -7,7 +7,7 @@ export interface {{.table.ClassName}}TableColumns {
{{end}}
{{range $index, $column := .table.Columns}}
{{if and $column.IsList (ne $column.HtmlField $.table.TreeCode) (ne $column.HtmlField $.table.TreeParentCode) (ne $column.HtmlField $.table.TreeName) }}
{{$column.HtmlField}}:{{if and (eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects") (eq $column.DictType "")}}any[]{{else}}{{$column.TsType}}{{end}}; // {{$column.ColumnComment}}
{{$column.HtmlField}}:{{if and (eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector") (eq $column.DictType "")}}any[]{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}number[]{{else}}{{$column.TsType}}{{end}}; // {{$column.ColumnComment}}
{{end}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
@@ -23,7 +23,7 @@ export interface {{.table.ClassName}}TableColumns {
{{if eq $column.HtmlField "createdBy" "updatedBy"}}
{{$column.HtmlField}}:string; // {{$column.ColumnComment}}
{{else}}
{{$column.HtmlField}}:{{if and (eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects") (eq $column.DictType "")}}any[]{{else}}{{$column.TsType}}{{end}}; // {{$column.ColumnComment}}
{{$column.HtmlField}}:{{if and (eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector") (eq $column.DictType "")}}any[]{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}number[]{{else}}{{$column.TsType}}{{end}}; // {{$column.ColumnComment}}
{{end}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
@@ -40,12 +40,24 @@ export interface {{.table.ClassName}}TableColumns {
////
export interface {{.table.ClassName}}InfoData {
{{range $index, $column := .table.Columns}}
{{if $column.IsPk}}{{$column.HtmlField}}:{{if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects"}}any[]{{else if eq $column.HtmlType "switch"}}boolean{{else if eq $column.HtmlType "keyValue"}}{key:string,value:any}[]{{else}}{{$column.TsType}}|undefined{{end}}; // {{$column.ColumnComment}} {{else}}{{$column.HtmlField}}:{{if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects"}}any[]{{else if eq $column.HtmlType "switch"}}boolean{{else if eq $column.HtmlType "keyValue"}}{key:string,value:any}[]{{else}}{{$column.TsType}}|undefined{{end}}; // {{$column.ColumnComment}} {{end}}
{{if $column.IsPk}}{{$column.HtmlField}}:{{if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector"}}any[]{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}number[]{{else if eq $column.HtmlType "switch"}}boolean{{else if eq $column.HtmlType "keyValue"}}{key:string,value:any}[]{{else}}{{$column.TsType}}|undefined{{end}}; // {{$column.ColumnComment}} {{else}}{{$column.HtmlField}}:{{if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector"}}any[]{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}number[]{{else if eq $column.HtmlType "switch"}}boolean{{else if eq $column.HtmlType "keyValue"}}{key:string,value:any}[]{{else}}{{$column.TsType}}|undefined{{end}}; // {{$column.ColumnComment}} {{end}}
{{range $ti, $linkedTable := $.table.LinkedTables}}
{{if eq $column.LinkTableClass $linkedTable.ClassName}}
linked{{$column.GoField}}?:Linked{{$.table.ClassName}}{{$linkedTable.ClassName}}{{if eq $column.HtmlType "checkbox" "selects" "treeSelects"}}[]{{end}}; // {{$column.ColumnComment}}
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorSingle"}}
linked{{$column.GoField}} : LinkedUserData|null;
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple"}}
linked{{$column.GoField}} : LinkedUserData[];
{{end}}
{{if eq $column.HtmlType "deptSelectorSingle"}}
linked{{$column.GoField}} : LinkedDeptData|null;
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple"}}
linked{{$column.GoField}} : LinkedDeptData[];
{{end}}
{{end}}
{{range $ti, $linkedTable := .table.LinkedTables}}
linked{{$.table.ClassName}}{{$linkedTable.ClassName}}?:Linked{{$.table.ClassName}}{{$linkedTable.ClassName}};
@@ -56,7 +68,7 @@ export interface {{.table.ClassName}}InfoData {
////
export interface Linked{{$.table.ClassName}}{{$linkedTable.ClassName}} {
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files"}}any[]{{else}}{{$linkedColumn.TsType}}|undefined{{end}}; // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}any[]{{else if eq $linkedColumn.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}number[]{{else}}{{$linkedColumn.TsType}}|undefined{{end}}; // {{$linkedColumn.ColumnComment}}
{{end}}
}
{{end}}
@@ -74,6 +86,8 @@ export interface {{.table.ClassName}}TableDataState {
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.QueryType "BETWEEN"}}
{{$column.HtmlField}}: {{$column.TsType}}[];
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: number[];
{{else}}
{{$column.HtmlField}}: {{$column.TsType}}|undefined;
{{end}}{{end}}
@@ -82,6 +96,31 @@ export interface {{.table.ClassName}}TableDataState {
};
}
{{$hasUserSelector := false}}
{{$hasDeptSelector := false}}
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "userSelectorMultiple" "userSelectorSingle"}}
{{$hasUserSelector = true}}
{{end}}
{{if eq $column.HtmlType "deptSelectorMultiple" "deptSelectorSingle"}}
{{$hasDeptSelector = true}}
{{end}}
{{end}}
{{if $hasUserSelector}}
////
export interface LinkedDeptData {
deptId:number;
deptName:string;
}
{{end}}
{{if $hasDeptSelector}}
////
export interface LinkedUserData {
id:number;
userNickname:string;
}
{{end}}
////
export interface {{.table.ClassName}}EditState{
loading:boolean;

View File

@@ -154,6 +154,69 @@
:href="proxy.getUpFileUrl(item.url)" target="_blank">{{"{{"}}item.name{{"}}"}}</el-link>
</div>
</el-descriptions-item>
{{else if eq $column.HtmlType "imageSelector"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
<div class="pic-block" v-for="(img,key) in formData.{{$column.HtmlField}}" :key="'{{$column.HtmlField}}-'+key">
<el-image
style="width: 150px; height: 150px"
v-if="!proxy.isEmpty(img.url)"
:src="proxy.getUpFileUrl(img.url)"
fit="contain"></el-image>
</div>
</el-descriptions-item>
{{else if eq $column.HtmlType "fileSelector"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
<div class="file-block" v-for="(item,key) in formData.{{$column.HtmlField}}" :key="'{{$column.HtmlField}}-'+key">
<el-link type="primary" :underline="false"
:href="proxy.getUpFileUrl(item.url)" target="_blank">{{"{{"}}item.name{{"}}"}}</el-link>
</div>
</el-descriptions-item>
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
{{"{{"}} formData.linked{{$column.GoField}}?formData.linked{{$column.GoField}}.userNickname:'' {{"}}"}}
</el-descriptions-item>
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
{{"{{"}} formData.linked{{$column.GoField}}?formData.linked{{$column.GoField}}.deptName:'' {{"}}"}}
</el-descriptions-item>
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
{{"{{"}} formData.linked{{$column.GoField}}?formData.linked{{$column.GoField}}.map((res:any)=>{return res.userNickname}).join(''):'' {{"}}"}}
</el-descriptions-item>
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
<div class="cell-item">
{{$column.ColumnComment}}
</div>
</template>
{{"{{"}} formData.linked{{$column.GoField}}?formData.linked{{$column.GoField}}.map((res:any)=>{return res.deptName}).join(''):'' {{"}}"}}
</el-descriptions-item>
{{else if eq $column.HtmlType "keyValue"}}
<el-descriptions-item :span="{{$column.ColSpan}}">
<template #label>
@@ -296,7 +359,7 @@
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "radio"}}
{{$column.HtmlField}}: false ,
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "keyValue"}}
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "keyValue" "imageSelector" "fileSelector" "deptSelectorMultiple" "userSelectorMultiple"}}
{{$column.HtmlField}}: [] ,
{{else}}
{{$column.HtmlField}}: undefined,
@@ -310,11 +373,16 @@
{{end}}
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
linked{{$column.GoField}}:[],
{{else if eq $column.HtmlType "userSelectorSingle" "deptSelectorSingle"}}
linked{{$column.GoField}}:null,
{{end}}
{{end}}
{{range $ti, $linkedTable := .table.LinkedTables}}
linked{{$.table.ClassName}}{{$linkedTable.ClassName}}: {
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files" "imageSelector" "fileSelector" "deptSelectorMultiple" "userSelectorMultiple"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{end}}
},
{{end}}
@@ -345,8 +413,10 @@
{{else if eq $column.HtmlType "imagefile"}}
//单图地址赋值
imageUrl{{$column.GoField}}.value = data.{{$column.HtmlField}} ? proxy.getUpFileUrl(data.{{$column.HtmlField}}) : ''
{{else if eq $column.HtmlType "images" "file" "files" "keyValue"}}
{{else if eq $column.HtmlType "images" "file" "files" "keyValue" "imageSelector" "fileSelector"}}
data.{{$column.HtmlField}} =data.{{$column.HtmlField}}?JSON.parse(data.{{$column.HtmlField}}) : []
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
data.{{$column.HtmlField}} = data.{{$column.HtmlField}}?data.{{$column.HtmlField}}:[]
{{end}}
{{if eq $column.HtmlField "createdBy"}}
data.createdBy = data.createdUser?.userNickname
@@ -379,7 +449,7 @@
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "radio"}}
{{$column.HtmlField}}: false ,
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "keyValue"}}
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "keyValue" "imageSelector" "fileSelector" "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: [] ,
{{else}}
{{$column.HtmlField}}: undefined,
@@ -393,11 +463,16 @@
{{end}}
{{end}}
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
linked{{$column.GoField}}:[],
{{else if eq $column.HtmlType "userSelectorSingle" "deptSelectorSingle"}}
linked{{$column.GoField}}:null,
{{end}}
{{end}}
{{range $ti, $linkedTable := .table.LinkedTables}}
linked{{$.table.ClassName}}{{$linkedTable.ClassName}}: {
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files" "imageSelector" "fileSelector" "userSelectorMultiple" "deptSelectorMultiple"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{end}}
},
{{end}}

View File

@@ -39,7 +39,7 @@
{{else if eq $column.HtmlType "select" "selects"}}
{{if ne $column.LinkTableName ""}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}} {{if $column.IsCascadeParent}}@change="form{{$column.ColumnName | CaseCamel}}Changed"{{end}} {{if eq $column.HtmlType "selects"}}multiple{{end}}>
<el-select filterable v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}} {{if $column.IsCascadeParent}}@change="form{{$column.ColumnName | CaseCamel}}Changed"{{end}} {{if eq $column.HtmlType "selects"}}multiple{{end}}>
<el-option
{{if $column.IsCascade}}
v-for="item in {{$column.HtmlField}}FormOptions"
@@ -54,7 +54,7 @@
</el-form-item>
{{else if ne $column.DictType ""}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}}>
<el-select filterable v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}}>
<el-option
v-for="dict in {{$column.HtmlField}}Options"
:key="dict.value"
@@ -69,7 +69,7 @@
</el-form-item>
{{else}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}}>
<el-select filterable v-model="formData.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" {{if $column.IsPk}}v-bind:disabled="this.currentOp === 'edit'" {{end}}>
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
@@ -171,7 +171,7 @@
{{end}}
{{else if eq $column.HtmlType "richtext"}}
<el-form-item label="{{$column.ColumnComment}}">
<gf-ueditor editorId="ue{{$.table.ClassName}}{{$column.GoField}}" v-model="formData.{{$column.HtmlField}}" @setEditContent="set{{$column.GoField}}EditContent"></gf-ueditor>
<gf-ueditor editorId="ue{{$.table.ClassName}}{{$column.GoField}}" v-model="formData.{{$column.HtmlField}}"></gf-ueditor>
</el-form-item>
{{else if eq $column.HtmlType "imagefile"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
@@ -191,15 +191,39 @@
</el-form-item>
{{else if eq $column.HtmlType "images"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}" >
<upload-img :action="baseURL+'{{$.apiVersion}}/system/upload/singleImg'" v-model="formData.{{$column.HtmlField}}" @uploadData="setUpImgList{{$column.GoField}}" :limit="10"></upload-img>
<upload-img :action="baseURL+'{{$.apiVersion}}/system/upload/singleImg'" v-model="formData.{{$column.HtmlField}}" :limit="10"></upload-img>
</el-form-item>
{{else if eq $column.HtmlType "file"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}" >
<upload-file :action="baseURL+'{{$.apiVersion}}/system/upload/singleFile'" v-model="formData.{{$column.HtmlField}}" @upFileData="setUpFileList{{$column.GoField}}" :limit="1"></upload-file>
<upload-file :action="baseURL+'{{$.apiVersion}}/system/upload/singleFile'" v-model="formData.{{$column.HtmlField}}" :limit="1"></upload-file>
</el-form-item>
{{else if eq $column.HtmlType "files"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}" >
<upload-file :action="baseURL+'{{$.apiVersion}}/system/upload/singleFile'" v-model="formData.{{$column.HtmlField}}" @upFileData="setUpFileList{{$column.GoField}}" :limit="10"></upload-file>
<upload-file :action="baseURL+'{{$.apiVersion}}/system/upload/singleFile'" v-model="formData.{{$column.HtmlField}}" :limit="10"></upload-file>
</el-form-item>
{{else if eq $column.HtmlType "imageSelector"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<upload-selector v-model="formData.{{$column.HtmlField}}" fileType="image" :limit="10"></upload-selector>
</el-form-item>
{{else if eq $column.HtmlType "fileSelector"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<upload-selector v-model="formData.{{$column.HtmlField}}" fileType="file" :limit="10"></upload-selector>
</el-form-item>
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="{{$column.HtmlField}}" :multiple="false"></select-user>
</el-form-item>
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="formData.{{$column.HtmlField}}"></select-user>
</el-form-item>
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="formData.{{$column.HtmlField}}"></select-dept>
</el-form-item>
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="formData.{{$column.HtmlField}}" :multiple="true"></select-dept>
</el-form-item>
{{else if eq $column.HtmlType "keyValue"}}
<p class="kv-label" >{{$column.ColumnComment}}</p>
@@ -251,7 +275,10 @@
{{$imgsImp := false}}
{{$editImp := false }}
{{$fileImp := false}}
{{$fileSelectorImp := false}}
{{$getUserList:=false}}
{{$selectorUserImp:=false}}
{{$selectorDeptImp:=false}}
{{range $index,$column:=.table.Columns}}
{{if eq $column.HtmlType "richtext"}}
@@ -262,6 +289,12 @@
{{$imgsImp = true}}
{{else if eq $column.HtmlType "file" "files"}}
{{$fileImp = true}}
{{else if or (eq $column.HtmlType "fileSelector") (eq $column.HtmlType "imageSelector")}}
{{$fileSelectorImp = true}}
{{else if or (eq $column.HtmlType "userSelectorSingle") (eq $column.HtmlType "userSelectorMultiple")}}
{{$selectorUserImp = true}}
{{else if or (eq $column.HtmlType "deptSelectorSingle") (eq $column.HtmlType "deptSelectorMultiple")}}
{{$selectorDeptImp = true}}
{{end}}
{{if eq $column.HtmlField "createdBy" "updatedBy"}}
{{$getUserList = true}}
@@ -269,7 +302,7 @@
{{end}}
<script setup lang="ts">
import { reactive, toRefs, ref,unref,getCurrentInstance } from 'vue';
import { reactive, toRefs, ref,unref,getCurrentInstance,computed } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
{{/*去重处理*/}}
import {
@@ -297,6 +330,15 @@ import uploadImg from "/@/components/uploadImg/index.vue"
{{if $fileImp}}
import uploadFile from "/@/components/uploadFile/index.vue"
{{end}}
{{if $fileSelectorImp}}
import uploadSelector from "/@/components/uploadSelector/index.vue"
{{end}}
{{if $selectorUserImp}}
import selectUser from "/@/components/selectUser/index.vue"
{{end}}
{{if $selectorDeptImp}}
import selectDept from "/@/components/selectDept/index.vue"
{{end}}
import {
{{.table.ClassName}}TableColumns,
{{.table.ClassName}}InfoData,
@@ -370,18 +412,23 @@ const state = reactive<{{.table.ClassName}}EditState>({
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "switch"}}
{{$column.HtmlField}}: false ,
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects"}}
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector" "deptSelectorMultiple" "userSelectorMultiple"}}
{{$column.HtmlField}}: [] ,
{{else if eq $column.HtmlType "keyValue"}}
{{$column.HtmlField}}:[{key:"",value:""}],
{{else}}
{{$column.HtmlField}}: undefined,
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
linked{{$column.GoField}}:[],
{{else if eq $column.HtmlType "userSelectorSingle" "deptSelectorSingle"}}
linked{{$column.GoField}}:null,
{{end}}
{{end}}
{{range $ti, $linkedTable := .table.LinkedTables}}
linked{{$.table.ClassName}}{{$linkedTable.ClassName}}: {
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files" "imageSelector" "fileSelector" "deptSelectorMultiple" "userSelectorMultiple"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{end}}
},
{{end}}
@@ -398,6 +445,18 @@ const state = reactive<{{.table.ClassName}}EditState>({
}
});
const { loading,isShowDialog,formData,rules } = toRefs(state);
{{range $index, $column := .table.EditColumns}}
{{if eq $column.HtmlType "userSelectorSingle"}}
const {{$column.HtmlField}} = computed({
get:()=>{
return state.formData.{{$column.HtmlField}}?[state.formData.{{$column.HtmlField}}]:[]
},
set:(val:number[])=>{
state.formData.{{$column.HtmlField}} = val?val[0]:0
}
})
{{end}}
{{end}}
// 打开弹窗
const openDialog = (row?: {{.table.ClassName}}InfoData) => {
resetForm();
@@ -453,10 +512,12 @@ const openDialog = (row?: {{.table.ClassName}}InfoData) => {
{{else if eq $column.HtmlType "imagefile"}}
//单图地址赋值
imageUrl{{$column.GoField}}.value = data.{{$column.HtmlField}} ? proxy.getUpFileUrl(data.{{$column.HtmlField}}) : ''
{{else if eq $column.HtmlType "images" "file" "files"}}
{{else if eq $column.HtmlType "images" "file" "files" "imageSelector" "fileSelector"}}
data.{{$column.HtmlField}} =data.{{$column.HtmlField}}?JSON.parse(data.{{$column.HtmlField}}) : []
{{else if eq $column.HtmlType "keyValue"}}
data.{{$column.HtmlField}} = data.{{$column.HtmlField}}?JSON.parse(data.{{$column.HtmlField}}) : [{key:'',value:''}]
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
data.{{$column.HtmlField}} = data.{{$column.HtmlField}}?data.{{$column.HtmlField}}:[]
{{end}}
{{end}}
state.formData = data;
@@ -511,18 +572,23 @@ const resetForm = ()=>{
{{$column.HtmlField}}: false ,
{{else if eq $column.HtmlType "radio"}}
{{$column.HtmlField}}: '' ,
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects"}}
{{else if eq $column.HtmlType "images" "file" "files" "checkbox" "selects" "treeSelects" "imageSelector" "fileSelector" "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: [] ,
{{else if eq $column.HtmlType "keyValue"}}
{{$column.HtmlField}}:[{key:"",value:""}],
{{else}}
{{$column.HtmlField}}: undefined,
{{end}}
{{if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
linked{{$column.GoField}}:[],
{{else if eq $column.HtmlType "userSelectorSingle" "deptSelectorSingle"}}
linked{{$column.GoField}}:null,
{{end}}
{{end}}
{{range $ti, $linkedTable := .table.LinkedTables}}
linked{{$.table.ClassName}}{{$linkedTable.ClassName}}: {
{{range $ci, $linkedColumn := $linkedTable.RefColumns.Values}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{$linkedColumn.HtmlField}}:{{if eq $linkedColumn.HtmlType "images" "file" "files" "imageSelector" "fileSelector" "userSelectorMultiple" "deptSelectorMultiple"}}[]{{else}}undefined{{end}}, // {{$linkedColumn.ColumnComment}}
{{end}}
},
{{end}}
@@ -535,12 +601,7 @@ const resetForm = ()=>{
};
{{$setUpData:=true}}
{{range $index, $column := .table.Columns}}
{{if eq $column.HtmlType "richtext"}}
//富文本编辑器{{$column.ColumnComment}}
const set{{$column.GoField}}EditContent = (data:string) => {
state.formData.{{$column.HtmlField}} = data
}
{{else if eq $column.HtmlType "imagefile"}}
{{if eq $column.HtmlType "imagefile"}}
//单图上传{{$column.ColumnComment}}
const handleAvatarSuccess{{$column.GoField}}:UploadProps['onSuccess'] = (res, file) => {
if (res.code === 0) {
@@ -561,14 +622,6 @@ const setUpData = () => {
}
{{$setUpData = false}}
{{end}}
{{else if eq $column.HtmlType "images"}}
const setUpImgList{{$column.GoField}} = (data:any)=>{
state.formData.{{$column.HtmlField}} = data
}
{{else if eq $column.HtmlType "file" "files"}}
const setUpFileList{{$column.GoField}} = (data:any)=>{
state.formData.{{$column.HtmlField}} = data
}
{{else if eq $column.HtmlType "keyValue"}}
// 新增{{$column.ColumnComment}}行
const onAddRow{{$column.GoField}} = () => {

View File

@@ -22,7 +22,7 @@
</el-form-item>
</el-col>
{{end}}
{{if eq $column.HtmlType "input" "textarea"}}
{{if eq $column.HtmlType "input" "textarea" "inputNumber"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-input
@@ -53,7 +53,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.DictType "") }}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option
v-for="dict in {{$column.DictType}}"
:key="dict.value"
@@ -130,7 +130,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.LinkTableName "")}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-option
{{if $column.IsCascade}}
v-for="item in {{$column.HtmlField}}QueryOptions"
@@ -167,10 +167,38 @@
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="{{$column.HtmlField}}" :multiple="false"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="tableData.param.{{$column.HtmlField}}"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}" :multiple="true"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
@@ -334,6 +362,42 @@
></el-switch>
</template>
</el-table-column>
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.userNickname:'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.map((res:any)=>{return res.userNickname}).join(''):'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.deptName:'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.map((res:any)=>{return res.deptName}).join(''):'' {{"}}"}}
</template>
</el-table-column>
{{else if ne $column.LinkTableName ""}}
<el-table-column label="{{$column.ColumnComment}}" align="center" prop="linked{{$column.GoField}}.{{$column.LinkLabelName | CaseCamelLower}}"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
@@ -432,6 +496,8 @@
{{$editImp := false }}
{{$fileImp := false}}
{{$getUserList:=false}}
{{$selectorUserImp:=false}}
{{$selectorDeptImp:=false}}
{{range $index,$column:=.table.Columns}}
{{if eq $column.HtmlType "richtext"}}
@@ -442,6 +508,10 @@
{{$imgsImp = true}}
{{else if eq $column.HtmlType "file" "files"}}
{{$fileImp = true}}
{{else if or (eq $column.HtmlType "userSelectorSingle") (eq $column.HtmlType "userSelectorMultiple")}}
{{$selectorUserImp = true}}
{{else if or (eq $column.HtmlType "deptSelectorSingle") (eq $column.HtmlType "deptSelectorMultiple")}}
{{$selectorDeptImp = true}}
{{end}}
{{if eq $column.HtmlField "createdBy" "updatedBy"}}
{{$getUserList = true}}
@@ -483,6 +553,12 @@ import {downLoadXml} from "/@/utils/zipdownload";
{{if .table.ExcelImp}}
import loadExcel from "/@/components/loadExcel/index.vue"
{{end}}
{{if $selectorUserImp}}
import selectUser from "/@/components/selectUser/index.vue"
{{end}}
{{if $selectorDeptImp}}
import selectDept from "/@/components/selectDept/index.vue"
{{end}}
defineOptions({ name: "{{.apiVersion|replace "/" "_"|CaseCamelLower}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}List"})
const {proxy} = <any>getCurrentInstance()
const loading = ref(false)
@@ -547,14 +623,29 @@ const state = reactive<{{.table.ClassName}}TableDataState>({
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.QueryType "BETWEEN"}}
{{$column.HtmlField}}: [],
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: [],
{{else}}
{{$column.HtmlField}}: undefined,
{{end}}{{end}}
{{end}}
{{end}}
dateRange: []
},
},
});
const { tableData } = toRefs(state);
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.HtmlType "userSelectorSingle"}}
const {{$column.HtmlField}} = computed({
get:()=>{
return state.tableData.param.{{$column.HtmlField}}?[state.tableData.param.{{$column.HtmlField}}]:[]
},
set:(val:number[])=>{
state.tableData.param.{{$column.HtmlField}} = val?val[0]:0
}
})
{{end}}
{{end}}
// 页面加载时
onMounted(() => {
initTableData();

View File

@@ -27,7 +27,7 @@
</el-form-item>
</el-col>
{{end}}
{{if eq $column.HtmlType "input" "textarea"}}
{{if eq $column.HtmlType "input" "textarea" "inputNumber"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-input
@@ -58,7 +58,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.DictType "") }}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option
v-for="dict in {{$column.DictType}}"
:key="dict.value"
@@ -135,7 +135,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.LinkTableName "")}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-option
{{if $column.IsCascade}}
v-for="item in {{$column.HtmlField}}QueryOptions"
@@ -172,10 +172,38 @@
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="{{$column.HtmlField}}" :multiple="false"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="tableData.param.{{$column.HtmlField}}"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}" :multiple="true"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
@@ -298,6 +326,8 @@
{{$editImp := false }}
{{$fileImp := false}}
{{$getUserList:=false}}
{{$selectorUserImp:=false}}
{{$selectorDeptImp:=false}}
{{range $index,$column:=.table.Columns}}
{{if eq $column.HtmlType "richtext"}}
@@ -308,6 +338,10 @@
{{$imgsImp = true}}
{{else if eq $column.HtmlType "file" "files"}}
{{$fileImp = true}}
{{else if or (eq $column.HtmlType "userSelectorSingle") (eq $column.HtmlType "userSelectorMultiple")}}
{{$selectorUserImp = true}}
{{else if or (eq $column.HtmlType "deptSelectorSingle") (eq $column.HtmlType "deptSelectorMultiple")}}
{{$selectorDeptImp = true}}
{{end}}
{{if eq $column.HtmlField "createdBy" "updatedBy"}}
{{$getUserList = true}}
@@ -345,6 +379,12 @@ import {
import {{.apiVersion|replace "/" "_"|CaseCamel}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}Edit from "/@/views/{{.modulePath}}/{{$businessName}}/list/component/edit.vue"
import {{.apiVersion|replace "/" "_"|CaseCamel}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}Detail from "/@/views/{{.modulePath}}/{{$businessName}}/list/component/detail.vue"
import _ from 'lodash'
{{if $selectorUserImp}}
import selectUser from "/@/components/selectUser/index.vue"
{{end}}
{{if $selectorDeptImp}}
import selectDept from "/@/components/selectDept/index.vue"
{{end}}
defineOptions({ name: "{{.apiVersion|replace "/" "_"|CaseCamelLower}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}List"})
const {proxy} = <any>getCurrentInstance()
const loading = ref(false)
@@ -407,6 +447,8 @@ const state = reactive<{{.table.ClassName}}TableDataState>({
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.QueryType "BETWEEN"}}
{{$column.HtmlField}}: [],
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: [],
{{else}}
{{$column.HtmlField}}: undefined,
{{end}}{{end}}
@@ -415,6 +457,18 @@ const state = reactive<{{.table.ClassName}}TableDataState>({
},
});
const { tableData } = toRefs(state);
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.HtmlType "userSelectorSingle"}}
const {{$column.HtmlField}} = computed({
get:()=>{
return state.tableData.param.{{$column.HtmlField}}?[state.tableData.param.{{$column.HtmlField}}]:[]
},
set:(val:number[])=>{
state.tableData.param.{{$column.HtmlField}} = val?val[0]:0
}
})
{{end}}
{{end}}
// 页面加载时
onMounted(() => {
initTableData();
@@ -677,6 +731,38 @@ const setVrData = (list:{{$.table.ClassName}}TableColumns[])=>{
onClick: () => { change{{$column.GoField}}(row)}});
}
})
{{else if eq $column.HtmlType "userSelectorSingle" }}
_columns.push({key: 'linked{{$column.GoField}}',dataKey: 'linked{{$column.GoField}}',title: `{{$column.ColumnComment}}`,
{{if gt $column.MinWidth 0}}width:{{$column.MinWidth}},{{end}}
{{if $column.IsFixed}}fixed: TableV2FixedDir.LEFT,{{end}}
cellRenderer: ({ cellData: linked{{$column.GoField}} }) => {
return h('span', linked{{$column.GoField}}?linked{{$column.GoField}}.userNickname:'');
}
})
{{else if eq $column.HtmlType "userSelectorMultiple" }}
_columns.push({key: 'linked{{$column.GoField}}',dataKey: 'linked{{$column.GoField}}',title: `{{$column.ColumnComment}}`,
{{if gt $column.MinWidth 0}}width:{{$column.MinWidth}},{{end}}
{{if $column.IsFixed}}fixed: TableV2FixedDir.LEFT,{{end}}
cellRenderer: ({ cellData: linked{{$column.GoField}} }) => {
return h('span', linked{{$column.GoField}}?linked{{$column.GoField}}.map((res:any)=>{return res.userNickname}).join(''):'');
}
})
{{else if eq $column.HtmlType "deptSelectorSingle" }}
_columns.push({key: 'linked{{$column.GoField}}',dataKey: 'linked{{$column.GoField}}',title: `{{$column.ColumnComment}}`,
{{if gt $column.MinWidth 0}}width:{{$column.MinWidth}},{{end}}
{{if $column.IsFixed}}fixed: TableV2FixedDir.LEFT,{{end}}
cellRenderer: ({ cellData: linked{{$column.GoField}} }) => {
return h('span', linked{{$column.GoField}}?linked{{$column.GoField}}.deptName:'');
}
})
{{else if eq $column.HtmlType "deptSelectorMultiple" }}
_columns.push({key: 'linked{{$column.GoField}}',dataKey: 'linked{{$column.GoField}}',title: `{{$column.ColumnComment}}`,
{{if gt $column.MinWidth 0}}width:{{$column.MinWidth}},{{end}}
{{if $column.IsFixed}}fixed: TableV2FixedDir.LEFT,{{end}}
cellRenderer: ({ cellData: linked{{$column.GoField}} }) => {
return h('span',linked{{$column.GoField}}?linked{{$column.GoField}}.map((res:any)=>{return res.deptName}).join(''):'');
}
})
{{else if eq $column.HtmlType "selects" "checkbox" "treeSelects"}}
{{if ne $column.LinkTableName ""}}
_columns.push({key: '{{$column.HtmlField}}',dataKey: '{{$column.HtmlField}}',title: `{{$column.ColumnComment}}`,

View File

@@ -25,7 +25,7 @@
</el-form-item>
</el-col>
{{end}}
{{if eq $column.HtmlType "input" "textarea"}}
{{if eq $column.HtmlType "input" "textarea" "inputNumber"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-input
@@ -56,7 +56,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.DictType "") }}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option
v-for="dict in {{$column.DictType}}"
:key="dict.value"
@@ -133,7 +133,7 @@
{{else if and (eq $column.HtmlType "select" "radio" "checkbox" "selects") (ne $column.LinkTableName "")}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable {{if $column.IsCascadeParent}}@change="query{{$column.ColumnName | CaseCamel}}Changed"{{end}} style="width:200px;">
<el-option
{{if $column.IsCascade}}
v-for="item in {{$column.HtmlField}}QueryOptions"
@@ -170,10 +170,38 @@
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="{{$column.HtmlField}}" :multiple="false"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-user v-model="tableData.param.{{$column.HtmlField}}"></select-user>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<select-dept v-model="tableData.param.{{$column.HtmlField}}" :multiple="true"></select-dept>
</el-form-item>
</el-col>
{{$colIndex = ($colIndex | plus 1)}}
{{else}}
<el-col :span="8" {{if lt $colIndex 2}}class="colBlock"{{else}}:class="showAll ? 'colBlock' : 'colNone'"{{end}}>
<el-form-item label="{{$column.ColumnComment}}" prop="{{$column.HtmlField}}">
<el-select v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-select filterable v-model="tableData.param.{{$column.HtmlField}}" placeholder="请选择{{$column.ColumnComment}}" clearable style="width:200px;">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
@@ -328,6 +356,42 @@
></el-switch>
</template>
</el-table-column>
{{else if eq $column.HtmlType "userSelectorSingle"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.userNickname:'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "userSelectorMultiple"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.map((res:any)=>{return res.userNickname}).join(''):'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "deptSelectorSingle"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.deptName:'' {{"}}"}}
</template>
</el-table-column>
{{else if eq $column.HtmlType "deptSelectorMultiple"}}
<el-table-column label="{{$column.ColumnComment}}" align="center"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
{{if $column.IsOverflowTooltip}}:show-overflow-tooltip="true"{{end}}
{{if $column.IsFixed}}fixed="left"{{end}}>
<template #default="scope">
{{"{{"}} scope.row.linked{{$column.GoField}}?scope.row.linked{{$column.GoField}}.map((res:any)=>{return res.deptName}).join(''):'' {{"}}"}}
</template>
</el-table-column>
{{else if ne $column.LinkTableName ""}}
<el-table-column label="{{$column.ColumnComment}}" align="center" prop="linked{{$column.GoField}}.{{$column.LinkLabelName | CaseCamelLower}}"
{{if gt $column.MinWidth 0}}min-width="{{$column.MinWidth}}px"{{end}}
@@ -415,6 +479,8 @@
{{$editImp := false }}
{{$fileImp := false}}
{{$getUserList:=false}}
{{$selectorUserImp:=false}}
{{$selectorDeptImp:=false}}
{{range $index,$column:=.table.Columns}}
{{if eq $column.HtmlType "richtext"}}
@@ -425,6 +491,10 @@
{{$imgsImp = true}}
{{else if eq $column.HtmlType "file" "files"}}
{{$fileImp = true}}
{{else if or (eq $column.HtmlType "userSelectorSingle") (eq $column.HtmlType "userSelectorMultiple")}}
{{$selectorUserImp = true}}
{{else if or (eq $column.HtmlType "deptSelectorSingle") (eq $column.HtmlType "deptSelectorMultiple")}}
{{$selectorDeptImp = true}}
{{end}}
{{if eq $column.HtmlField "createdBy" "updatedBy"}}
{{$getUserList = true}}
@@ -461,6 +531,12 @@ import {
import {{.apiVersion|replace "/" "_"|CaseCamel}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}Edit from "/@/views/{{.modulePath}}/{{$businessName}}/list/component/edit.vue"
import {{.apiVersion|replace "/" "_"|CaseCamel}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}Detail from "/@/views/{{.modulePath}}/{{$businessName}}/list/component/detail.vue"
import _ from 'lodash'
{{if $selectorUserImp}}
import selectUser from "/@/components/selectUser/index.vue"
{{end}}
{{if $selectorDeptImp}}
import selectDept from "/@/components/selectDept/index.vue"
{{end}}
defineOptions({ name: "{{.apiVersion|replace "/" "_"|CaseCamelLower}}{{.modulePath|replace "/" "_"|CaseCamel}}{{.table.ClassName}}List"})
const {proxy} = <any>getCurrentInstance()
const loading = ref(false)
@@ -523,6 +599,8 @@ const state = reactive<{{.table.ClassName}}TableDataState>({
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.QueryType "BETWEEN"}}
{{$column.HtmlField}}: [],
{{else if eq $column.HtmlType "userSelectorMultiple" "deptSelectorMultiple"}}
{{$column.HtmlField}}: [],
{{else}}
{{$column.HtmlField}}: undefined,
{{end}}{{end}}
@@ -531,6 +609,18 @@ const state = reactive<{{.table.ClassName}}TableDataState>({
},
});
const { tableData } = toRefs(state);
{{range $index, $column := .table.QueryColumns}}
{{if eq $column.HtmlType "userSelectorSingle"}}
const {{$column.HtmlField}} = computed({
get:()=>{
return state.tableData.param.{{$column.HtmlField}}?[state.tableData.param.{{$column.HtmlField}}]:[]
},
set:(val:number[])=>{
state.tableData.param.{{$column.HtmlField}} = val?val[0]:0
}
})
{{end}}
{{end}}
// 页面加载时
onMounted(() => {
initTableData();

View File

@@ -8,12 +8,21 @@
package task
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/tiger1103/gfast/v3/internal/app/system/model"
"github.com/tiger1103/gfast/v3/internal/app/system/service"
"github.com/tiger1103/gfast/v3/internal/mounter"
)
func init() {
mounter.Mount(func(ctx context.Context, s *ghttp.Server) {
Run()
})
}
func Run() {
task1 := &model.TimeTask{
FuncName: "test1",