Merge pull request #19 from bufanyun/v2.0

模块化上传驱动,使用泛型优化工具库降低冗余
This commit is contained in:
maxbad
2023-06-02 22:57:23 +08:00
committed by GitHub
96 changed files with 1276 additions and 1483 deletions

View File

@@ -12,27 +12,33 @@ build:
@cd ../web && yarn build && \cp -rf ./dist/* ../server$(ADMIN_RESOURCE_PATH) @cd ../web && yarn build && \cp -rf ./dist/* ../server$(ADMIN_RESOURCE_PATH)
@echo "y" | gf build @echo "y" | gf build
# 通过热编译启动所有服务 # 通过热编译启动所有服务
.PHONY: all .PHONY: all
all: all:
gf run main.go --args "all" gf run main.go --args "all"
.PHONY: http .PHONY: http
http: http:
gf run main.go --args "http" gf run main.go --args "http"
.PHONY: queue .PHONY: queue
queue: queue:
gf run main.go --args "queue" gf run main.go --args "queue"
.PHONY: cron .PHONY: cron
cron: cron:
gf run main.go --args "cron" gf run main.go --args "cron"
.PHONY: auth .PHONY: auth
auth: auth:
gf run main.go --args "auth" gf run main.go --args "auth"
# 启动web服务 # 启动web服务
.PHONY: web .PHONY: web
web: web:
@@ -44,11 +50,20 @@ web:
refresh: refresh:
@go run main.go tools -m=casbin -a1=refresh @go run main.go tools -m=casbin -a1=refresh
# 清理casbin权限 # 清理casbin权限
.PHONY: clear .PHONY: clear
clear: clear:
@go run main.go tools -m=casbin -a1=clear @go run main.go tools -m=casbin -a1=clear
# 运行代码质量分析工具
# https://github.com/ywanbing/golangci
.PHONY: ci
ci:
golangci-lint run
.PHONY: killmain .PHONY: killmain
killmain: killmain:
@kill -9 $(ps -ef|grep main|grep -v grep|awk '{print $2}') @kill -9 $(ps -ef|grep main|grep -v grep|awk '{print $2}')
@@ -79,11 +94,13 @@ cli.install:
dao: cli.install dao: cli.install
@gf gen dao @gf gen dao
# Generate Go files for Service. # Generate Go files for Service.
.PHONY: service .PHONY: service
service: cli.install service: cli.install
@gf gen service @gf gen service
# Build image, deploy image and yaml to current kubectl environment and make port forward to local machine. # Build image, deploy image and yaml to current kubectl environment and make port forward to local machine.
.PHONY: start .PHONY: start
start: start:
@@ -92,6 +109,7 @@ start:
make deploy; \ make deploy; \
make port; make port;
# Build docker image. # Build docker image.
.PHONY: image .PHONY: image
image: cli.install image: cli.install

View File

@@ -189,7 +189,7 @@ func (s *sSysTable) Status(ctx context.Context, in sysin.TableStatusInp) (err er
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }
@@ -209,7 +209,7 @@ func (s *sSysTable) Switch(ctx context.Context, in sysin.TableSwitchInp) (err er
// ... // ...
} }
if !validate.InSliceString(fields, in.Key) { if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单") err = gerror.New("开关键名不在白名单")
return return
} }

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sysin package sysin
import ( import (
@@ -53,7 +52,6 @@ func (in *TableEditInp) Filter(ctx context.Context) (err error) {
if err := g.Validator().Rules("float|between:0,5").Messages("请输入一个浮点数|推荐星只能是0~5星").Data(in.Star).Run(ctx); err != nil { if err := g.Validator().Rules("float|between:0,5").Messages("请输入一个浮点数|推荐星只能是0~5星").Data(in.Star).Run(ctx); err != nil {
return err.Current() return err.Current()
} }
return return
} }

View File

@@ -15,7 +15,7 @@ import (
) )
var ( var (
NoLogin []interface{} // 无需登录 NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录 LoginRequiredRouter []interface{} // 需要登录
) )
@@ -23,8 +23,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) { func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
group.Group(prefix, func(group *ghttp.RouterGroup) { group.Group(prefix, func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 { if len(NoLoginRouter) > 0 {
group.Bind(NoLogin...) group.Bind(NoLoginRouter...)
} }
group.Middleware(service.Middleware().AdminAuth) group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 { if len(LoginRequiredRouter) > 0 {

View File

@@ -3,17 +3,15 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package attachment package attachment
import ( import (
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form" "hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
) )
// ListReq 查询列表 // ListReq 查询附件列表
type ListReq struct { type ListReq struct {
form.PageReq form.PageReq
form.RangeDateReq form.RangeDateReq
@@ -28,41 +26,18 @@ type ListRes struct {
form.PageRes form.PageRes
} }
// ViewReq 获取信息 // ViewReq 获取附件信息
type ViewReq struct { type ViewReq struct {
Id int64 `json:"id" v:"required#附件ID不能为空" dc:"附件ID"` Id int64 `json:"id" v:"required#附件ID不能为空" dc:"附件ID"`
g.Meta `path:"/attachment/view" method:"get" tags:"附件" summary:"获取指定信息"` g.Meta `path:"/attachment/view" method:"get" tags:"附件" summary:"获取指定附件信息"`
} }
type ViewRes struct { type ViewRes struct {
*sysin.AttachmentViewModel *sysin.AttachmentViewModel
} }
// EditReq 修改/新增 // DeleteReq 删除附件
type EditReq struct {
entity.SysAttachment
g.Meta `path:"/attachment/edit" method:"post" tags:"附件" summary:"修改/新增附件"`
}
type EditRes struct{}
// DeleteReq 删除
type DeleteReq struct { type DeleteReq struct {
Id interface{} `json:"id" v:"required#附件ID不能为空" dc:"附件ID"` Id interface{} `json:"id" v:"required#附件ID不能为空" dc:"附件ID"`
g.Meta `path:"/attachment/delete" method:"post" tags:"附件" summary:"删除附件"` g.Meta `path:"/attachment/delete" method:"post" tags:"附件" summary:"删除附件"`
} }
type DeleteRes struct{} type DeleteRes struct{}
// MaxSortReq 最大排序
type MaxSortReq struct {
Id int64 `json:"id" dc:"附件ID"`
g.Meta `path:"/attachment/maxSort" method:"get" tags:"附件" summary:"附件最大排序"`
}
type MaxSortRes struct {
Sort int `json:"sort" dc:"排序"`
}
// StatusReq 更新状态
type StatusReq struct {
entity.SysAttachment
g.Meta `path:"/attachment/status" method:"post" tags:"附件" summary:"更新附件状态"`
}
type StatusRes struct{}

View File

@@ -21,7 +21,7 @@ var (
Http = &gcmd.Command{ Http = &gcmd.Command{
Name: "http", Name: "http",
Usage: "http", Usage: "http",
Brief: "HTTP服务", Brief: "HTTP服务也可以称为主服务包含http、websocket、tcpserver多个可对外服务",
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) { Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
// 加载权限 // 加载权限
casbin.InitEnforcer(ctx) casbin.InitEnforcer(ctx)
@@ -32,6 +32,7 @@ var (
s.BindStatusHandler(404, func(r *ghttp.Request) { s.BindStatusHandler(404, func(r *ghttp.Request) {
r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…") r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…")
}) })
s.BindStatusHandler(403, func(r *ghttp.Request) { s.BindStatusHandler(403, func(r *ghttp.Request) {
r.Response.Writeln("403 - 网站拒绝显示此网页") r.Response.Writeln("403 - 网站拒绝显示此网页")
}) })

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package consts package consts
// 碎片 // 碎片
@@ -12,4 +11,5 @@ const (
DemoTips = "演示系统已隐藏" DemoTips = "演示系统已隐藏"
NilJsonToString = "{}" // 空json初始化值 NilJsonToString = "{}" // 空json初始化值
RegionSpilt = " / " // 地区分隔符 RegionSpilt = " / " // 地区分隔符
Unknown = "Unknown"
) )

View File

@@ -1,7 +1,5 @@
package consts package consts
import "time"
const ( const (
TCPMsgCodeSuccess = 2000 // 成功的状态码 TCPMsgCodeSuccess = 2000 // 成功的状态码
) )
@@ -21,5 +19,6 @@ const (
) )
const ( const (
TCPRpcTimeout = time.Second * 10 // rpc通讯超时时间 默认10s TCPHeartbeatTimeout = 300 // tcp心跳超时默认300s
TCPRpcTimeout = 10 // rpc通讯超时时间 默认10s
) )

View File

@@ -5,6 +5,16 @@
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package consts package consts
// 上传类型
const (
UploadTypeFile = 1 // 文件
UploadTypeImage = 2 // 图片
UploadTypeDoc = 3 // 文档
UploadTypeAudio = 4 // 音频
UploadTypeVideo = 5 // 视频
)
// 上传存储驱动
const ( const (
UploadDriveLocal = "local" // 本地驱动 UploadDriveLocal = "local" // 本地驱动
UploadDriveUCloud = "ucloud" // ucloud对象存储 UploadDriveUCloud = "ucloud" // ucloud对象存储

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sys package sys
import ( import (
@@ -21,7 +20,7 @@ var (
type cAttachment struct{} type cAttachment struct{}
// Delete 删除 // Delete 删除附件
func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (res *attachment.DeleteRes, err error) { func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (res *attachment.DeleteRes, err error) {
var in sysin.AttachmentDeleteInp var in sysin.AttachmentDeleteInp
if err = gconv.Scan(req, &in); err != nil { if err = gconv.Scan(req, &in); err != nil {
@@ -32,30 +31,7 @@ func (c *cAttachment) Delete(ctx context.Context, req *attachment.DeleteReq) (re
return return
} }
// Edit 更新 // View 获取指定附件信息
func (c *cAttachment) Edit(ctx context.Context, req *attachment.EditReq) (res *attachment.EditRes, err error) {
var in sysin.AttachmentEditInp
if err = gconv.Scan(req, &in); err != nil {
return
}
err = service.SysAttachment().Edit(ctx, in)
return
}
// MaxSort 最大排序
func (c *cAttachment) MaxSort(ctx context.Context, req *attachment.MaxSortReq) (res *attachment.MaxSortRes, err error) {
data, err := service.SysAttachment().MaxSort(ctx, sysin.AttachmentMaxSortInp{Id: req.Id})
if err != nil {
return
}
res = new(attachment.MaxSortRes)
res.Sort = data.Sort
return
}
// View 获取指定信息
func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *attachment.ViewRes, err error) { func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *attachment.ViewRes, err error) {
data, err := service.SysAttachment().View(ctx, sysin.AttachmentViewInp{Id: req.Id}) data, err := service.SysAttachment().View(ctx, sysin.AttachmentViewInp{Id: req.Id})
if err != nil { if err != nil {
@@ -67,7 +43,7 @@ func (c *cAttachment) View(ctx context.Context, req *attachment.ViewReq) (res *a
return return
} }
// List 查看列表 // List 查看附件列表
func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *attachment.ListRes, err error) { func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *attachment.ListRes, err error) {
var in sysin.AttachmentListInp var in sysin.AttachmentListInp
if err = gconv.Scan(req, &in); err != nil { if err = gconv.Scan(req, &in); err != nil {
@@ -86,14 +62,3 @@ func (c *cAttachment) List(ctx context.Context, req *attachment.ListReq) (res *a
res.PerPage = req.PerPage res.PerPage = req.PerPage
return return
} }
// Status 更新部门状态
func (c *cAttachment) Status(ctx context.Context, req *attachment.StatusReq) (res *attachment.StatusRes, err error) {
var in sysin.AttachmentStatusInp
if err = gconv.Scan(req, &in); err != nil {
return
}
err = service.SysAttachment().Status(ctx, in)
return
}

View File

@@ -5,15 +5,7 @@
package dao package dao
import ( import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
"hotgo/internal/dao/internal" "hotgo/internal/dao/internal"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/format"
) )
// internalSysAttachmentDao is internal type for wrapping internal DAO implements. // internalSysAttachmentDao is internal type for wrapping internal DAO implements.
@@ -31,34 +23,3 @@ var (
internal.NewSysAttachmentDao(), internal.NewSysAttachmentDao(),
} }
) )
func (dao *sysAttachmentDao) GetMd5File(ctx context.Context, md5 string) (data *sysin.AttachmentListModel, err error) {
if err = dao.Ctx(ctx).
Where("md5", md5).
Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
if data == nil {
return nil, nil
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return nil, nil
}
data.SizeFormat = format.FileSize(data.Size)
data.FileUrl = service.CommonUpload().LastUrl(ctx, conf, data.FileUrl, data.Drive)
// 只有在上传时才会检查md5值如果文件存在则更新最后上传时间保证上传列表更新显示在最前面
if data.Id > 0 {
_, _ = dao.Ctx(ctx).Where("id", data.Id).Data(g.Map{
"status": consts.StatusEnabled,
"updated_at": gtime.Now(),
}).Update()
}
return data, nil
}

View File

@@ -23,10 +23,8 @@ func Tpl(name, tpl string) string {
// 最终效果:/应用名称/插件模块名称/xxx/xxx。如果你不喜欢现在的路由风格可以自行调整 // 最终效果:/应用名称/插件模块名称/xxx/xxx。如果你不喜欢现在的路由风格可以自行调整
func RouterPrefix(ctx context.Context, app, name string) string { func RouterPrefix(ctx context.Context, app, name string) string {
var prefix = "/" var prefix = "/"
if app != "" { if app != "" {
prefix = g.Cfg().MustGet(ctx, "router."+app+".prefix", "/"+app+"").String() prefix = g.Cfg().MustGet(ctx, "router."+app+".prefix", "/"+app+"").String()
} }
return prefix + "/" + name return prefix + "/" + name
} }

View File

@@ -91,7 +91,6 @@ func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err
if err = gfile.PutContents(webViewsPath+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil { if err = gfile.PutContents(webViewsPath+"/config/system.vue", gstr.ReplaceByMap(webConfigSystem, replaces)); err != nil {
return return
} }
return return
} }

View File

@@ -141,6 +141,5 @@ func ModuleSelect() form.Selects {
Name: skeleton.Label, Name: skeleton.Label,
}) })
} }
return lst return lst
} }

View File

@@ -104,21 +104,18 @@ func (a *adapter) model() *gdb.Model {
// create a policy table when it's not exists. // create a policy table when it's not exists.
func (a *adapter) createPolicyTable() (err error) { func (a *adapter) createPolicyTable() (err error) {
_, err = a.db.Exec(context.TODO(), fmt.Sprintf(createPolicyTableSql, a.table)) _, err = a.db.Exec(context.TODO(), fmt.Sprintf(createPolicyTableSql, a.table))
return return
} }
// drop policy table from the storage. // drop policy table from the storage.
func (a *adapter) dropPolicyTable() (err error) { func (a *adapter) dropPolicyTable() (err error) {
_, err = a.db.Exec(context.TODO(), fmt.Sprintf(dropPolicyTableSql, a.table)) _, err = a.db.Exec(context.TODO(), fmt.Sprintf(dropPolicyTableSql, a.table))
return return
} }
// LoadPolicy loads all policy rules from the storage. // LoadPolicy loads all policy rules from the storage.
func (a *adapter) LoadPolicy(model model.Model) (err error) { func (a *adapter) LoadPolicy(model model.Model) (err error) {
var rules []policyRule var rules []policyRule
if err = a.model().Scan(&rules); err != nil { if err = a.model().Scan(&rules); err != nil {
return return
} }
@@ -126,7 +123,6 @@ func (a *adapter) LoadPolicy(model model.Model) (err error) {
for _, rule := range rules { for _, rule := range rules {
a.loadPolicyRule(rule, model) a.loadPolicyRule(rule, model)
} }
return return
} }
@@ -159,14 +155,12 @@ func (a *adapter) SavePolicy(model model.Model) (err error) {
return return
} }
} }
return return
} }
// AddPolicy adds a policy rule to the storage. // AddPolicy adds a policy rule to the storage.
func (a *adapter) AddPolicy(sec string, ptype string, rule []string) (err error) { func (a *adapter) AddPolicy(sec string, ptype string, rule []string) (err error) {
_, err = a.model().Insert(a.buildPolicyRule(ptype, rule)) _, err = a.model().Insert(a.buildPolicyRule(ptype, rule))
return return
} }
@@ -183,7 +177,6 @@ func (a *adapter) AddPolicies(sec string, ptype string, rules [][]string) (err e
} }
_, err = a.model().Insert(policyRules) _, err = a.model().Insert(policyRules)
return return
} }
@@ -228,14 +221,12 @@ func (a *adapter) RemovePolicies(sec string, ptype string, rules [][]string) (er
} }
_, err = db.Delete() _, err = db.Delete()
return return
} }
// UpdatePolicy updates a policy rule from storage. // UpdatePolicy updates a policy rule from storage.
func (a *adapter) UpdatePolicy(sec string, ptype string, oldRule, newRule []string) (err error) { func (a *adapter) UpdatePolicy(sec string, ptype string, oldRule, newRule []string) (err error) {
_, err = a.model().Update(a.buildPolicyRule(ptype, newRule), a.buildPolicyRule(ptype, oldRule)) _, err = a.model().Update(a.buildPolicyRule(ptype, newRule), a.buildPolicyRule(ptype, oldRule))
return return
} }
@@ -244,18 +235,14 @@ func (a *adapter) UpdatePolicies(sec string, ptype string, oldRules, newRules []
if len(oldRules) == 0 || len(newRules) == 0 { if len(oldRules) == 0 || len(newRules) == 0 {
return return
} }
return a.db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
err = a.db.Transaction(context.TODO(), func(ctx context.Context, tx gdb.TX) error {
for i := 0; i < int(math.Min(float64(len(oldRules)), float64(len(newRules)))); i++ { for i := 0; i < int(math.Min(float64(len(oldRules)), float64(len(newRules)))); i++ {
if _, err = tx.Model(a.table).Update(a.buildPolicyRule(ptype, newRules[i]), a.buildPolicyRule(ptype, oldRules[i])); err != nil { if _, err = tx.Model(a.table).Update(a.buildPolicyRule(ptype, newRules[i]), a.buildPolicyRule(ptype, oldRules[i])); err != nil {
return err return err
} }
} }
return nil return nil
}) })
return
} }
// 加载策略规则 // 加载策略规则
@@ -285,7 +272,6 @@ func (a *adapter) loadPolicyRule(rule policyRule, model model.Model) {
if rule.V5 != "" { if rule.V5 != "" {
ruleText += ", " + rule.V5 ruleText += ", " + rule.V5
} }
if err := persist.LoadPolicyLine(ruleText, model); err != nil { if err := persist.LoadPolicyLine(ruleText, model); err != nil {
panic(err) panic(err)
} }
@@ -318,6 +304,5 @@ func (a *adapter) buildPolicyRule(ptype string, data []string) policyRule {
if len(data) > 5 { if len(data) > 5 {
rule.V5 = data[5] rule.V5 = data[5]
} }
return rule return rule
} }

View File

@@ -66,7 +66,6 @@ func GetUser(ctx context.Context) *model.Identity {
if c == nil { if c == nil {
return nil return nil
} }
return c.User return c.User
} }

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package ems package ems
import ( import (
@@ -47,6 +46,5 @@ func sendToMail(config *model.EmailConfig, to, subject, body, mailType string) e
} }
msg := []byte("To: " + to + "\r\nFrom: " + config.SendName + "<" + config.User + ">" + "\r\nSubject: " + subject + "\r\n" + contentType + "\r\n\r\n" + body) msg := []byte("To: " + to + "\r\nFrom: " + config.SendName + "<" + config.User + ">" + "\r\nSubject: " + subject + "\r\n" + contentType + "\r\n\r\n" + body)
return smtp.SendMail(config.Addr, auth, config.User, sendTo, msg) return smtp.SendMail(config.Addr, auth, config.User, sendTo, msg)
} }

View File

@@ -33,7 +33,6 @@ func Dao(ctx context.Context) (err error) {
} }
gendao.DoGenDaoForArray(ctx, inp) gendao.DoGenDaoForArray(ctx, inp)
} }
return return
} }
@@ -126,7 +125,6 @@ func TableSelects(ctx context.Context, in sysin.GenCodesSelectsInp) (res *sysin.
} }
res.Addons = addons.ModuleSelect() res.Addons = addons.ModuleSelect()
return return
} }
@@ -163,7 +161,6 @@ func GenTypeSelect(ctx context.Context) (res sysin.GenTypeSelects, err error) {
res = append(res, row) res = append(res, row)
} }
sort.Sort(res) sort.Sort(res)
return return
} }

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package hggen package hggen
import ( import (
@@ -77,7 +76,6 @@ func GetDaoConfig(group string) gendao.CGenDaoInput {
panic(err) panic(err)
} }
} }
return inp return inp
} }

View File

@@ -81,7 +81,7 @@ func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreview
} }
} }
dictTypeIds = convert.UniqueSliceInt64(dictTypeIds) dictTypeIds = convert.UniqueSlice(dictTypeIds)
if len(dictTypeIds) == 0 { if len(dictTypeIds) == 0 {
options["has"] = false options["has"] = false
return options, nil return options, nil

View File

@@ -108,8 +108,7 @@ func GenJoinSelect(ctx context.Context, entity interface{}, masterDao interface{
continue continue
} }
} }
return gstr.Implode(",", convert.UniqueSlice(tmpFields)), nil
return gstr.Implode(",", convert.UniqueSliceString(tmpFields)), nil
} }
// GenSelect 生成select // GenSelect 生成select
@@ -144,8 +143,7 @@ func GenSelect(ctx context.Context, entity interface{}, dao interface{}) (allFie
continue continue
} }
} }
return gstr.Implode(",", convert.UniqueSlice(tmpFields)), nil
return gstr.Implode(",", convert.UniqueSliceString(tmpFields)), nil
} }
// GetPkField 获取dao实例中的主键名称 // GetPkField 获取dao实例中的主键名称
@@ -163,7 +161,6 @@ func GetPkField(ctx context.Context, dao daoInstance) (string, error) {
return field.Name, nil return field.Name, nil
} }
} }
return "", errors.New("no primary key") return "", errors.New("no primary key")
} }

View File

@@ -38,7 +38,6 @@ func FilterAuth(m *gdb.Model) *gdb.Model {
if !needAuth { if !needAuth {
return m return m
} }
return m.Handler(FilterAuthWithField(filterField)) return m.Handler(FilterAuthWithField(filterField))
} }

View File

@@ -72,20 +72,19 @@ func WhoisLocation(ctx context.Context, ip string) (*IpLocationData, error) {
return nil, err return nil, err
} }
var whoisData *WhoisRegionData var who *WhoisRegionData
if err = gconv.Struct([]byte(str), &whoisData); err != nil { if err = gconv.Struct([]byte(str), &who); err != nil {
return nil, err return nil, err
} }
return &IpLocationData{ return &IpLocationData{
Ip: whoisData.Ip, Ip: who.Ip,
Region: whoisData.Addr, Region: who.Addr,
Province: whoisData.Pro, Province: who.Pro,
ProvinceCode: gconv.Int64(whoisData.ProCode), ProvinceCode: gconv.Int64(who.ProCode),
City: whoisData.City, City: who.City,
CityCode: gconv.Int64(whoisData.CityCode), CityCode: gconv.Int64(who.CityCode),
Area: whoisData.Region, Area: who.Region,
AreaCode: gconv.Int64(whoisData.RegionCode), AreaCode: gconv.Int64(who.RegionCode),
}, nil }, nil
} }
@@ -159,7 +158,6 @@ func GetLocation(ctx context.Context, ip string) (data *IpLocationData, err erro
} }
cacheMap.Set(ip, data) cacheMap.Set(ip, data)
} }
return return
} }
@@ -234,6 +232,5 @@ func GetClientIp(r *ghttp.Request) string {
if gstr.Contains(ip, ", ") { if gstr.Contains(ip, ", ") {
ip = gstr.StrTillEx(ip, ", ") ip = gstr.StrTillEx(ip, ", ")
} }
return ip return ip
} }

View File

@@ -52,7 +52,6 @@ func ParseSimpleRegion(ctx context.Context, id int64, spilt ...string) (string,
} }
return ParseRegion(ctx, ids[0], ids[1], id, spilt...) return ParseRegion(ctx, ids[0], ids[1], id, spilt...)
} }
return "", gerror.New("currently, it is only supported to regional areas") return "", gerror.New("currently, it is only supported to regional areas")
} }
@@ -104,6 +103,5 @@ func ParseRegion(ctx context.Context, province int64, city int64, county int64,
if province > 0 && city > 0 { if province > 0 && city > 0 {
return provinceName.String() + sp + cityName.String(), nil return provinceName.String() + sp + cityName.String(), nil
} }
return provinceName.String(), nil return provinceName.String(), nil
} }

View File

@@ -22,41 +22,42 @@ import (
// ClientConfig 客户端配置 // ClientConfig 客户端配置
type ClientConfig struct { type ClientConfig struct {
Addr string Addr string // 连接地址
Auth *AuthMeta Auth *AuthMeta // 认证元数据
Timeout time.Duration Timeout time.Duration // 连接超时时间
ConnectInterval time.Duration ConnectInterval time.Duration // 重连时间间隔
MaxConnectCount uint MaxConnectCount uint // 最大重连次数0不限次数
ConnectCount uint ConnectCount uint // 已重连次数
AutoReconnect bool AutoReconnect bool // 是否开启自动重连
LoginEvent CallbackEvent LoginEvent CallbackEvent // 登录成功事件
CloseEvent CallbackEvent CloseEvent CallbackEvent // 连接关闭事件
} }
// Client 客户端 // Client 客户端
type Client struct { type Client struct {
Ctx context.Context Ctx context.Context // 上下文
Logger *glog.Logger Logger *glog.Logger // 日志处理器
IsLogin bool // 是否已登录 IsLogin bool // 是否已登录
addr string addr string // 连接地址
auth *AuthMeta auth *AuthMeta // 认证元数据
rpc *Rpc rpc *Rpc // rpc协议支持
timeout time.Duration timeout time.Duration // 连接超时时间
connectInterval time.Duration connectInterval time.Duration // 重连时间间隔
maxConnectCount uint maxConnectCount uint // 最大重连次数0不限次数
connectCount uint connectCount uint // 已重连次数
autoReconnect bool autoReconnect bool // 是否开启自动重连
loginEvent CallbackEvent loginEvent CallbackEvent // 登录成功事件
closeEvent CallbackEvent closeEvent CallbackEvent // 连接关闭事件
sync.Mutex sync.Mutex // 状态锁
heartbeat int64 heartbeat int64 // 心跳
routers map[string]RouterHandler routers map[string]RouterHandler // 已注册的路由
conn *gtcp.Conn conn *gtcp.Conn // 连接对象
wg sync.WaitGroup wg sync.WaitGroup // 状态控制
closeFlag bool // 关闭标签,关闭以后可以重连 closeFlag bool // 关闭标签,关闭以后可以重连
stopFlag bool // 停止标签,停止以后不能重连 stopFlag bool // 停止标签,停止以后不能重连
} }
// NewClient 初始化一个tcp客户端
func NewClient(config *ClientConfig) (client *Client, err error) { func NewClient(config *ClientConfig) (client *Client, err error) {
client = new(Client) client = new(Client)
@@ -110,7 +111,7 @@ func NewClient(config *ClientConfig) (client *Client, err error) {
return return
} }
// Start 启动 // Start 启动tcp连接
func (client *Client) Start() (err error) { func (client *Client) Start() (err error) {
client.Lock() client.Lock()
defer client.Unlock() defer client.Unlock()
@@ -133,7 +134,6 @@ func (client *Client) Start() (err error) {
simple.SafeGo(client.Ctx, func(ctx context.Context) { simple.SafeGo(client.Ctx, func(ctx context.Context) {
client.connect() client.connect()
}) })
return return
} }
@@ -165,6 +165,7 @@ func (client *Client) RegisterRouter(routers map[string]RouterHandler) (err erro
return return
} }
// dial
func (client *Client) dial() *gtcp.Conn { func (client *Client) dial() *gtcp.Conn {
for { for {
conn, err := gtcp.NewConn(client.addr, client.timeout) conn, err := gtcp.NewConn(client.addr, client.timeout)
@@ -218,6 +219,7 @@ reconnect:
client.startCron() client.startCron()
} }
// read
func (client *Client) read() { func (client *Client) read() {
simple.SafeGo(client.Ctx, func(ctx context.Context) { simple.SafeGo(client.Ctx, func(ctx context.Context) {
defer func() { defer func() {
@@ -347,7 +349,6 @@ func (client *Client) Write(data interface{}) error {
return gerror.Newf("client json message pointer required: %+v", data) return gerror.Newf("client json message pointer required: %+v", data)
} }
msg := &Message{Router: msgType.Elem().Name(), Data: data} msg := &Message{Router: msgType.Elem().Name(), Data: data}
return SendPkg(client.conn, msg) return SendPkg(client.conn, msg)
} }
@@ -379,7 +380,6 @@ func (client *Client) RpcRequest(ctx context.Context, data interface{}) (res int
err = gerror.New("traceID is required") err = gerror.New("traceID is required")
return return
} }
return client.rpc.Request(key, func() { return client.rpc.Request(key, func() {
_ = client.Write(data) _ = client.Write(data)
}) })

View File

@@ -13,21 +13,24 @@ import (
"hotgo/internal/consts" "hotgo/internal/consts"
) )
// getCronKey 生成客户端定时任务名称
func (client *Client) getCronKey(s string) string { func (client *Client) getCronKey(s string) string {
return fmt.Sprintf("tcp.client_%s_%s:%s", s, client.auth.Group, client.auth.Name) return fmt.Sprintf("tcp.client_%s_%s:%s", s, client.auth.Group, client.auth.Name)
} }
// stopCron 停止定时任务
func (client *Client) stopCron() { func (client *Client) stopCron() {
for _, v := range gcron.Entries() { for _, v := range gcron.Entries() {
gcron.Remove(v.Name) gcron.Remove(v.Name)
} }
} }
// startCron 启动定时任务
func (client *Client) startCron() { func (client *Client) startCron() {
// 心跳超时检查 // 心跳超时检查
if gcron.Search(client.getCronKey(consts.TCPCronHeartbeatVerify)) == nil { if gcron.Search(client.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
_, _ = gcron.AddSingleton(client.Ctx, "@every 600s", func(ctx context.Context) { _, _ = gcron.AddSingleton(client.Ctx, "@every 600s", func(ctx context.Context) {
if client.heartbeat < gtime.Timestamp()-600 { if client.heartbeat < gtime.Timestamp()-consts.TCPHeartbeatTimeout {
client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..") client.Logger.Debugf(client.Ctx, "client heartbeat timeout, about to reconnect..")
client.Destroy() client.Destroy()
} }

View File

@@ -37,6 +37,7 @@ func (client *Client) serverLogin() {
} }
} }
// onResponseServerLogin 接收服务登陆响应结果
func (client *Client) onResponseServerLogin(ctx context.Context, args ...interface{}) { func (client *Client) onResponseServerLogin(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerLogin var in *msgin.ResponseServerLogin
if err := gconv.Scan(args[0], &in); err != nil { if err := gconv.Scan(args[0], &in); err != nil {
@@ -58,6 +59,7 @@ func (client *Client) onResponseServerLogin(ctx context.Context, args ...interfa
} }
} }
// onResponseServerHeartbeat 接收心跳响应结果
func (client *Client) onResponseServerHeartbeat(ctx context.Context, args ...interface{}) { func (client *Client) onResponseServerHeartbeat(ctx context.Context, args ...interface{}) {
var in *msgin.ResponseServerHeartbeat var in *msgin.ResponseServerHeartbeat
if err := gconv.Scan(args[0], &in); err != nil { if err := gconv.Scan(args[0], &in); err != nil {

View File

@@ -19,6 +19,7 @@ type AuthMeta struct {
EndAt *gtime.Time `json:"-"` EndAt *gtime.Time `json:"-"`
} }
// Context tcp上下文
type Context struct { type Context struct {
Conn *gtcp.Conn `json:"conn"` Conn *gtcp.Conn `json:"conn"`
Auth *AuthMeta `json:"auth"` // 认证元数据 Auth *AuthMeta `json:"auth"` // 认证元数据

View File

@@ -14,8 +14,10 @@ import (
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
) )
var GoPool = grpool.New(100) // GoPool 初始化一个协程池,用于处理消息处理
var GoPool = grpool.New(20)
// RouterHandler 路由消息处理器
type RouterHandler func(ctx context.Context, args ...interface{}) type RouterHandler func(ctx context.Context, args ...interface{})
// Message 路由消息 // Message 路由消息
@@ -24,6 +26,7 @@ type Message struct {
Data interface{} `json:"data"` Data interface{} `json:"data"`
} }
// SendPkg 打包发送的数据包
func SendPkg(conn *gtcp.Conn, message *Message) error { func SendPkg(conn *gtcp.Conn, message *Message) error {
b, err := json.Marshal(message) b, err := json.Marshal(message)
if err != nil { if err != nil {
@@ -32,6 +35,7 @@ func SendPkg(conn *gtcp.Conn, message *Message) error {
return conn.SendPkg(b) return conn.SendPkg(b)
} }
// RecvPkg 解包
func RecvPkg(conn *gtcp.Conn) (*Message, error) { func RecvPkg(conn *gtcp.Conn) (*Message, error) {
if data, err := conn.RecvPkg(); err != nil { if data, err := conn.RecvPkg(); err != nil {
return nil, err return nil, err
@@ -58,7 +62,6 @@ func MsgPkg(data interface{}, auth *AuthMeta, traceID string) string {
if msg == nil { if msg == nil {
return "" return ""
} }
return msg.TraceID return msg.TraceID
} }

View File

@@ -22,6 +22,7 @@ type Rpc struct {
callbacks map[string]RpcRespFunc callbacks map[string]RpcRespFunc
} }
// RpcResp 响应结构
type RpcResp struct { type RpcResp struct {
res interface{} res interface{}
err error err error
@@ -29,6 +30,7 @@ type RpcResp struct {
type RpcRespFunc func(resp interface{}, err error) type RpcRespFunc func(resp interface{}, err error)
// NewRpc 初始化一个rpc协议
func NewRpc(ctx context.Context) *Rpc { func NewRpc(ctx context.Context) *Rpc {
return &Rpc{ return &Rpc{
ctx: ctx, ctx: ctx,
@@ -57,7 +59,6 @@ func (r *Rpc) HandleMsg(ctx context.Context, cancel context.CancelFunc, data int
}) })
return true return true
} }
return false return false
} }
@@ -99,7 +100,7 @@ func (r *Rpc) Request(callId string, send func()) (res interface{}, err error) {
<-waitCh <-waitCh
select { select {
case <-time.After(consts.TCPRpcTimeout): case <-time.After(time.Second * consts.TCPRpcTimeout):
err = gerror.New("rpc response timeout") err = gerror.New("rpc response timeout")
return return
case got := <-resCh: case got := <-resCh:

View File

@@ -19,35 +19,38 @@ import (
"time" "time"
) )
// ClientConn 连接到tcp服务器的客户端对象
type ClientConn struct { type ClientConn struct {
Conn *gtcp.Conn Conn *gtcp.Conn // 连接对象
Auth *AuthMeta Auth *AuthMeta // 认证元数据
heartbeat int64 heartbeat int64 // 心跳
} }
// ServerConfig tcp服务器配置
type ServerConfig struct { type ServerConfig struct {
Name string // 服务名称 Name string // 服务名称
Addr string // 监听地址 Addr string // 监听地址
} }
// Server tcp服务器对象结构
type Server struct { type Server struct {
Ctx context.Context Ctx context.Context // 上下文
Logger *glog.Logger Logger *glog.Logger // 日志处理器
addr string addr string // 连接地址
name string name string // 服务器名称
rpc *Rpc rpc *Rpc // rpc协议
ln *gtcp.Server ln *gtcp.Server // tcp服务器
wgLn sync.WaitGroup wgLn sync.WaitGroup // 状态控制主要用于tcp服务器能够按流程启动退出
mutex sync.Mutex mutex sync.Mutex // 服务器状态锁
closeFlag bool closeFlag bool // 服务关闭标签
clients map[string]*ClientConn // 已登录的认证客户端 clients map[string]*ClientConn // 已登录的认证客户端
mutexConns sync.Mutex mutexConns sync.Mutex // 连接锁,主要用于客户端上下线
wgConns sync.WaitGroup cronRouters map[string]RouterHandler // 定时任务路由
cronRouters map[string]RouterHandler // 路由 queueRouters map[string]RouterHandler // 队列路由
queueRouters map[string]RouterHandler authRouters map[string]RouterHandler // 任务路由
authRouters map[string]RouterHandler
} }
// NewServer 初始一个tcp服务器对象
func NewServer(config *ServerConfig) (server *Server, err error) { func NewServer(config *ServerConfig) (server *Server, err error) {
if config == nil { if config == nil {
err = gerror.New("config is nil") err = gerror.New("config is nil")
@@ -84,6 +87,7 @@ func NewServer(config *ServerConfig) (server *Server, err error) {
return return
} }
// accept
func (server *Server) accept(conn *gtcp.Conn) { func (server *Server) accept(conn *gtcp.Conn) {
defer func() { defer func() {
server.mutexConns.Lock() server.mutexConns.Lock()
@@ -262,6 +266,7 @@ func (server *Server) RegisterQueueRouter(routers map[string]RouterHandler) {
} }
} }
// Listen 监听服务
func (server *Server) Listen() (err error) { func (server *Server) Listen() (err error) {
server.wgLn.Add(1) server.wgLn.Add(1)
defer server.wgLn.Done() defer server.wgLn.Done()
@@ -283,7 +288,6 @@ func (server *Server) Close() {
} }
server.clients = nil server.clients = nil
server.mutexConns.Unlock() server.mutexConns.Unlock()
server.wgConns.Wait()
if server.ln != nil { if server.ln != nil {
_ = server.ln.Close() _ = server.ln.Close()

View File

@@ -13,16 +13,19 @@ import (
"hotgo/internal/consts" "hotgo/internal/consts"
) )
// getCronKey 生成服务端定时任务名称
func (server *Server) getCronKey(s string) string { func (server *Server) getCronKey(s string) string {
return fmt.Sprintf("tcp.server_%s_%s", s, server.name) return fmt.Sprintf("tcp.server_%s_%s", s, server.name)
} }
// stopCron 停止定时任务
func (server *Server) stopCron() { func (server *Server) stopCron() {
for _, v := range gcron.Entries() { for _, v := range gcron.Entries() {
gcron.Remove(v.Name) gcron.Remove(v.Name)
} }
} }
// startCron 启动定时任务
func (server *Server) startCron() { func (server *Server) startCron() {
// 心跳超时检查 // 心跳超时检查
if gcron.Search(server.getCronKey(consts.TCPCronHeartbeatVerify)) == nil { if gcron.Search(server.getCronKey(consts.TCPCronHeartbeatVerify)) == nil {
@@ -31,7 +34,7 @@ func (server *Server) startCron() {
return return
} }
for _, client := range server.clients { for _, client := range server.clients {
if client.heartbeat < gtime.Timestamp()-300 { if client.heartbeat < gtime.Timestamp()-consts.TCPHeartbeatTimeout {
_ = client.Conn.Close() _ = client.Conn.Close()
server.Logger.Debugf(server.Ctx, "client heartbeat timeout, close conn. auth:%+v", client.Auth) server.Logger.Debugf(server.Ctx, "client heartbeat timeout, close conn. auth:%+v", client.Auth)
} }

View File

@@ -17,6 +17,7 @@ import (
"hotgo/utility/convert" "hotgo/utility/convert"
) )
// onServerLogin 处理客户端登录
func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) { func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) {
var ( var (
in = new(msgin.ServerLogin) in = new(msgin.ServerLogin)
@@ -137,6 +138,7 @@ func (server *Server) onServerLogin(ctx context.Context, args ...interface{}) {
_ = server.Write(user.Conn, res) _ = server.Write(user.Conn, res)
} }
// onServerHeartbeat 处理客户端心跳
func (server *Server) onServerHeartbeat(ctx context.Context, args ...interface{}) { func (server *Server) onServerHeartbeat(ctx context.Context, args ...interface{}) {
var ( var (
in *msgin.ServerHeartbeat in *msgin.ServerHeartbeat

View File

@@ -93,7 +93,6 @@ func (h *aliPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Not
res.OutTradeNo = notify.OutTradeNo res.OutTradeNo = notify.OutTradeNo
res.PayAt = notify.GmtPayment res.PayAt = notify.GmtPayment
res.ActualAmount = gconv.Float64(notify.ReceiptAmount) res.ActualAmount = gconv.Float64(notify.ReceiptAmount)
return return
} }
@@ -115,7 +114,6 @@ func (h *aliPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res
default: default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType) err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
} }
return return
} }

View File

@@ -44,7 +44,6 @@ func New(name ...string) PayClient {
default: default:
panic(fmt.Sprintf("暂不支持的支付方式:%v", payType)) panic(fmt.Sprintf("暂不支持的支付方式:%v", payType))
} }
return client return client
} }

View File

@@ -75,7 +75,6 @@ func (h *qqPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Noti
res.OutTradeNo = notify.OutTradeNo res.OutTradeNo = notify.OutTradeNo
res.PayAt = gtime.New(notify.TimeEnd) res.PayAt = gtime.New(notify.TimeEnd)
res.ActualAmount = gconv.Float64(notify.CouponFee) / 100 // 用户本次交易中,实际支付的金额 转为元,和系统内保持一至 res.ActualAmount = gconv.Float64(notify.CouponFee) / 100 // 用户本次交易中,实际支付的金额 转为元,和系统内保持一至
return return
} }
@@ -119,7 +118,6 @@ func (h *qqPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *
default: default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType) err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
} }
return return
} }

View File

@@ -105,7 +105,6 @@ func (h *wxPay) Notify(ctx context.Context, in payin.NotifyInp) (res *payin.Noti
res.OutTradeNo = notify.OutTradeNo res.OutTradeNo = notify.OutTradeNo
res.PayAt = gtime.New(notify.SuccessTime) res.PayAt = gtime.New(notify.SuccessTime)
res.ActualAmount = float64(notify.Amount.PayerTotal / 100) // 转为元,和系统内保持一至 res.ActualAmount = float64(notify.Amount.PayerTotal / 100) // 转为元,和系统内保持一至
return return
} }
@@ -121,7 +120,6 @@ func (h *wxPay) CreateOrder(ctx context.Context, in payin.CreateOrderInp) (res *
default: default:
err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType) err = gerror.Newf("暂未支持的交易方式:%v", in.Pay.TradeType)
} }
return return
} }

View File

@@ -69,5 +69,4 @@ func consumerListen(ctx context.Context, job consumerStrategy) {
}); listenErr != nil { }); listenErr != nil {
g.Log().Fatalf(ctx, "消费队列:%s 监听失败, err:%+v", topic, listenErr) g.Log().Fatalf(ctx, "消费队列:%s 监听失败, err:%+v", topic, listenErr)
} }
} }

View File

@@ -11,7 +11,8 @@ import (
"github.com/Shopify/sarama" "github.com/Shopify/sarama"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"hotgo/utility/signal" "github.com/gogf/gf/v2/os/gproc"
"os"
"time" "time"
) )
@@ -109,14 +110,13 @@ func (r *KafkaMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
<-consumer.ready <-consumer.ready
g.Log().Debug(ctx, "kafka consumer up and running!...") g.Log().Debug(ctx, "kafka consumer up and running!...")
signal.AppDefer(func() { gproc.AddSigHandlerShutdown(func(sig os.Signal) {
g.Log().Debug(ctx, "kafka consumer close...") g.Log().Debug(ctx, "kafka consumer close...")
cancel() cancel()
if err = r.consumerIns.Close(); err != nil { if err = r.consumerIns.Close(); err != nil {
g.Log().Fatalf(ctx, "kafka Error closing client, err:%+v", err) g.Log().Fatalf(ctx, "kafka Error closing client, err:%+v", err)
} }
}) })
return return
} }
@@ -203,7 +203,7 @@ func doRegisterKafkaProducer(connOpt KafkaConfig, mqIns *KafkaMq) (err error) {
return return
} }
signal.AppDefer(func() { gproc.AddSigHandlerShutdown(func(sig os.Signal) {
g.Log().Debug(ctx, "kafka producer AsyncClose...") g.Log().Debug(ctx, "kafka producer AsyncClose...")
mqIns.producerIns.AsyncClose() mqIns.producerIns.AsyncClose()
}) })

View File

@@ -0,0 +1,22 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model"
)
var config *model.UploadConfig
func SetConfig(c *model.UploadConfig) {
config = c
}
func GetConfig() *model.UploadConfig {
return config
}
func GetModel(ctx context.Context) *gdb.Model {
return g.Model("sys_attachment").Ctx(ctx)
}

View File

@@ -1,9 +1,9 @@
// Package file // Package storager
// @Link https://github.com/bufanyun/hotgo // @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
package file package storager
import ( import (
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
@@ -14,7 +14,7 @@ import (
"path" "path"
) )
// 文件分类 // 文件归属分类
const ( const (
KindImg = "images" // 图片 KindImg = "images" // 图片
KindDoc = "document" // 文档 KindDoc = "document" // 文档
@@ -85,6 +85,24 @@ func IsImgType(ext string) bool {
return ok return ok
} }
// IsDocType 判断是否为文档
func IsDocType(ext string) bool {
_, ok := docType[ext]
return ok
}
// IsAudioType 判断是否为音频
func IsAudioType(ext string) bool {
_, ok := audioType[ext]
return ok
}
// IsVideoType 判断是否为视频
func IsVideoType(ext string) bool {
_, ok := videoType[ext]
return ok
}
// GetImgType 获取图片类型 // GetImgType 获取图片类型
func GetImgType(ext string) (string, error) { func GetImgType(ext string) (string, error) {
if mime, ok := imgType[ext]; ok { if mime, ok := imgType[ext]; ok {

View File

@@ -0,0 +1,12 @@
package storager
// FileMeta 文件元数据
type FileMeta struct {
Filename string // 文件名称
Size int64 // 文件大小
Kind string // 文件所属分类
MetaType string // 文件类型
NaiveType string // NaiveUI类型
Ext string // 文件后缀名
Md5 string // 文件hash
}

View File

@@ -0,0 +1,228 @@
package storager
import (
"context"
"fmt"
"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/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"hotgo/internal/consts"
"hotgo/internal/library/contexts"
"hotgo/internal/model/entity"
"hotgo/utility/encrypt"
"hotgo/utility/url"
"hotgo/utility/validate"
"strconv"
"strings"
)
// UploadDrive 存储驱动
type UploadDrive interface {
// Upload 上传
Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error)
}
// New 初始化存储驱动
func New(name ...string) UploadDrive {
var (
driveType = consts.UploadDriveLocal
drive UploadDrive
)
if len(name) > 0 && name[0] != "" {
driveType = name[0]
}
switch driveType {
case consts.UploadDriveLocal:
drive = &LocalDrive{}
case consts.UploadDriveUCloud:
drive = &UCloudDrive{}
case consts.UploadDriveCos:
drive = &CosDrive{}
case consts.UploadDriveOss:
drive = &OssDrive{}
case consts.UploadDriveQiNiu:
drive = &QiNiuDrive{}
default:
panic(fmt.Sprintf("暂不支持的存储驱动:%v", driveType))
}
return drive
}
// DoUpload 上传入口
func DoUpload(ctx context.Context, file *ghttp.UploadFile, typ int) (result *entity.SysAttachment, err error) {
if file == nil {
err = gerror.New("文件必须!")
return
}
meta, err := GetFileMeta(file)
if err != nil {
return
}
if _, err = GetFileType(meta.Ext); err != nil {
return
}
switch typ {
case consts.UploadTypeFile:
if config.FileSize > 0 && meta.Size > config.FileSize*1024*1024 {
err = gerror.Newf("文件大小不能超过%vMB", config.FileSize)
return
}
case consts.UploadTypeImage:
if !IsImgType(meta.Ext) {
err = gerror.New("上传的文件不是图片")
return
}
if config.ImageSize > 0 && meta.Size > config.ImageSize*1024*1024 {
err = gerror.Newf("图片大小不能超过%vMB", config.ImageSize)
return
}
case consts.UploadTypeDoc:
if !IsDocType(meta.Ext) {
err = gerror.New("上传的文件不是文档")
return
}
case consts.UploadTypeAudio:
if !IsAudioType(meta.Ext) {
err = gerror.New("上传的文件不是音频")
return
}
case consts.UploadTypeVideo:
if !IsVideoType(meta.Ext) {
err = gerror.New("上传的文件不是视频")
return
}
default:
err = gerror.Newf("无效的上传类型:%v", typ)
return
}
result, err = hasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
// 上传到驱动
fullPath, err := New(config.Drive).Upload(ctx, file)
if err != nil {
return
}
// 写入附件记录
return write(ctx, meta, fullPath)
}
// LastUrl 根据驱动获取最终文件访问地址
func LastUrl(ctx context.Context, fullPath, drive string) string {
if validate.IsURL(fullPath) {
return fullPath
}
switch drive {
case consts.UploadDriveLocal:
return url.GetAddr(ctx) + "/" + fullPath
case consts.UploadDriveUCloud:
return config.UCloudEndpoint + "/" + fullPath
case consts.UploadDriveCos:
return config.CosBucketURL + "/" + fullPath
case consts.UploadDriveOss:
return config.OssBucketURL + "/" + fullPath
case consts.UploadDriveQiNiu:
return config.QiNiuDomain + "/" + fullPath
default:
return fullPath
}
}
// GetFileMeta 获取上传文件元数据
func GetFileMeta(file *ghttp.UploadFile) (meta *FileMeta, err error) {
meta = new(FileMeta)
meta.Filename = file.Filename
meta.Size = file.Size
meta.Ext = Ext(file.Filename)
meta.Kind = GetFileKind(meta.Ext)
meta.MetaType, err = GetFileType(meta.Ext)
if err != nil {
return
}
// 兼容naiveUI
naiveType := "text/plain"
if IsImgType(Ext(file.Filename)) {
naiveType = ""
}
meta.NaiveType = naiveType
// 文件hash
b, err := UploadFileByte(file)
if err != nil {
return
}
meta.Md5 = encrypt.Md5ToString(gconv.String(encrypt.Hash32(b)))
return
}
// GenFullPath 根据目录和文件类型生成一个绝对地址
func GenFullPath(basePath, ext string) string {
fileName := strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6)
fileName = fileName + ext
return basePath + gtime.Date() + "/" + strings.ToLower(fileName)
}
// write 写入附件记录
func write(ctx context.Context, meta *FileMeta, fullPath string) (models *entity.SysAttachment, err error) {
models = &entity.SysAttachment{
Id: 0,
AppId: contexts.GetModule(ctx),
MemberId: contexts.GetUserId(ctx),
Drive: config.Drive,
Size: meta.Size,
Path: fullPath,
FileUrl: fullPath,
Name: meta.Filename,
Kind: meta.Kind,
MetaType: meta.MetaType,
NaiveType: meta.NaiveType,
Ext: meta.Ext,
Md5: meta.Md5,
Status: consts.StatusEnabled,
}
id, err := GetModel(ctx).Data(models).InsertAndGetId()
if err != nil {
return
}
models.Id = id
return
}
// hasFile 检查附件是否存在
func hasFile(ctx context.Context, md5 string) (res *entity.SysAttachment, err error) {
if err = GetModel(ctx).Where("md5", md5).Scan(&res); err != nil {
err = gerror.Wrap(err, "检查文件hash时出现错误")
return
}
if res == nil {
return
}
// 只有在上传时才会检查md5值如果附件存在则更新最后上传时间保证上传列表更新显示在最前面
if res.Id > 0 {
_, _ = GetModel(ctx).WherePri(res.Id).Data(g.Map{
"status": consts.StatusEnabled,
"updated_at": gtime.Now(),
}).Update()
}
return
}

View File

@@ -0,0 +1,42 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/tencentyun/cos-go-sdk-v5"
"net/http"
"net/url"
)
// CosDrive 腾讯云cos驱动
type CosDrive struct {
}
// Upload 上传到腾讯云cos对象存储
func (d *CosDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.CosPath == "" {
err = gerror.New("COS存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
URL, _ := url.Parse(config.CosBucketURL)
client := cos.NewClient(&cos.BaseURL{BucketURL: URL}, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: config.CosSecretId,
SecretKey: config.CosSecretKey,
},
})
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
_, err = client.Object.Put(ctx, fullPath, f2, nil)
return
}

View File

@@ -0,0 +1,42 @@
package storager
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/gtime"
"strings"
)
// LocalDrive 本地驱动
type LocalDrive struct {
}
// Upload 上传到本地
func (d *LocalDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
var (
sp = g.Cfg().MustGet(ctx, "server.serverRoot")
nowDate = gtime.Date()
)
if sp.IsEmpty() {
err = gerror.New("本地上传驱动必须配置静态路径!")
return
}
if config.LocalPath == "" {
err = gerror.New("本地上传驱动必须配置本地存储路径!")
return
}
// 包含静态文件夹的路径
fullDirPath := strings.Trim(sp.String(), "/") + "/" + config.LocalPath + nowDate
fileName, err := file.Save(fullDirPath, true)
if err != nil {
return
}
// 不含静态文件夹的路径
fullPath = config.LocalPath + nowDate + "/" + fileName
return
}

View File

@@ -0,0 +1,42 @@
package storager
import (
"context"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
)
// OssDrive 阿里云oss驱动
type OssDrive struct {
}
// Upload 上传到阿里云oss
func (d *OssDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.OssPath == "" {
err = gerror.New("OSS存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
client, err := oss.New(config.OssEndpoint, config.OssSecretId, config.OssSecretKey)
if err != nil {
return
}
bucket, err := client.Bucket(config.OssBucket)
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = bucket.PutObject(fullPath, f2)
return
}

View File

@@ -0,0 +1,52 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
)
// QiNiuDrive 七牛云对象存储驱动
type QiNiuDrive struct {
}
// Upload 上传到七牛云对象存储
func (d *QiNiuDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.QiNiuPath == "" {
err = gerror.New("七牛云存储驱动必须配置存储路径!")
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
putPolicy := storage.PutPolicy{
Scope: config.QiNiuBucket,
}
token := putPolicy.UploadToken(qbox.NewMac(config.QiNiuAccessKey, config.QiNiuSecretKey))
cfg := storage.Config{}
// 是否使用https域名
cfg.UseHTTPS = true
// 上传是否使用CDN上传加速
cfg.UseCdnDomains = false
// 空间对应的机房
cfg.Region, err = storage.GetRegion(config.QiNiuAccessKey, config.QiNiuBucket)
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = storage.NewFormUploader(&cfg).Put(ctx, &storage.PutRet{}, token, fullPath, f2, file.Size, &storage.PutExtra{})
return
}

View File

@@ -0,0 +1,45 @@
package storager
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
upload "github.com/ufilesdk-dev/ufile-gosdk"
)
// UCloudDrive UCloud对象存储驱动
type UCloudDrive struct {
}
// Upload 上传到UCloud对象存储
func (d *UCloudDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error) {
if config.UCloudPath == "" {
err = gerror.New("UCloud存储驱动必须配置存储路径!")
return
}
client, err := upload.NewFileRequest(&upload.Config{
PublicKey: config.UCloudPublicKey,
PrivateKey: config.UCloudPrivateKey,
BucketHost: config.UCloudBucketHost,
BucketName: config.UCloudBucketName,
FileHost: config.UCloudFileHost,
Endpoint: config.UCloudEndpoint,
VerifyUploadMD5: false,
}, nil)
if err != nil {
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
fullPath = GenFullPath(config.UCloudPath, gfile.Ext(file.Filename))
err = client.IOPut(f2, fullPath, "")
return
}

View File

@@ -223,8 +223,8 @@ func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (res *adm
} }
if len(ids) > 0 { if len(ids) > 0 {
ids = convert.UniqueSliceInt64(ids) ids = convert.UniqueSlice(ids)
pids = convert.UniqueSliceInt64(pids) pids = convert.UniqueSlice(pids)
mod = mod.Wheref(`id in (?) or pid in (?)`, ids, pids) mod = mod.Wheref(`id in (?) or pid in (?)`, ids, pids)
} }

View File

@@ -307,6 +307,6 @@ func (s *sAdminMenu) LoginPermissions(ctx context.Context, memberId int64) (list
} }
} }
lists = convert.UniqueSliceString(lists) lists = convert.UniqueSlice(lists)
return return
} }

View File

@@ -124,7 +124,7 @@ func (s *sAdminNotice) Status(ctx context.Context, in adminin.NoticeStatusInp) (
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }
@@ -322,16 +322,14 @@ func (s *sAdminNotice) UnreadCount(ctx context.Context, in adminin.NoticeUnreadC
// messageIds 获取我的消息所有的消息ID // messageIds 获取我的消息所有的消息ID
func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []int64, err error) { func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []int64, err error) {
mod := s.Model(ctx, &handler.Option{FilterAuth: false}). array, err := s.Model(ctx, &handler.Option{FilterAuth: false}).
Fields("id"). Fields("id").
Where("status", consts.StatusEnabled). Where("status", consts.StatusEnabled).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))", Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))",
[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter, []int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter,
) ).Array()
array, err := mod.Array()
if err != nil { if err != nil {
return nil, err return
} }
for _, v := range array { for _, v := range array {
@@ -351,14 +349,15 @@ func (s *sAdminNotice) UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (
err = gerror.New("获取用户信息失败!") err = gerror.New("获取用户信息失败!")
return return
} }
if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&data); err != nil { if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return
} }
if data == nil { if data == nil {
return gerror.New("公告不存在") return gerror.New("公告不存在")
} }
return s.updatedReadClicks(ctx, in.Id, memberId) return s.updatedReadClicks(ctx, in.Id, memberId)
} }
@@ -408,13 +407,12 @@ func (s *sAdminNotice) ReadAll(ctx context.Context, in adminin.NoticeReadAllInp)
} }
for _, messageId := range messageIds { for _, messageId := range messageIds {
if !validate.InSliceInt64(readIds, messageId) { if !validate.InSlice(readIds, messageId) {
if err = s.updatedReadClicks(ctx, messageId, memberId); err != nil { if err = s.updatedReadClicks(ctx, messageId, memberId); err != nil {
return return
} }
} }
} }
return return
} }
@@ -435,7 +433,7 @@ func (s *sAdminNotice) updatedReadClicks(ctx context.Context, noticeId, memberId
_, err = dao.AdminNoticeRead.Ctx(ctx).Data(entity.AdminNoticeRead{NoticeId: noticeId, MemberId: memberId}).Insert() _, err = dao.AdminNoticeRead.Ctx(ctx).Data(entity.AdminNoticeRead{NoticeId: noticeId, MemberId: memberId}).Insert()
return return
} }
_, err = dao.AdminNoticeRead.Ctx(ctx).Where(dao.AdminNoticeRead.Columns().Id, models.Id).Increment("clicks", 1) _, err = dao.AdminNoticeRead.Ctx(ctx).Where(dao.AdminNoticeRead.Columns().Id, models.Id).Increment(dao.AdminNoticeRead.Columns().Clicks, 1)
return return
} }

View File

@@ -382,7 +382,7 @@ func (s *sAdminOrder) Status(ctx context.Context, in adminin.OrderStatusInp) (er
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -203,7 +203,7 @@ func (s *sAdminPost) Status(ctx context.Context, in adminin.PostStatusInp) (err
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -57,7 +57,6 @@ func (s *sAdminRole) Verify(ctx context.Context, path, method string) bool {
g.Log().Infof(ctx, "admin Verify Enforce err:%+v", err) g.Log().Infof(ctx, "admin Verify Enforce err:%+v", err)
return false return false
} }
return ok return ok
} }
@@ -102,7 +101,6 @@ func (s *sAdminRole) GetName(ctx context.Context, id int64) (name string, err er
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return return
} }
return r.String(), nil return r.String(), nil
} }
@@ -148,7 +146,7 @@ func (s *sAdminRole) UpdatePermissions(ctx context.Context, in adminin.UpdatePer
} }
// 去重 // 去重
in.MenuIds = convert.UniqueSliceInt64(in.MenuIds) in.MenuIds = convert.UniqueSlice(in.MenuIds)
list := make(g.List, 0, len(in.MenuIds)) list := make(g.List, 0, len(in.MenuIds))
for _, v := range in.MenuIds { for _, v := range in.MenuIds {
@@ -169,7 +167,6 @@ func (s *sAdminRole) UpdatePermissions(ctx context.Context, in adminin.UpdatePer
if err != nil { if err != nil {
return return
} }
return casbin.Refresh(ctx) return casbin.Refresh(ctx)
} }
@@ -296,19 +293,18 @@ func (s *sAdminRole) DataScopeEdit(ctx context.Context, in *adminin.DataScopeEdi
return gerror.New("超管角色拥有全部权限,无需修改!") return gerror.New("超管角色拥有全部权限,无需修改!")
} }
if in.DataScope == consts.RoleDataDeptCustom && len(convert.UniqueSliceInt64(in.CustomDept)) == 0 { if in.DataScope == consts.RoleDataDeptCustom && len(convert.UniqueSlice(in.CustomDept)) == 0 {
return gerror.New("自定义权限必须配置自定义部门!") return gerror.New("自定义权限必须配置自定义部门!")
} }
models.DataScope = in.DataScope models.DataScope = in.DataScope
models.CustomDept = gjson.New(convert.UniqueSliceInt64(in.CustomDept)) models.CustomDept = gjson.New(convert.UniqueSlice(in.CustomDept))
_, err = dao.AdminRole.Ctx(ctx). _, err = dao.AdminRole.Ctx(ctx).
Fields(dao.AdminRole.Columns().DataScope, dao.AdminRole.Columns().CustomDept). Fields(dao.AdminRole.Columns().DataScope, dao.AdminRole.Columns().CustomDept).
Where("id", in.Id). Where("id", in.Id).
Data(models). Data(models).
Update() Update()
return return
} }

View File

@@ -7,33 +7,12 @@ package common
import ( import (
"context" "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/net/ghttp"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"github.com/qiniu/go-sdk/v7/auth/qbox"
"github.com/qiniu/go-sdk/v7/storage"
"github.com/tencentyun/cos-go-sdk-v5"
ufile "github.com/ufilesdk-dev/ufile-gosdk"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/library/storager"
"hotgo/internal/model"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/encrypt"
f "hotgo/utility/file"
"hotgo/utility/format" "hotgo/utility/format"
utilityurl "hotgo/utility/url"
"hotgo/utility/validate"
"net/http"
"net/url"
"strconv"
"strings"
"time"
) )
type sCommonUpload struct{} type sCommonUpload struct{}
@@ -47,391 +26,31 @@ func init() {
} }
// UploadFile 上传文件 // UploadFile 上传文件
func (s *sCommonUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) { func (s *sCommonUpload) UploadFile(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error) {
if file == nil { attachment, err := storager.DoUpload(ctx, file, consts.UploadTypeFile)
err = gerror.New("文件必须!")
return
}
meta, err := s.fileMeta(file)
if err != nil { if err != nil {
return return
} }
if _, err = f.GetFileType(meta.Ext); err != nil { attachment.FileUrl = storager.LastUrl(ctx, attachment.FileUrl, attachment.Drive)
return res = &sysin.AttachmentListModel{
} SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
result, err = s.HasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return
}
switch conf.Drive {
case consts.UploadDriveLocal:
return s.UploadLocal(ctx, conf, file, meta)
case consts.UploadDriveUCloud:
return s.UploadUCloud(ctx, conf, file, meta)
case consts.UploadDriveCos:
return s.UploadCOS(ctx, conf, file, meta)
case consts.UploadDriveOss:
return s.UploadOSS(ctx, conf, file, meta)
case consts.UploadDriveQiNiu:
return s.UploadQiNiu(ctx, conf, file, meta)
default:
return nil, gerror.Newf("暂不支持上传驱动:%v", conf.Drive)
} }
return
} }
// UploadImage 上传图片 // UploadImage 上传图片
func (s *sCommonUpload) UploadImage(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) { func (s *sCommonUpload) UploadImage(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error) {
if file == nil { attachment, err := storager.DoUpload(ctx, file, consts.UploadTypeImage)
err = gerror.New("文件必须!")
return
}
meta, err := s.fileMeta(file)
if err != nil { if err != nil {
return return
} }
if !f.IsImgType(meta.Ext) { attachment.FileUrl = storager.LastUrl(ctx, attachment.FileUrl, attachment.Drive)
err = gerror.New("上传的文件不是图片") res = &sysin.AttachmentListModel{
return
}
if meta.Size > 2*1024*1024 {
err = gerror.New("图片大小不能超过2MB")
return
}
result, err = s.HasFile(ctx, meta.Md5)
if err != nil {
return
}
if result != nil {
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return
}
switch conf.Drive {
case consts.UploadDriveLocal:
return s.UploadLocal(ctx, conf, file, meta)
case consts.UploadDriveUCloud:
return s.UploadUCloud(ctx, conf, file, meta)
case consts.UploadDriveCos:
return s.UploadCOS(ctx, conf, file, meta)
case consts.UploadDriveOss:
return s.UploadOSS(ctx, conf, file, meta)
case consts.UploadDriveQiNiu:
return s.UploadQiNiu(ctx, conf, file, meta)
default:
err = gerror.Newf("暂不支持上传驱动:%v", conf.Drive)
return
}
}
// UploadLocal 上传本地
func (s *sCommonUpload) UploadLocal(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
var (
value = g.Cfg().MustGet(ctx, "server.serverRoot")
nowDate = time.Now().Format("2006-01-02")
)
if value.IsEmpty() {
err = gerror.New("本地上传驱动必须配置静态路径!")
return
}
if conf.LocalPath == "" {
err = gerror.New("本地上传驱动必须配置本地存储路径!")
return
}
// 包含静态文件夹的路径
fullDirPath := strings.Trim(value.String(), "/") + "/" + conf.LocalPath + nowDate
fileName, err := file.Save(fullDirPath, true)
if err != nil {
return
}
// 不含静态文件夹的路径
fullPath := conf.LocalPath + nowDate + "/" + fileName
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveLocal)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment, SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size), SizeFormat: format.FileSize(attachment.Size),
} }
return return
} }
// UploadUCloud 上传UCloud对象存储
func (s *sCommonUpload) UploadUCloud(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.UCloudPath == "" {
err = gerror.New("UCloud存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.UCloudPath + nowDate + "/" + fileName
config := &ufile.Config{
PublicKey: conf.UCloudPublicKey,
PrivateKey: conf.UCloudPrivateKey,
BucketHost: conf.UCloudBucketHost,
BucketName: conf.UCloudBucketName,
FileHost: conf.UCloudFileHost,
Endpoint: conf.UCloudEndpoint,
VerifyUploadMD5: false,
}
req, err := ufile.NewFileRequest(config, nil)
if err != nil {
return
}
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
if err = req.IOPut(f2, fullPath, ""); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveUCloud)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadCOS 上传腾讯云对象存储
func (s *sCommonUpload) UploadCOS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.CosPath == "" {
err = gerror.New("COS存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.CosPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
u, _ := url.Parse(conf.CosBucketURL)
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{
Transport: &cos.AuthorizationTransport{
SecretID: conf.CosSecretId,
SecretKey: conf.CosSecretKey,
},
})
if _, err = c.Object.Put(ctx, fullPath, f2, nil); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveCos)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadOSS 上传阿里云云对象存储
func (s *sCommonUpload) UploadOSS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.OssPath == "" {
err = gerror.New("OSS存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.OssPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
client, err := oss.New(conf.OssEndpoint, conf.OssSecretId, conf.OssSecretKey)
if err != nil {
return
}
bucket, err := client.Bucket(conf.OssBucket)
if err != nil {
return
}
if err = bucket.PutObject(fullPath, f2); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveOss)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// UploadQiNiu 上传七牛云对象存储
func (s *sCommonUpload) UploadQiNiu(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error) {
if conf.QiNiuPath == "" {
err = gerror.New("七牛云存储驱动必须配置存储路径!")
return
}
nowDate := time.Now().Format("2006-01-02")
fileName := strings.ToLower(strconv.FormatInt(gtime.TimestampNano(), 36) + grand.S(6))
fileName = fileName + gfile.Ext(file.Filename)
fullPath := conf.QiNiuPath + nowDate + "/" + fileName
// 流式上传本地小文件
f2, err := file.Open()
defer func() { _ = f2.Close() }()
if err != nil {
return
}
putPolicy := storage.PutPolicy{
Scope: conf.QiNiuBucket,
}
token := putPolicy.UploadToken(qbox.NewMac(conf.QiNiuAccessKey, conf.QiNiuSecretKey))
cfg := storage.Config{}
// 是否使用https域名
cfg.UseHTTPS = true
// 上传是否使用CDN上传加速
cfg.UseCdnDomains = false
// 空间对应的机房
cfg.Region, err = storage.GetRegion(conf.QiNiuAccessKey, conf.QiNiuBucket)
if err != nil {
return
}
if err = storage.NewFormUploader(&cfg).Put(ctx, &storage.PutRet{}, token, fullPath, f2, file.Size, &storage.PutExtra{}); err != nil {
return
}
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveQiNiu)
if err != nil {
return
}
attachment.FileUrl = s.LastUrl(ctx, conf, attachment.FileUrl, attachment.Drive)
result = &sysin.AttachmentListModel{
SysAttachment: *attachment,
SizeFormat: format.FileSize(attachment.Size),
}
return
}
// LastUrl 根据驱动获取最终文件访问地址
func (s *sCommonUpload) LastUrl(ctx context.Context, conf *model.UploadConfig, fullPath, drive string) string {
if validate.IsURL(fullPath) {
return fullPath
}
switch drive {
case consts.UploadDriveLocal:
return utilityurl.GetAddr(ctx) + "/" + fullPath
case consts.UploadDriveUCloud:
return conf.UCloudEndpoint + "/" + fullPath
case consts.UploadDriveCos:
return conf.CosBucketURL + "/" + fullPath
case consts.UploadDriveOss:
return conf.OssBucketURL + "/" + fullPath
case consts.UploadDriveQiNiu:
return conf.QiNiuDomain + "/" + fullPath
default:
return fullPath
}
}
// HasFile 文件是否存在
func (s *sCommonUpload) HasFile(ctx context.Context, md5 string) (res *sysin.AttachmentListModel, err error) {
res, err = dao.SysAttachment.GetMd5File(ctx, md5)
return
}
// fileMeta 上传文件元数据
func (s *sCommonUpload) fileMeta(file *ghttp.UploadFile) (meta *sysin.UploadFileMeta, err error) {
meta = new(sysin.UploadFileMeta)
meta.Filename = file.Filename
meta.Size = file.Size
meta.Ext = f.Ext(file.Filename)
meta.Kind = f.GetFileKind(meta.Ext)
meta.MetaType, err = f.GetFileType(meta.Ext)
if err != nil {
return
}
// 兼容naiveUI
naiveType := "text/plain"
if f.IsImgType(f.Ext(file.Filename)) {
naiveType = ""
}
meta.NaiveType = naiveType
// 文件hash
b, err := f.UploadFileByte(file)
if err != nil {
return
}
meta.Md5 = encrypt.Md5ToString(gconv.String(encrypt.Hash32(b)))
return
}

View File

@@ -32,7 +32,6 @@ func (s *sMiddleware) AdminAuth(r *ghttp.Request) {
// 将用户信息传递到上下文中 // 将用户信息传递到上下文中
if err := deliverUserContext(r); err != nil { if err := deliverUserContext(r); err != nil {
g.Log().Warningf(ctx, "deliverUserContext err:%+v", err)
response.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error()) response.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error())
return return
} }

View File

@@ -138,7 +138,7 @@ func (s *sPay) Status(ctx context.Context, in payin.PayStatusInp) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -90,7 +90,6 @@ func (s *sSysAddons) List(ctx context.Context, in sysin.AddonsListInp) (list []*
} }
totalCount = len(sks) totalCount = len(sks)
return return
} }
@@ -129,7 +128,6 @@ func (s *sSysAddons) Build(ctx context.Context, in sysin.AddonsBuildInp) (err er
err = gerror.New("没有找到有效的生成或插件配置,请检查配置文件是否正常") err = gerror.New("没有找到有效的生成或插件配置,请检查配置文件是否正常")
return return
} }
return addons.Build(ctx, in.Skeleton, genConfig.Addon) return addons.Build(ctx, in.Skeleton, genConfig.Addon)
} }

View File

@@ -54,8 +54,8 @@ func (s *sSysAddonsConfig) GetConfigByGroup(ctx context.Context, in sysin.GetAdd
Scan(&models); err != nil { Scan(&models); err != nil {
return nil, err return nil, err
} }
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false)
if len(models) > 0 { if len(models) > 0 {
res = new(sysin.GetAddonsConfigModel) res = new(sysin.GetAddonsConfigModel)
res.List = make(g.Map, len(models)) res.List = make(g.Map, len(models))
@@ -71,7 +71,6 @@ func (s *sSysAddonsConfig) GetConfigByGroup(ctx context.Context, in sysin.GetAdd
} }
} }
} }
return return
} }
@@ -105,10 +104,10 @@ func (s *sSysAddonsConfig) UpdateConfigByGroup(ctx context.Context, in sysin.Upd
Where("addon_name", in.AddonName). Where("addon_name", in.AddonName).
Where("group", in.Group). Where("group", in.Group).
Scan(&models); err != nil { Scan(&models); err != nil {
return err return
} }
err = dao.SysAddonsConfig.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { err = dao.SysAddonsConfig.Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
for k, v := range in.List { for k, v := range in.List {
row := s.getConfigByKey(k, models) row := s.getConfigByKey(k, models)
// 新增 // 新增
@@ -130,20 +129,15 @@ func (s *sSysAddonsConfig) UpdateConfigByGroup(ctx context.Context, in sysin.Upd
} }
// 更新 // 更新
_, err = dao.SysAddonsConfig.Ctx(ctx).Where("id", row.Id).Data(g.Map{"value": v, "updated_at": gtime.Now()}).Update() if _, err = dao.SysAddonsConfig.Ctx(ctx).Where("id", row.Id).Data(g.Map{"value": v, "updated_at": gtime.Now()}).Update(); err != nil {
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return
} }
} }
return nil return
}) })
if err != nil { return
return err
}
return nil
} }
func (s *sSysAddonsConfig) getConfigByKey(key string, models []*entity.SysAddonsConfig) *entity.SysAddonsConfig { func (s *sSysAddonsConfig) getConfigByKey(key string, models []*entity.SysAddonsConfig) *entity.SysAddonsConfig {
@@ -156,6 +150,5 @@ func (s *sSysAddonsConfig) getConfigByKey(key string, models []*entity.SysAddons
return v return v
} }
} }
return nil return nil
} }

View File

@@ -9,17 +9,12 @@ import (
"context" "context"
"github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm/handler" "hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/entity" "hotgo/internal/library/storager"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/format" "hotgo/utility/format"
"hotgo/utility/validate"
) )
type sSysAttachment struct{} type sSysAttachment struct{}
@@ -37,92 +32,41 @@ func (s *sSysAttachment) Model(ctx context.Context, option ...*handler.Option) *
return handler.Model(dao.SysAttachment.Ctx(ctx), option...) return handler.Model(dao.SysAttachment.Ctx(ctx), option...)
} }
// Delete 删除 // Delete 删除附件
func (s *sSysAttachment) Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error) { func (s *sSysAttachment) Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error) {
_, err = s.Model(ctx).Where("id", in.Id).Delete() if _, err = s.Model(ctx).WherePri(in.Id).Delete(); err != nil {
err = gerror.Wrap(err, "删除附件失败,请稍后重试!")
}
return return
} }
// Edit 修改/新增 // View 获取附件信息
func (s *sSysAttachment) Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error) {
if in.Name == "" {
err = gerror.New("标题不能为空")
return
}
// 修改
if in.Id > 0 {
_, err = s.Model(ctx).Where("id", in.Id).Data(in).Update()
return
}
// 新增
_, err = dao.SysAttachment.Ctx(ctx).Data(in).Insert()
return
}
// Status 更新部门状态
func (s *sSysAttachment) Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return
}
if !validate.InSliceInt(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确")
return
}
// 修改
_, err = s.Model(ctx).Where("id", in.Id).Data("status", in.Status).Update()
return
}
// MaxSort 最大排序
func (s *sSysAttachment) MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (res *sysin.AttachmentMaxSortModel, err error) {
if in.Id > 0 {
if err = s.Model(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
return
}
}
if res == nil {
res = new(sysin.AttachmentMaxSortModel)
}
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return
}
// View 获取指定字典类型信息
func (s *sSysAttachment) View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error) { func (s *sSysAttachment) View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error) {
err = s.Model(ctx).Where("id", in.Id).Scan(&res) if err = s.Model(ctx).WherePri(in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, "获取附件信息失败,请稍后重试!")
}
return return
} }
// List 获取列表 // List 获取附件列表
func (s *sSysAttachment) List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error) { func (s *sSysAttachment) List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error) {
mod := s.Model(ctx) mod := s.Model(ctx)
if in.MemberId > 0 { if in.MemberId > 0 {
mod = mod.Where("member_id", in.MemberId) mod = mod.Where(dao.SysAttachment.Columns().MemberId, in.MemberId)
} }
if in.Drive != "" { if in.Drive != "" {
mod = mod.Where("drive", in.Drive) mod = mod.Where(dao.SysAttachment.Columns().Drive, in.Drive)
} }
if in.Status > 0 { if in.Status > 0 {
mod = mod.Where("status", in.Status) mod = mod.Where(dao.SysAttachment.Columns().Status, in.Status)
} }
totalCount, err = mod.Count() totalCount, err = mod.Count()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, "获取附件数据行失败!")
return return
} }
@@ -130,58 +74,14 @@ func (s *sSysAttachment) List(ctx context.Context, in sysin.AttachmentListInp) (
return return
} }
if err = mod.Page(in.Page, in.PerPage).Order("updated_at desc").Scan(&list); err != nil { if err = mod.Page(in.Page, in.PerPage).OrderDesc(dao.SysAttachment.Columns().UpdatedAt).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, "获取附件列表失败!")
return
}
conf, err := service.SysConfig().GetUpload(ctx)
if err != nil {
return return
} }
for _, v := range list { for _, v := range list {
v.SizeFormat = format.FileSize(v.Size) v.SizeFormat = format.FileSize(v.Size)
v.FileUrl = service.CommonUpload().LastUrl(ctx, conf, v.FileUrl, v.Drive) v.FileUrl = storager.LastUrl(ctx, v.FileUrl, v.Drive)
} }
return return
} }
// Add 新增附件
func (s *sSysAttachment) Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (models *entity.SysAttachment, err error) {
var (
c = contexts.Get(ctx)
user = c.User
memberId int64 = 0
)
if user != nil {
memberId = user.Id
}
models = &entity.SysAttachment{
Id: 0,
AppId: c.Module,
MemberId: memberId,
Drive: drive,
Size: meta.Size,
Path: fullPath,
FileUrl: fullPath,
Name: meta.Filename,
Kind: meta.Kind,
MetaType: meta.MetaType,
NaiveType: meta.NaiveType,
Ext: meta.Ext,
Md5: meta.Md5,
Status: consts.StatusEnabled,
CreatedAt: gtime.Now(),
UpdatedAt: gtime.Now(),
}
id, err := dao.SysAttachment.Ctx(ctx).Data(models).InsertAndGetId()
if err != nil {
return
}
models.Id = id
return
}

View File

@@ -71,7 +71,7 @@ func (s *sSysBlacklist) Status(ctx context.Context, in sysin.BlacklistStatusInp)
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -16,6 +16,7 @@ import (
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/library/payment" "hotgo/internal/library/payment"
"hotgo/internal/library/storager"
"hotgo/internal/library/token" "hotgo/internal/library/token"
"hotgo/internal/library/wechat" "hotgo/internal/library/wechat"
"hotgo/internal/model" "hotgo/internal/model"
@@ -35,6 +36,7 @@ func init() {
service.RegisterSysConfig(NewSysConfig()) service.RegisterSysConfig(NewSysConfig())
} }
// InitConfig 初始化一些系统启动就需要用到的配置
func (s *sSysConfig) InitConfig(ctx context.Context) { func (s *sSysConfig) InitConfig(ctx context.Context) {
wx, err := s.GetWechat(ctx) wx, err := s.GetWechat(ctx)
if err != nil { if err != nil {
@@ -48,12 +50,17 @@ func (s *sSysConfig) InitConfig(ctx context.Context) {
} }
payment.SetConfig(pay) payment.SetConfig(pay)
upload, err := s.GetUpload(ctx)
if err != nil {
g.Log().Fatalf(ctx, "init upload conifg fail%+v", err)
}
storager.SetConfig(upload)
tk, err := s.GetLoadToken(ctx) tk, err := s.GetLoadToken(ctx)
if err != nil { if err != nil {
g.Log().Fatalf(ctx, "init token conifg fail%+v", err) g.Log().Fatalf(ctx, "init token conifg fail%+v", err)
} }
token.SetConfig(tk) token.SetConfig(tk)
} }
// GetLogin 获取登录配置 // GetLogin 获取登录配置
@@ -267,7 +274,6 @@ func (s *sSysConfig) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateCon
return s.syncUpdate(ctx, in) return s.syncUpdate(ctx, in)
}) })
return return
} }
@@ -281,7 +287,6 @@ func (s *sSysConfig) getConfigByKey(key string, models []*entity.SysConfig) *ent
return v return v
} }
} }
return nil return nil
} }
@@ -298,6 +303,11 @@ func (s *sSysConfig) syncUpdate(ctx context.Context, in sysin.UpdateConfigInp) (
if err == nil { if err == nil {
payment.SetConfig(pay) payment.SetConfig(pay)
} }
case "upload":
upload, err := s.GetUpload(ctx)
if err == nil {
storager.SetConfig(upload)
}
} }
if err != nil { if err != nil {

View File

@@ -106,7 +106,7 @@ func (s *sSysCron) Status(ctx context.Context, in sysin.CronStatusInp) (err erro
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -46,7 +46,6 @@ func (s *sSysCronGroup) Edit(ctx context.Context, in sysin.CronGroupEditInp) (er
if _, err = dao.SysCronGroup.Ctx(ctx).Fields(sysin.CronGroupInsertFields{}).Data(in).Insert(); err != nil { if _, err = dao.SysCronGroup.Ctx(ctx).Fields(sysin.CronGroupInsertFields{}).Data(in).Insert(); err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
} }
return return
} }

View File

@@ -198,7 +198,7 @@ func (s *sSysCurdDemo) Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (
// ... // ...
} }
if !validate.InSliceString(fields, in.Key) { if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单") err = gerror.New("开关键名不在白名单")
return return
} }

View File

@@ -44,7 +44,6 @@ func (s *sSysDictData) Edit(ctx context.Context, in sysin.DictDataEditInp) (err
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return err
} }
return nil return nil
} }

View File

@@ -76,7 +76,7 @@ func (s *sSysEmsLog) Status(ctx context.Context, in sysin.EmsLogStatusInp) (err
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -110,7 +110,7 @@ func (s *sSysGenCodes) Status(ctx context.Context, in sysin.GenCodesStatusInp) (
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }
@@ -274,7 +274,6 @@ func (s *sSysGenCodes) ColumnSelect(ctx context.Context, in sysin.GenCodesColumn
res[k].Name = fmt.Sprintf("%s (%s)", v.Value, v.Label) res[k].Name = fmt.Sprintf("%s (%s)", v.Value, v.Label)
res[k].Label = res[k].Name res[k].Label = res[k].Name
} }
return return
} }
@@ -306,6 +305,5 @@ func (s *sSysGenCodes) Build(ctx context.Context, in sysin.GenCodesBuildInp) (er
_ = s.Status(ctx, sysin.GenCodesStatusInp{Id: in.Id, Status: consts.GenCodesStatusFail}) _ = s.Status(ctx, sysin.GenCodesStatusInp{Id: in.Id, Status: consts.GenCodesStatusFail})
return err return err
} }
return return
} }

View File

@@ -230,7 +230,6 @@ func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
Status: consts.StatusEnabled, Status: consts.StatusEnabled,
TakeUpTime: takeUpTime, TakeUpTime: takeUpTime,
} }
return data return data
} }
@@ -241,8 +240,7 @@ func (s *sSysLog) View(ctx context.Context, in sysin.LogViewInp) (res *sysin.Log
return return
} }
isDemo := g.Cfg().MustGet(ctx, "hotgo.isDemo", false) if g.Cfg().MustGet(ctx, "hotgo.isDemo", false).Bool() {
if isDemo.Bool() {
res.HeaderData = gjson.New(`{ res.HeaderData = gjson.New(`{
"none": [ "none": [
"` + consts.DemoTips + `" "` + consts.DemoTips + `"
@@ -364,6 +362,5 @@ func (s *sSysLog) List(ctx context.Context, in sysin.LogListInp) (list []*sysin.
} }
} }
return return
} }

View File

@@ -107,7 +107,6 @@ func (s *sSysLoginLog) List(ctx context.Context, in sysin.LoginLogListInp) (list
v.Os = useragent.GetOs(v.SysLogUserAgent) v.Os = useragent.GetOs(v.SysLogUserAgent)
v.Browser = useragent.GetBrowser(v.SysLogUserAgent) v.Browser = useragent.GetBrowser(v.SysLogUserAgent)
} }
return return
} }

View File

@@ -71,7 +71,7 @@ func (s *sSysSmsLog) Status(ctx context.Context, in sysin.SmsLogStatusInp) (err
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -3,11 +3,9 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package view package view
import ( import (
"fmt"
"hotgo/internal/consts" "hotgo/internal/consts"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
@@ -44,41 +42,6 @@ func (s *viewBuildIn) UrlPath() string {
return s.httpRequest.URL.Path return s.httpRequest.URL.Path
} }
// FormatTime 格式化时间
func (s *viewBuildIn) FormatTime(gt *gtime.Time) string {
if gt == nil {
return ""
}
n := gtime.Now().Timestamp()
t := gt.Timestamp()
var ys int64 = 31536000
var ds int64 = 86400
var hs int64 = 3600
var ms int64 = 60
var ss int64 = 1
var rs string
d := n - t
switch {
case d > ys:
rs = fmt.Sprintf("%d年前", int(d/ys))
case d > ds:
rs = fmt.Sprintf("%d天前", int(d/ds))
case d > hs:
rs = fmt.Sprintf("%d小时前", int(d/hs))
case d > ms:
rs = fmt.Sprintf("%d分钟前", int(d/ms))
case d > ss:
rs = fmt.Sprintf("%d秒前", int(d/ss))
default:
rs = "刚刚"
}
return rs
}
// Version 随机数 开发环境时间戳,线上为前端版本号 // Version 随机数 开发环境时间戳,线上为前端版本号
func (s *viewBuildIn) Version() string { func (s *viewBuildIn) Version() string {
var rand string var rand string

View File

@@ -124,7 +124,7 @@ func (in *DeptStatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -225,7 +225,7 @@ func (in *MemberStatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -25,7 +25,7 @@ type OrderAcceptRefundInp struct {
} }
func (in *OrderAcceptRefundInp) Filter(ctx context.Context) (err error) { func (in *OrderAcceptRefundInp) Filter(ctx context.Context) (err error) {
if !validate.InSliceInt64(consts.OrderStatusSlice, in.Status) { if !validate.InSlice(consts.OrderStatusSlice, in.Status) {
err = gerror.Newf("订单状态不正确") err = gerror.Newf("订单状态不正确")
return return
} }

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sysin package sysin
import ( import (
@@ -11,28 +10,13 @@ import (
"hotgo/internal/model/input/form" "hotgo/internal/model/input/form"
) )
// AttachmentMaxSortInp 最大排序 // AttachmentDeleteInp 删除附件
type AttachmentMaxSortInp struct {
Id int64
}
type AttachmentMaxSortModel struct {
Sort int
}
// AttachmentEditInp 修改/新增字典数据
type AttachmentEditInp struct {
entity.SysAttachment
}
type AttachmentEditModel struct{}
// AttachmentDeleteInp 删除字典类型
type AttachmentDeleteInp struct { type AttachmentDeleteInp struct {
Id interface{} Id interface{}
} }
type AttachmentDeleteModel struct{} type AttachmentDeleteModel struct{}
// AttachmentViewInp 获取信息 // AttachmentViewInp 获取附件信息
type AttachmentViewInp struct { type AttachmentViewInp struct {
Id int64 Id int64
} }
@@ -41,7 +25,7 @@ type AttachmentViewModel struct {
entity.SysAttachment entity.SysAttachment
} }
// AttachmentListInp 获取列表 // AttachmentListInp 获取附件列表
type AttachmentListInp struct { type AttachmentListInp struct {
form.PageReq form.PageReq
form.RangeDateReq form.RangeDateReq
@@ -54,19 +38,3 @@ type AttachmentListModel struct {
entity.SysAttachment entity.SysAttachment
SizeFormat string `json:"sizeFormat" description:"长度"` SizeFormat string `json:"sizeFormat" description:"长度"`
} }
// AttachmentStatusInp 更新状态
type AttachmentStatusInp struct {
entity.SysAttachment
}
type AttachmentStatusModel struct{}
type UploadFileMeta struct {
Filename string
Size int64
Kind string
MetaType string
NaiveType string
Ext string
Md5 string
}

View File

@@ -108,7 +108,7 @@ func (in *CronGroupStatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -186,7 +186,7 @@ func (in *CurdDemoStatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -114,7 +114,7 @@ func (in *ProvincesStatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -3,7 +3,6 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package genrouter package genrouter
import ( import (
@@ -14,7 +13,7 @@ import (
) )
var ( var (
NoLogin []interface{} // 无需登录 NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录 LoginRequiredRouter []interface{} // 需要登录
) )
@@ -22,8 +21,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) { func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := g.Cfg().MustGet(ctx, "router.admin.prefix", "/admin") prefix := g.Cfg().MustGet(ctx, "router.admin.prefix", "/admin")
group.Group(prefix.String(), func(group *ghttp.RouterGroup) { group.Group(prefix.String(), func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 { if len(NoLoginRouter) > 0 {
group.Bind(NoLogin...) group.Bind(NoLoginRouter...)
} }
group.Middleware(service.Middleware().AdminAuth) group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 { if len(LoginRequiredRouter) > 0 {

View File

@@ -19,6 +19,68 @@ import (
) )
type ( type (
IAdminMember interface {
AddBalance(ctx context.Context, in adminin.MemberAddBalanceInp) (err error)
AddIntegral(ctx context.Context, in adminin.MemberAddIntegralInp) (err error)
UpdateCash(ctx context.Context, in adminin.MemberUpdateCashInp) (err error)
UpdateEmail(ctx context.Context, in adminin.MemberUpdateEmailInp) (err error)
UpdateMobile(ctx context.Context, in adminin.MemberUpdateMobileInp) (err error)
UpdateProfile(ctx context.Context, in adminin.MemberUpdateProfileInp) (err error)
UpdatePwd(ctx context.Context, in adminin.MemberUpdatePwdInp) (err error)
ResetPwd(ctx context.Context, in adminin.MemberResetPwdInp) (err error)
VerifyUnique(ctx context.Context, in adminin.VerifyUniqueInp) (err error)
Delete(ctx context.Context, in adminin.MemberDeleteInp) (err error)
Edit(ctx context.Context, in adminin.MemberEditInp) (err error)
View(ctx context.Context, in adminin.MemberViewInp) (res *adminin.MemberViewModel, err error)
List(ctx context.Context, in adminin.MemberListInp) (list []*adminin.MemberListModel, totalCount int, err error)
Status(ctx context.Context, in adminin.MemberStatusInp) (err error)
GenTree(ctx context.Context, pid int64) (level int, newTree string, err error)
LoginMemberInfo(ctx context.Context) (res *adminin.LoginMemberInfoModel, err error)
MemberLoginStat(ctx context.Context, in adminin.MemberLoginStatInp) (res *adminin.MemberLoginStatModel, err error)
GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error)
Select(ctx context.Context, in adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error)
VerifySuperId(ctx context.Context, verifyId int64) bool
FilterAuthModel(ctx context.Context, memberId int64) *gdb.Model
}
IAdminMemberPost interface {
UpdatePostIds(ctx context.Context, memberId int64, postIds []int64) (err error)
}
IAdminMenu interface {
MaxSort(ctx context.Context, req *menu.MaxSortReq) (res *menu.MaxSortRes, err error)
NameUnique(ctx context.Context, req *menu.NameUniqueReq) (res *menu.NameUniqueRes, err error)
CodeUnique(ctx context.Context, req *menu.CodeUniqueReq) (res *menu.CodeUniqueRes, err error)
Delete(ctx context.Context, req *menu.DeleteReq) (err error)
Edit(ctx context.Context, req *menu.EditReq) (err error)
View(ctx context.Context, req *menu.ViewReq) (res *menu.ViewRes, err error)
List(ctx context.Context, req *menu.ListReq) (lists []map[string]interface{}, err error)
GetMenuList(ctx context.Context, memberId int64) (res *role.DynamicRes, err error)
LoginPermissions(ctx context.Context, memberId int64) (lists adminin.MemberLoginPermissions, err error)
}
IAdminNotice interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in adminin.NoticeDeleteInp) (err error)
Edit(ctx context.Context, in adminin.NoticeEditInp) (err error)
Status(ctx context.Context, in adminin.NoticeStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.NoticeMaxSortInp) (res *adminin.NoticeMaxSortModel, err error)
View(ctx context.Context, in adminin.NoticeViewInp) (res *adminin.NoticeViewModel, err error)
List(ctx context.Context, in adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error)
PullMessages(ctx context.Context, in adminin.PullMessagesInp) (res *adminin.PullMessagesModel, err error)
UnreadCount(ctx context.Context, in adminin.NoticeUnreadCountInp) (res *adminin.NoticeUnreadCountModel, err error)
UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (err error)
ReadAll(ctx context.Context, in adminin.NoticeReadAllInp) (err error)
MessageList(ctx context.Context, in adminin.NoticeMessageListInp) (list []*adminin.NoticeMessageListModel, totalCount int, err error)
}
IAdminSite interface {
Register(ctx context.Context, in adminin.RegisterInp) (err error)
AccountLogin(ctx context.Context, in adminin.AccountLoginInp) (res *adminin.LoginModel, err error)
MobileLogin(ctx context.Context, in adminin.MobileLoginInp) (res *adminin.LoginModel, err error)
}
IAdminCash interface {
View(ctx context.Context, in adminin.CashViewInp) (res *adminin.CashViewModel, err error)
List(ctx context.Context, in adminin.CashListInp) (list []*adminin.CashListModel, totalCount int, err error)
Apply(ctx context.Context, in adminin.CashApplyInp) (err error)
Payment(ctx context.Context, in adminin.CashPaymentInp) (err error)
}
IAdminCreditsLog interface { IAdminCreditsLog interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model Model(ctx context.Context, option ...*handler.Option) *gdb.Model
SaveBalance(ctx context.Context, in adminin.CreditsLogSaveBalanceInp) (res *adminin.CreditsLogSaveBalanceModel, err error) SaveBalance(ctx context.Context, in adminin.CreditsLogSaveBalanceInp) (res *adminin.CreditsLogSaveBalanceModel, err error)
@@ -26,8 +88,32 @@ type (
List(ctx context.Context, in adminin.CreditsLogListInp) (list []*adminin.CreditsLogListModel, totalCount int, err error) List(ctx context.Context, in adminin.CreditsLogListInp) (list []*adminin.CreditsLogListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.CreditsLogListInp) (err error) Export(ctx context.Context, in adminin.CreditsLogListInp) (err error)
} }
IAdminMemberPost interface { IAdminDept interface {
UpdatePostIds(ctx context.Context, memberId int64, postIds []int64) (err error) Delete(ctx context.Context, in adminin.DeptDeleteInp) (err error)
Edit(ctx context.Context, in adminin.DeptEditInp) (err error)
Status(ctx context.Context, in adminin.DeptStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.DeptMaxSortInp) (res *adminin.DeptMaxSortModel, err error)
View(ctx context.Context, in adminin.DeptViewInp) (res *adminin.DeptViewModel, err error)
Option(ctx context.Context, in adminin.DeptOptionInp) (res *adminin.DeptOptionModel, totalCount int, err error)
List(ctx context.Context, in adminin.DeptListInp) (res *adminin.DeptListModel, err error)
GetName(ctx context.Context, id int64) (name string, err error)
}
IAdminMonitor interface {
StartMonitor(ctx context.Context)
GetMeta(ctx context.Context) *model.MonitorData
}
IAdminOrder interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
AcceptRefund(ctx context.Context, in adminin.OrderAcceptRefundInp) (err error)
ApplyRefund(ctx context.Context, in adminin.OrderApplyRefundInp) (err error)
PayNotify(ctx context.Context, in payin.NotifyCallFuncInp) (err error)
Create(ctx context.Context, in adminin.OrderCreateInp) (res *adminin.OrderCreateModel, err error)
List(ctx context.Context, in adminin.OrderListInp) (list []*adminin.OrderListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.OrderListInp) (err error)
Edit(ctx context.Context, in adminin.OrderEditInp) (err error)
Delete(ctx context.Context, in adminin.OrderDeleteInp) (err error)
View(ctx context.Context, in adminin.OrderViewInp) (res *adminin.OrderViewModel, err error)
Status(ctx context.Context, in adminin.OrderStatusInp) (err error)
} }
IAdminPost interface { IAdminPost interface {
Delete(ctx context.Context, in adminin.PostDeleteInp) (err error) Delete(ctx context.Context, in adminin.PostDeleteInp) (err error)
@@ -52,109 +138,34 @@ type (
DataScopeSelect() (res form.Selects) DataScopeSelect() (res form.Selects)
DataScopeEdit(ctx context.Context, in *adminin.DataScopeEditInp) (err error) DataScopeEdit(ctx context.Context, in *adminin.DataScopeEditInp) (err error)
} }
IAdminCash interface {
View(ctx context.Context, in adminin.CashViewInp) (res *adminin.CashViewModel, err error)
List(ctx context.Context, in adminin.CashListInp) (list []*adminin.CashListModel, totalCount int, err error)
Apply(ctx context.Context, in adminin.CashApplyInp) (err error)
Payment(ctx context.Context, in adminin.CashPaymentInp) (err error)
}
IAdminMember interface {
AddBalance(ctx context.Context, in adminin.MemberAddBalanceInp) (err error)
AddIntegral(ctx context.Context, in adminin.MemberAddIntegralInp) (err error)
UpdateCash(ctx context.Context, in adminin.MemberUpdateCashInp) (err error)
UpdateEmail(ctx context.Context, in adminin.MemberUpdateEmailInp) (err error)
UpdateMobile(ctx context.Context, in adminin.MemberUpdateMobileInp) (err error)
UpdateProfile(ctx context.Context, in adminin.MemberUpdateProfileInp) (err error)
UpdatePwd(ctx context.Context, in adminin.MemberUpdatePwdInp) (err error)
ResetPwd(ctx context.Context, in adminin.MemberResetPwdInp) (err error)
VerifyUnique(ctx context.Context, in adminin.VerifyUniqueInp) (err error)
Delete(ctx context.Context, in adminin.MemberDeleteInp) (err error)
Edit(ctx context.Context, in adminin.MemberEditInp) (err error)
View(ctx context.Context, in adminin.MemberViewInp) (res *adminin.MemberViewModel, err error)
List(ctx context.Context, in adminin.MemberListInp) (list []*adminin.MemberListModel, totalCount int, err error)
Status(ctx context.Context, in adminin.MemberStatusInp) (err error)
GenTree(ctx context.Context, pid int64) (level int, newTree string, err error)
LoginMemberInfo(ctx context.Context) (res *adminin.LoginMemberInfoModel, err error)
MemberLoginStat(ctx context.Context, in adminin.MemberLoginStatInp) (res *adminin.MemberLoginStatModel, err error)
GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error)
Select(ctx context.Context, in adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error)
VerifySuperId(ctx context.Context, verifyId int64) bool
FilterAuthModel(ctx context.Context, memberId int64) *gdb.Model
}
IAdminMenu interface {
MaxSort(ctx context.Context, req *menu.MaxSortReq) (res *menu.MaxSortRes, err error)
NameUnique(ctx context.Context, req *menu.NameUniqueReq) (res *menu.NameUniqueRes, err error)
CodeUnique(ctx context.Context, req *menu.CodeUniqueReq) (res *menu.CodeUniqueRes, err error)
Delete(ctx context.Context, req *menu.DeleteReq) (err error)
Edit(ctx context.Context, req *menu.EditReq) (err error)
View(ctx context.Context, req *menu.ViewReq) (res *menu.ViewRes, err error)
List(ctx context.Context, req *menu.ListReq) (lists []map[string]interface{}, err error)
GetMenuList(ctx context.Context, memberId int64) (res *role.DynamicRes, err error)
LoginPermissions(ctx context.Context, memberId int64) (lists adminin.MemberLoginPermissions, err error)
}
IAdminMonitor interface {
StartMonitor(ctx context.Context)
GetMeta(ctx context.Context) *model.MonitorData
}
IAdminNotice interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
Delete(ctx context.Context, in adminin.NoticeDeleteInp) (err error)
Edit(ctx context.Context, in adminin.NoticeEditInp) (err error)
Status(ctx context.Context, in adminin.NoticeStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.NoticeMaxSortInp) (res *adminin.NoticeMaxSortModel, err error)
View(ctx context.Context, in adminin.NoticeViewInp) (res *adminin.NoticeViewModel, err error)
List(ctx context.Context, in adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error)
PullMessages(ctx context.Context, in adminin.PullMessagesInp) (res *adminin.PullMessagesModel, err error)
UnreadCount(ctx context.Context, in adminin.NoticeUnreadCountInp) (res *adminin.NoticeUnreadCountModel, err error)
UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (err error)
ReadAll(ctx context.Context, in adminin.NoticeReadAllInp) (err error)
MessageList(ctx context.Context, in adminin.NoticeMessageListInp) (list []*adminin.NoticeMessageListModel, totalCount int, err error)
}
IAdminOrder interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
AcceptRefund(ctx context.Context, in adminin.OrderAcceptRefundInp) (err error)
ApplyRefund(ctx context.Context, in adminin.OrderApplyRefundInp) (err error)
PayNotify(ctx context.Context, in payin.NotifyCallFuncInp) (err error)
Create(ctx context.Context, in adminin.OrderCreateInp) (res *adminin.OrderCreateModel, err error)
List(ctx context.Context, in adminin.OrderListInp) (list []*adminin.OrderListModel, totalCount int, err error)
Export(ctx context.Context, in adminin.OrderListInp) (err error)
Edit(ctx context.Context, in adminin.OrderEditInp) (err error)
Delete(ctx context.Context, in adminin.OrderDeleteInp) (err error)
View(ctx context.Context, in adminin.OrderViewInp) (res *adminin.OrderViewModel, err error)
Status(ctx context.Context, in adminin.OrderStatusInp) (err error)
}
IAdminSite interface {
Register(ctx context.Context, in adminin.RegisterInp) (err error)
AccountLogin(ctx context.Context, in adminin.AccountLoginInp) (res *adminin.LoginModel, err error)
MobileLogin(ctx context.Context, in adminin.MobileLoginInp) (res *adminin.LoginModel, err error)
}
IAdminDept interface {
Delete(ctx context.Context, in adminin.DeptDeleteInp) (err error)
Edit(ctx context.Context, in adminin.DeptEditInp) (err error)
Status(ctx context.Context, in adminin.DeptStatusInp) (err error)
MaxSort(ctx context.Context, in adminin.DeptMaxSortInp) (res *adminin.DeptMaxSortModel, err error)
View(ctx context.Context, in adminin.DeptViewInp) (res *adminin.DeptViewModel, err error)
Option(ctx context.Context, in adminin.DeptOptionInp) (res *adminin.DeptOptionModel, totalCount int, err error)
List(ctx context.Context, in adminin.DeptListInp) (res *adminin.DeptListModel, err error)
GetName(ctx context.Context, id int64) (name string, err error)
}
) )
var ( var (
localAdminSite IAdminSite
localAdminCash IAdminCash localAdminCash IAdminCash
localAdminCreditsLog IAdminCreditsLog localAdminCreditsLog IAdminCreditsLog
localAdminMemberPost IAdminMemberPost localAdminDept IAdminDept
localAdminMonitor IAdminMonitor
localAdminOrder IAdminOrder
localAdminPost IAdminPost localAdminPost IAdminPost
localAdminRole IAdminRole localAdminRole IAdminRole
localAdminDept IAdminDept
localAdminMember IAdminMember localAdminMember IAdminMember
localAdminMemberPost IAdminMemberPost
localAdminMenu IAdminMenu localAdminMenu IAdminMenu
localAdminMonitor IAdminMonitor
localAdminNotice IAdminNotice localAdminNotice IAdminNotice
localAdminOrder IAdminOrder
localAdminSite IAdminSite
) )
func AdminSite() IAdminSite {
if localAdminSite == nil {
panic("implement not found for interface IAdminSite, forgot register?")
}
return localAdminSite
}
func RegisterAdminSite(i IAdminSite) {
localAdminSite = i
}
func AdminCash() IAdminCash { func AdminCash() IAdminCash {
if localAdminCash == nil { if localAdminCash == nil {
panic("implement not found for interface IAdminCash, forgot register?") panic("implement not found for interface IAdminCash, forgot register?")
@@ -177,15 +188,37 @@ func RegisterAdminCreditsLog(i IAdminCreditsLog) {
localAdminCreditsLog = i localAdminCreditsLog = i
} }
func AdminMemberPost() IAdminMemberPost { func AdminDept() IAdminDept {
if localAdminMemberPost == nil { if localAdminDept == nil {
panic("implement not found for interface IAdminMemberPost, forgot register?") panic("implement not found for interface IAdminDept, forgot register?")
} }
return localAdminMemberPost return localAdminDept
} }
func RegisterAdminMemberPost(i IAdminMemberPost) { func RegisterAdminDept(i IAdminDept) {
localAdminMemberPost = i localAdminDept = i
}
func AdminMonitor() IAdminMonitor {
if localAdminMonitor == nil {
panic("implement not found for interface IAdminMonitor, forgot register?")
}
return localAdminMonitor
}
func RegisterAdminMonitor(i IAdminMonitor) {
localAdminMonitor = i
}
func AdminOrder() IAdminOrder {
if localAdminOrder == nil {
panic("implement not found for interface IAdminOrder, forgot register?")
}
return localAdminOrder
}
func RegisterAdminOrder(i IAdminOrder) {
localAdminOrder = i
} }
func AdminPost() IAdminPost { func AdminPost() IAdminPost {
@@ -210,17 +243,6 @@ func RegisterAdminRole(i IAdminRole) {
localAdminRole = i localAdminRole = i
} }
func AdminDept() IAdminDept {
if localAdminDept == nil {
panic("implement not found for interface IAdminDept, forgot register?")
}
return localAdminDept
}
func RegisterAdminDept(i IAdminDept) {
localAdminDept = i
}
func AdminMember() IAdminMember { func AdminMember() IAdminMember {
if localAdminMember == nil { if localAdminMember == nil {
panic("implement not found for interface IAdminMember, forgot register?") panic("implement not found for interface IAdminMember, forgot register?")
@@ -232,6 +254,17 @@ func RegisterAdminMember(i IAdminMember) {
localAdminMember = i localAdminMember = i
} }
func AdminMemberPost() IAdminMemberPost {
if localAdminMemberPost == nil {
panic("implement not found for interface IAdminMemberPost, forgot register?")
}
return localAdminMemberPost
}
func RegisterAdminMemberPost(i IAdminMemberPost) {
localAdminMemberPost = i
}
func AdminMenu() IAdminMenu { func AdminMenu() IAdminMenu {
if localAdminMenu == nil { if localAdminMenu == nil {
panic("implement not found for interface IAdminMenu, forgot register?") panic("implement not found for interface IAdminMenu, forgot register?")
@@ -243,17 +276,6 @@ func RegisterAdminMenu(i IAdminMenu) {
localAdminMenu = i localAdminMenu = i
} }
func AdminMonitor() IAdminMonitor {
if localAdminMonitor == nil {
panic("implement not found for interface IAdminMonitor, forgot register?")
}
return localAdminMonitor
}
func RegisterAdminMonitor(i IAdminMonitor) {
localAdminMonitor = i
}
func AdminNotice() IAdminNotice { func AdminNotice() IAdminNotice {
if localAdminNotice == nil { if localAdminNotice == nil {
panic("implement not found for interface IAdminNotice, forgot register?") panic("implement not found for interface IAdminNotice, forgot register?")
@@ -264,25 +286,3 @@ func AdminNotice() IAdminNotice {
func RegisterAdminNotice(i IAdminNotice) { func RegisterAdminNotice(i IAdminNotice) {
localAdminNotice = i localAdminNotice = i
} }
func AdminOrder() IAdminOrder {
if localAdminOrder == nil {
panic("implement not found for interface IAdminOrder, forgot register?")
}
return localAdminOrder
}
func RegisterAdminOrder(i IAdminOrder) {
localAdminOrder = i
}
func AdminSite() IAdminSite {
if localAdminSite == nil {
panic("implement not found for interface IAdminSite, forgot register?")
}
return localAdminSite
}
func RegisterAdminSite(i IAdminSite) {
localAdminSite = i
}

View File

@@ -7,7 +7,6 @@ package service
import ( import (
"context" "context"
"hotgo/internal/model"
"hotgo/internal/model/input/commonin" "hotgo/internal/model/input/commonin"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
@@ -16,15 +15,8 @@ import (
type ( type (
ICommonUpload interface { ICommonUpload interface {
UploadFile(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) UploadFile(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error)
UploadImage(ctx context.Context, file *ghttp.UploadFile) (result *sysin.AttachmentListModel, err error) UploadImage(ctx context.Context, file *ghttp.UploadFile) (res *sysin.AttachmentListModel, err error)
UploadLocal(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadUCloud(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadCOS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadOSS(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
UploadQiNiu(ctx context.Context, conf *model.UploadConfig, file *ghttp.UploadFile, meta *sysin.UploadFileMeta) (result *sysin.AttachmentListModel, err error)
LastUrl(ctx context.Context, conf *model.UploadConfig, fullPath, drive string) string
HasFile(ctx context.Context, md5 string) (res *sysin.AttachmentListModel, err error)
} }
ICommonWechat interface { ICommonWechat interface {
Authorize(ctx context.Context, in commonin.WechatAuthorizeInp) (res *commonin.WechatAuthorizeModel, err error) Authorize(ctx context.Context, in commonin.WechatAuthorizeInp) (res *commonin.WechatAuthorizeModel, err error)

View File

@@ -17,11 +17,71 @@ import (
) )
type ( type (
ISysDictData interface { ISysSmsLog interface {
Delete(ctx context.Context, in sysin.DictDataDeleteInp) error Delete(ctx context.Context, in sysin.SmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.DictDataEditInp) (err error) Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error) Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error) MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (res *sysin.SmsLogMaxSortModel, err error)
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
}
ISysServeLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
}
ISysAddons interface {
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
}
ISysCron interface {
StartCron(ctx context.Context)
Delete(ctx context.Context, in sysin.CronDeleteInp) (err error)
Edit(ctx context.Context, in sysin.CronEditInp) (err error)
Status(ctx context.Context, in sysin.CronStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (res *sysin.CronMaxSortModel, err error)
View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error)
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error)
OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error)
}
ISysCurdDemo interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error)
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error)
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error)
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error)
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error)
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
}
ISysDictType interface {
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error)
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) (err error)
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error)
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error)
}
ISysEmsLog interface {
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error)
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error)
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
} }
ISysGenCodes interface { ISysGenCodes interface {
Delete(ctx context.Context, in sysin.GenCodesDeleteInp) (err error) Delete(ctx context.Context, in sysin.GenCodesDeleteInp) (err error)
@@ -37,32 +97,11 @@ type (
Preview(ctx context.Context, in sysin.GenCodesPreviewInp) (res *sysin.GenCodesPreviewModel, err error) Preview(ctx context.Context, in sysin.GenCodesPreviewInp) (res *sysin.GenCodesPreviewModel, err error)
Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error) Build(ctx context.Context, in sysin.GenCodesBuildInp) (err error)
} }
ISysLog interface { ISysAttachment interface {
Export(ctx context.Context, in sysin.LogListInp) (err error) Model(ctx context.Context, option ...*handler.Option) *gdb.Model
RealWrite(ctx context.Context, log entity.SysLog) (err error) Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error)
AutoLog(ctx context.Context) error View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error)
AnalysisLog(ctx context.Context) entity.SysLog List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error)
View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
}
ISysServeLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.ServeLogListInp) (err error)
Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error)
View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error)
RealWrite(ctx context.Context, models entity.SysServeLog) (err error)
}
ISysCron interface {
StartCron(ctx context.Context)
Delete(ctx context.Context, in sysin.CronDeleteInp) (err error)
Edit(ctx context.Context, in sysin.CronEditInp) (err error)
Status(ctx context.Context, in sysin.CronStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (res *sysin.CronMaxSortModel, err error)
View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error)
List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error)
OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error)
} }
ISysBlacklist interface { ISysBlacklist interface {
Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error) Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error)
@@ -95,32 +134,35 @@ type (
ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error) ConversionType(ctx context.Context, models *entity.SysConfig) (value interface{}, err error)
UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) (err error) UpdateConfigByGroup(ctx context.Context, in sysin.UpdateConfigInp) (err error)
} }
ISysCurdDemo interface { ISysLog interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model Export(ctx context.Context, in sysin.LogListInp) (err error)
List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error) RealWrite(ctx context.Context, log entity.SysLog) (err error)
Export(ctx context.Context, in sysin.CurdDemoListInp) (err error) AutoLog(ctx context.Context) error
Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err error) AnalysisLog(ctx context.Context) entity.SysLog
Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error) View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error)
MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error) Delete(ctx context.Context, in sysin.LogDeleteInp) (err error)
View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error) List(ctx context.Context, in sysin.LogListInp) (list []*sysin.LogListModel, totalCount int, err error)
Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error)
Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (err error)
} }
ISysDictType interface { ISysLoginLog interface {
Tree(ctx context.Context) (list []*sysin.DictTypeTree, err error) Model(ctx context.Context) *gdb.Model
Delete(ctx context.Context, in sysin.DictTypeDeleteInp) (err error) List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
Edit(ctx context.Context, in sysin.DictTypeEditInp) (err error) Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
TreeSelect(ctx context.Context, in sysin.DictTreeSelectInp) (list []*sysin.DictTypeTree, err error) Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
Push(ctx context.Context, in sysin.LoginLogPushInp)
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
} }
ISysAttachment interface { ISysProvinces interface {
Model(ctx context.Context, option ...*handler.Option) *gdb.Model Tree(ctx context.Context) (list []g.Map, err error)
Delete(ctx context.Context, in sysin.AttachmentDeleteInp) (err error) Delete(ctx context.Context, in sysin.ProvincesDeleteInp) (err error)
Edit(ctx context.Context, in sysin.AttachmentEditInp) (err error) Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error)
Status(ctx context.Context, in sysin.AttachmentStatusInp) (err error) Status(ctx context.Context, in sysin.ProvincesStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.AttachmentMaxSortInp) (res *sysin.AttachmentMaxSortModel, err error) MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (res *sysin.ProvincesMaxSortModel, err error)
View(ctx context.Context, in sysin.AttachmentViewInp) (res *sysin.AttachmentViewModel, err error) View(ctx context.Context, in sysin.ProvincesViewInp) (res *sysin.ProvincesViewModel, err error)
List(ctx context.Context, in sysin.AttachmentListInp) (list []*sysin.AttachmentListModel, totalCount int, err error) List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error)
Add(ctx context.Context, meta *sysin.UploadFileMeta, fullPath, drive string) (models *entity.SysAttachment, err error) ChildrenList(ctx context.Context, in sysin.ProvincesChildrenListInp) (list []*sysin.ProvincesChildrenListModel, totalCount int, err error)
UniqueId(ctx context.Context, in sysin.ProvincesUniqueIdInp) (res *sysin.ProvincesUniqueIdModel, err error)
Select(ctx context.Context, in sysin.ProvincesSelectInp) (res *sysin.ProvincesSelectModel, err error)
} }
ISysAddonsConfig interface { ISysAddonsConfig interface {
GetConfigByGroup(ctx context.Context, in sysin.GetAddonsConfigInp) (res *sysin.GetAddonsConfigModel, err error) GetConfigByGroup(ctx context.Context, in sysin.GetAddonsConfigInp) (res *sysin.GetAddonsConfigModel, err error)
@@ -136,122 +178,54 @@ type (
List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int, err error) List(ctx context.Context, in sysin.CronGroupListInp) (list []*sysin.CronGroupListModel, totalCount int, err error)
Select(ctx context.Context, in sysin.CronGroupSelectInp) (res *sysin.CronGroupSelectModel, err error) Select(ctx context.Context, in sysin.CronGroupSelectInp) (res *sysin.CronGroupSelectModel, err error)
} }
ISysEmsLog interface { ISysDictData interface {
Delete(ctx context.Context, in sysin.EmsLogDeleteInp) (err error) Delete(ctx context.Context, in sysin.DictDataDeleteInp) error
Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error) Edit(ctx context.Context, in sysin.DictDataEditInp) (err error)
Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error) List(ctx context.Context, in sysin.DictDataListInp) (list []*sysin.DictDataListModel, totalCount int, err error)
View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error) Select(ctx context.Context, in sysin.DataSelectInp) (list sysin.DataSelectModel, err error)
List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error)
Send(ctx context.Context, in sysin.SendEmsInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error)
}
ISysProvinces interface {
Tree(ctx context.Context) (list []g.Map, err error)
Delete(ctx context.Context, in sysin.ProvincesDeleteInp) (err error)
Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error)
Status(ctx context.Context, in sysin.ProvincesStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (res *sysin.ProvincesMaxSortModel, err error)
View(ctx context.Context, in sysin.ProvincesViewInp) (res *sysin.ProvincesViewModel, err error)
List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error)
ChildrenList(ctx context.Context, in sysin.ProvincesChildrenListInp) (list []*sysin.ProvincesChildrenListModel, totalCount int, err error)
UniqueId(ctx context.Context, in sysin.ProvincesUniqueIdInp) (res *sysin.ProvincesUniqueIdModel, err error)
Select(ctx context.Context, in sysin.ProvincesSelectInp) (res *sysin.ProvincesSelectModel, err error)
}
ISysAddons interface {
List(ctx context.Context, in sysin.AddonsListInp) (list []*sysin.AddonsListModel, totalCount int, err error)
Selects(ctx context.Context, in sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error)
Build(ctx context.Context, in sysin.AddonsBuildInp) (err error)
Install(ctx context.Context, in sysin.AddonsInstallInp) (err error)
Upgrade(ctx context.Context, in sysin.AddonsUpgradeInp) (err error)
UnInstall(ctx context.Context, in sysin.AddonsUnInstallInp) (err error)
}
ISysSmsLog interface {
Delete(ctx context.Context, in sysin.SmsLogDeleteInp) (err error)
Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error)
Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error)
MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (res *sysin.SmsLogMaxSortModel, err error)
View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error)
List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error)
SendCode(ctx context.Context, in sysin.SendCodeInp) (err error)
GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error)
AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error)
VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error)
}
ISysLoginLog interface {
Model(ctx context.Context) *gdb.Model
List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error)
Export(ctx context.Context, in sysin.LoginLogListInp) (err error)
Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error)
View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error)
Push(ctx context.Context, in sysin.LoginLogPushInp)
RealWrite(ctx context.Context, models entity.SysLoginLog) (err error)
} }
) )
var ( var (
localSysDictData ISysDictData
localSysGenCodes ISysGenCodes
localSysLog ISysLog
localSysServeLog ISysServeLog
localSysCron ISysCron localSysCron ISysCron
localSysCurdDemo ISysCurdDemo
localSysServeLog ISysServeLog
localSysAddons ISysAddons
localSysBlacklist ISysBlacklist localSysBlacklist ISysBlacklist
localSysConfig ISysConfig localSysConfig ISysConfig
localSysCurdDemo ISysCurdDemo
localSysDictType ISysDictType localSysDictType ISysDictType
localSysAttachment ISysAttachment
localSysAddonsConfig ISysAddonsConfig
localSysCronGroup ISysCronGroup
localSysEmsLog ISysEmsLog localSysEmsLog ISysEmsLog
localSysProvinces ISysProvinces localSysGenCodes ISysGenCodes
localSysAddons ISysAddons localSysAttachment ISysAttachment
localSysSmsLog ISysSmsLog localSysCronGroup ISysCronGroup
localSysDictData ISysDictData
localSysLog ISysLog
localSysLoginLog ISysLoginLog localSysLoginLog ISysLoginLog
localSysProvinces ISysProvinces
localSysAddonsConfig ISysAddonsConfig
localSysSmsLog ISysSmsLog
) )
func SysProvinces() ISysProvinces { func SysConfig() ISysConfig {
if localSysProvinces == nil { if localSysConfig == nil {
panic("implement not found for interface ISysProvinces, forgot register?") panic("implement not found for interface ISysConfig, forgot register?")
} }
return localSysProvinces return localSysConfig
} }
func RegisterSysProvinces(i ISysProvinces) { func RegisterSysConfig(i ISysConfig) {
localSysProvinces = i localSysConfig = i
} }
func SysAddons() ISysAddons { func SysDictType() ISysDictType {
if localSysAddons == nil { if localSysDictType == nil {
panic("implement not found for interface ISysAddons, forgot register?") panic("implement not found for interface ISysDictType, forgot register?")
} }
return localSysAddons return localSysDictType
} }
func RegisterSysAddons(i ISysAddons) { func RegisterSysDictType(i ISysDictType) {
localSysAddons = i localSysDictType = i
}
func SysAddonsConfig() ISysAddonsConfig {
if localSysAddonsConfig == nil {
panic("implement not found for interface ISysAddonsConfig, forgot register?")
}
return localSysAddonsConfig
}
func RegisterSysAddonsConfig(i ISysAddonsConfig) {
localSysAddonsConfig = i
}
func SysCronGroup() ISysCronGroup {
if localSysCronGroup == nil {
panic("implement not found for interface ISysCronGroup, forgot register?")
}
return localSysCronGroup
}
func RegisterSysCronGroup(i ISysCronGroup) {
localSysCronGroup = i
} }
func SysEmsLog() ISysEmsLog { func SysEmsLog() ISysEmsLog {
@@ -265,61 +239,6 @@ func RegisterSysEmsLog(i ISysEmsLog) {
localSysEmsLog = i localSysEmsLog = i
} }
func SysLoginLog() ISysLoginLog {
if localSysLoginLog == nil {
panic("implement not found for interface ISysLoginLog, forgot register?")
}
return localSysLoginLog
}
func RegisterSysLoginLog(i ISysLoginLog) {
localSysLoginLog = i
}
func SysSmsLog() ISysSmsLog {
if localSysSmsLog == nil {
panic("implement not found for interface ISysSmsLog, forgot register?")
}
return localSysSmsLog
}
func RegisterSysSmsLog(i ISysSmsLog) {
localSysSmsLog = i
}
func SysServeLog() ISysServeLog {
if localSysServeLog == nil {
panic("implement not found for interface ISysServeLog, forgot register?")
}
return localSysServeLog
}
func RegisterSysServeLog(i ISysServeLog) {
localSysServeLog = i
}
func SysCron() ISysCron {
if localSysCron == nil {
panic("implement not found for interface ISysCron, forgot register?")
}
return localSysCron
}
func RegisterSysCron(i ISysCron) {
localSysCron = i
}
func SysDictData() ISysDictData {
if localSysDictData == nil {
panic("implement not found for interface ISysDictData, forgot register?")
}
return localSysDictData
}
func RegisterSysDictData(i ISysDictData) {
localSysDictData = i
}
func SysGenCodes() ISysGenCodes { func SysGenCodes() ISysGenCodes {
if localSysGenCodes == nil { if localSysGenCodes == nil {
panic("implement not found for interface ISysGenCodes, forgot register?") panic("implement not found for interface ISysGenCodes, forgot register?")
@@ -331,28 +250,6 @@ func RegisterSysGenCodes(i ISysGenCodes) {
localSysGenCodes = i localSysGenCodes = i
} }
func SysLog() ISysLog {
if localSysLog == nil {
panic("implement not found for interface ISysLog, forgot register?")
}
return localSysLog
}
func RegisterSysLog(i ISysLog) {
localSysLog = i
}
func SysDictType() ISysDictType {
if localSysDictType == nil {
panic("implement not found for interface ISysDictType, forgot register?")
}
return localSysDictType
}
func RegisterSysDictType(i ISysDictType) {
localSysDictType = i
}
func SysAttachment() ISysAttachment { func SysAttachment() ISysAttachment {
if localSysAttachment == nil { if localSysAttachment == nil {
panic("implement not found for interface ISysAttachment, forgot register?") panic("implement not found for interface ISysAttachment, forgot register?")
@@ -375,15 +272,81 @@ func RegisterSysBlacklist(i ISysBlacklist) {
localSysBlacklist = i localSysBlacklist = i
} }
func SysConfig() ISysConfig { func SysDictData() ISysDictData {
if localSysConfig == nil { if localSysDictData == nil {
panic("implement not found for interface ISysConfig, forgot register?") panic("implement not found for interface ISysDictData, forgot register?")
} }
return localSysConfig return localSysDictData
} }
func RegisterSysConfig(i ISysConfig) { func RegisterSysDictData(i ISysDictData) {
localSysConfig = i localSysDictData = i
}
func SysLog() ISysLog {
if localSysLog == nil {
panic("implement not found for interface ISysLog, forgot register?")
}
return localSysLog
}
func RegisterSysLog(i ISysLog) {
localSysLog = i
}
func SysLoginLog() ISysLoginLog {
if localSysLoginLog == nil {
panic("implement not found for interface ISysLoginLog, forgot register?")
}
return localSysLoginLog
}
func RegisterSysLoginLog(i ISysLoginLog) {
localSysLoginLog = i
}
func SysProvinces() ISysProvinces {
if localSysProvinces == nil {
panic("implement not found for interface ISysProvinces, forgot register?")
}
return localSysProvinces
}
func RegisterSysProvinces(i ISysProvinces) {
localSysProvinces = i
}
func SysAddonsConfig() ISysAddonsConfig {
if localSysAddonsConfig == nil {
panic("implement not found for interface ISysAddonsConfig, forgot register?")
}
return localSysAddonsConfig
}
func RegisterSysAddonsConfig(i ISysAddonsConfig) {
localSysAddonsConfig = i
}
func SysCronGroup() ISysCronGroup {
if localSysCronGroup == nil {
panic("implement not found for interface ISysCronGroup, forgot register?")
}
return localSysCronGroup
}
func RegisterSysCronGroup(i ISysCronGroup) {
localSysCronGroup = i
}
func SysSmsLog() ISysSmsLog {
if localSysSmsLog == nil {
panic("implement not found for interface ISysSmsLog, forgot register?")
}
return localSysSmsLog
}
func RegisterSysSmsLog(i ISysSmsLog) {
localSysSmsLog = i
} }
func SysCurdDemo() ISysCurdDemo { func SysCurdDemo() ISysCurdDemo {
@@ -396,3 +359,36 @@ func SysCurdDemo() ISysCurdDemo {
func RegisterSysCurdDemo(i ISysCurdDemo) { func RegisterSysCurdDemo(i ISysCurdDemo) {
localSysCurdDemo = i localSysCurdDemo = i
} }
func SysServeLog() ISysServeLog {
if localSysServeLog == nil {
panic("implement not found for interface ISysServeLog, forgot register?")
}
return localSysServeLog
}
func RegisterSysServeLog(i ISysServeLog) {
localSysServeLog = i
}
func SysAddons() ISysAddons {
if localSysAddons == nil {
panic("implement not found for interface ISysAddons, forgot register?")
}
return localSysAddons
}
func RegisterSysAddons(i ISysAddons) {
localSysAddons = i
}
func SysCron() ISysCron {
if localSysCron == nil {
panic("implement not found for interface ISysCron, forgot register?")
}
return localSysCron
}
func RegisterSysCron(i ISysCron) {
localSysCron = i
}

View File

@@ -28,21 +28,10 @@ type (
) )
var ( var (
localAuthClient IAuthClient
localCronClient ICronClient localCronClient ICronClient
localAuthClient IAuthClient
) )
func CronClient() ICronClient {
if localCronClient == nil {
panic("implement not found for interface ICronClient, forgot register?")
}
return localCronClient
}
func RegisterCronClient(i ICronClient) {
localCronClient = i
}
func AuthClient() IAuthClient { func AuthClient() IAuthClient {
if localAuthClient == nil { if localAuthClient == nil {
panic("implement not found for interface IAuthClient, forgot register?") panic("implement not found for interface IAuthClient, forgot register?")
@@ -53,3 +42,14 @@ func AuthClient() IAuthClient {
func RegisterAuthClient(i IAuthClient) { func RegisterAuthClient(i IAuthClient) {
localAuthClient = i localAuthClient = i
} }
func CronClient() ICronClient {
if localCronClient == nil {
panic("implement not found for interface ICronClient, forgot register?")
}
return localCronClient
}
func RegisterCronClient(i ICronClient) {
localCronClient = i
}

View File

@@ -289,7 +289,6 @@ func (manager *ClientManager) start() {
g.Log().Info(ctxManager, "websocket closeSignal quit..") g.Log().Info(ctxManager, "websocket closeSignal quit..")
return return
} }
} }
} }

View File

@@ -8,14 +8,14 @@ package genrouter
import ( import (
"context" "context"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
"hotgo/addons/@{.name}/global" "hotgo/addons/hgexample/global"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/library/addons" "hotgo/internal/library/addons"
"hotgo/internal/service" "hotgo/internal/service"
) )
var ( var (
NoLogin []interface{} // 无需登录 NoLoginRouter []interface{} // 无需登录
LoginRequiredRouter []interface{} // 需要登录 LoginRequiredRouter []interface{} // 需要登录
) )
@@ -23,8 +23,8 @@ var (
func Register(ctx context.Context, group *ghttp.RouterGroup) { func Register(ctx context.Context, group *ghttp.RouterGroup) {
prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name) prefix := addons.RouterPrefix(ctx, consts.AppAdmin, global.GetSkeleton().Name)
group.Group(prefix, func(group *ghttp.RouterGroup) { group.Group(prefix, func(group *ghttp.RouterGroup) {
if len(NoLogin) > 0 { if len(NoLoginRouter) > 0 {
group.Bind(NoLogin...) group.Bind(NoLoginRouter...)
} }
group.Middleware(service.Middleware().AdminAuth) group.Middleware(service.Middleware().AdminAuth)
if len(LoginRequiredRouter) > 0 { if len(LoginRequiredRouter) > 0 {

View File

@@ -117,7 +117,7 @@ func (in *@{.varName}StatusInp) Filter(ctx context.Context) (err error) {
return return
} }
if !validate.InSliceInt(consts.StatusSlice, in.Status) { if !validate.InSlice(consts.StatusSlice, in.Status) {
err = gerror.New("状态不正确") err = gerror.New("状态不正确")
return return
} }

View File

@@ -159,7 +159,7 @@ func (s *s@{.servFunName}) Switch(ctx context.Context, in @{.templateGroup}in.@{
// ... // ...
} }
if !validate.InSliceString(fields, in.Key) { if !validate.InSlice(fields, in.Key) {
err = gerror.New("开关键名不在白名单") err = gerror.New("开关键名不在白名单")
return return
} }

View File

@@ -9,41 +9,11 @@ import (
"crypto/rand" "crypto/rand"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/utility/convert"
r "math/rand" r "math/rand"
"strings" "strings"
"time" "time"
) )
// SplitMemberIds 从截取字串符中读取用户ID
func SplitMemberIds(str, pos string) (memberIds []int64) {
receiver := strings.Split(strings.TrimSpace(str), pos)
if len(receiver) == 0 {
return memberIds
}
if len(receiver) == 1 && strings.TrimSpace(receiver[0]) == "" {
return memberIds
}
for _, memberId := range receiver {
memberIds = append(memberIds, gconv.Int64(strings.TrimSpace(memberId)))
}
return convert.UniqueSliceInt64(memberIds)
}
// GetMapKeysByString 获取map的所有key字串符类型
func GetMapKeysByString(m map[string]string) []string {
// 数组默认长度为map长度,后面append时,不需要重新申请内存和拷贝,效率很高
j := 0
keys := make([]string, len(m))
for k := range m {
keys[j] = k
j++
}
return keys
}
// RandomCreateBytes 生成随机字串符 // RandomCreateBytes 生成随机字串符
func RandomCreateBytes(n int, alphabets ...byte) []byte { func RandomCreateBytes(n int, alphabets ...byte) []byte {
if len(alphabets) == 0 { if len(alphabets) == 0 {
@@ -51,13 +21,12 @@ func RandomCreateBytes(n int, alphabets ...byte) []byte {
} }
var bytes = make([]byte, n) var bytes = make([]byte, n)
var randBy bool var randBy bool
r.Seed(time.Now().UnixNano())
if num, err := rand.Read(bytes); num != n || err != nil { if num, err := rand.Read(bytes); num != n || err != nil {
randBy = true randBy = true
} }
for i, b := range bytes { for i, b := range bytes {
if randBy { if randBy {
bytes[i] = alphabets[r.Intn(len(alphabets))] bytes[i] = alphabets[r.New(r.NewSource(time.Now().UnixNano())).Intn(len(alphabets))]
} else { } else {
bytes[i] = alphabets[b%byte(len(alphabets))] bytes[i] = alphabets[b%byte(len(alphabets))]
} }

View File

@@ -17,23 +17,21 @@ var (
fieldTags = []string{"json"} // 实体字段名称映射 fieldTags = []string{"json"} // 实体字段名称映射
) )
// UniqueSliceInt64 切片去重 // GetMapKeys 获取map的所有key
func UniqueSliceInt64(languages []int64) []int64 { func GetMapKeys[K comparable](m map[K]any) []K {
result := make([]int64, 0, len(languages)) j := 0
temp := map[int64]struct{}{} keys := make([]K, len(m))
for _, item := range languages { for k := range m {
if _, ok := temp[item]; !ok { keys[j] = k
temp[item] = struct{}{} j++
result = append(result, item)
}
} }
return result return keys
} }
// UniqueSliceString 切片去重 // UniqueSlice 切片去重
func UniqueSliceString(languages []string) []string { func UniqueSlice[K comparable](languages []K) []K {
result := make([]string, 0, len(languages)) result := make([]K, 0, len(languages))
temp := map[string]struct{}{} temp := map[K]struct{}{}
for _, item := range languages { for _, item := range languages {
if _, ok := temp[item]; !ok { if _, ok := temp[item]; !ok {
temp[item] = struct{}{} temp[item] = struct{}{}
@@ -121,19 +119,19 @@ func reflectTag(reflectType reflect.Type, filterTags []string, tags []string) ([
// reflectTagName 解析实体中的描述标签优先级description > dc > json > Name // reflectTagName 解析实体中的描述标签优先级description > dc > json > Name
func reflectTagName(field reflect.StructField, filterTags []string, isDef bool) string { func reflectTagName(field reflect.StructField, filterTags []string, isDef bool) string {
if validate.InSliceString(filterTags, "description") { if validate.InSlice(filterTags, "description") {
if description, ok := field.Tag.Lookup("description"); ok && description != "" { if description, ok := field.Tag.Lookup("description"); ok && description != "" {
return description return description
} }
} }
if validate.InSliceString(filterTags, "dc") { if validate.InSlice(filterTags, "dc") {
if dc, ok := field.Tag.Lookup("dc"); ok && dc != "" { if dc, ok := field.Tag.Lookup("dc"); ok && dc != "" {
return dc return dc
} }
} }
if validate.InSliceString(filterTags, "json") { if validate.InSlice(filterTags, "json") {
if jsonName, ok := field.Tag.Lookup("json"); ok && jsonName != "" { if jsonName, ok := field.Tag.Lookup("json"); ok && jsonName != "" {
return jsonName return jsonName
} }

View File

@@ -12,12 +12,6 @@ import (
"path/filepath" "path/filepath"
) )
const ( //文件大小单位
_ = iota
KB = 1 << (10 * iota)
MB
)
type fileInfo struct { //文件信息 type fileInfo struct { //文件信息
name string name string
size int64 size int64

View File

@@ -7,40 +7,67 @@ package format
import ( import (
"fmt" "fmt"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"strconv" "strconv"
) )
// Round2String 四舍五入保留小数默认2位 // Round2String 四舍五入保留小数默认2位
func Round2String(value float64, args ...interface{}) (v string) { func Round2String(value float64, args ...interface{}) string {
var places = 2 var places = 2
if len(args) > 0 { if len(args) > 0 {
places = gconv.Int(args[0]) places = gconv.Int(args[0])
} }
return fmt.Sprintf("%0."+strconv.Itoa(places)+"f", value)
cDig := strconv.Itoa(places)
val := fmt.Sprintf("%0."+cDig+"f", value)
return val
} }
// Round2Float64 四舍五入保留小数默认2位 // Round2Float64 四舍五入保留小数默认2位
func Round2Float64(value float64, args ...interface{}) (v float64) { func Round2Float64(value float64, args ...interface{}) float64 {
return gconv.Float64(Round2String(value, args...)) return gconv.Float64(Round2String(value, args...))
} }
// FileSize 字节的单位转换 保留两位小数 // FileSize 字节的单位转换 保留两位小数
func FileSize(fileSize int64) (size string) { func FileSize(data int64) string {
if fileSize < 1024 { var factor float64 = 1024
return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1)) res := float64(data)
} else if fileSize < (1024 * 1024) { for _, unit := range []string{"", "K", "M", "G", "T", "P"} {
return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024)) if res < factor {
} else if fileSize < (1024 * 1024 * 1024) { return fmt.Sprintf("%.2f%sB", res, unit)
return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024)) }
} else if fileSize < (1024 * 1024 * 1024 * 1024) { res /= factor
return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024))
} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024))
} else {
return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
} }
return fmt.Sprintf("%.2f%sB", res, "P")
}
// AgoTime 多久以前
func AgoTime(gt *gtime.Time) string {
if gt == nil {
return ""
}
n := gtime.Now().Timestamp()
t := gt.Timestamp()
var ys int64 = 31536000
var ds int64 = 86400
var hs int64 = 3600
var ms int64 = 60
var ss int64 = 1
var rs string
d := n - t
switch {
case d > ys:
rs = fmt.Sprintf("%d年前", int(d/ys))
case d > ds:
rs = fmt.Sprintf("%d天前", int(d/ds))
case d > hs:
rs = fmt.Sprintf("%d小时前", int(d/hs))
case d > ms:
rs = fmt.Sprintf("%d分钟前", int(d/ms))
case d > ss:
rs = fmt.Sprintf("%d秒前", int(d/ss))
default:
rs = "刚刚"
}
return rs
} }

View File

@@ -1,56 +0,0 @@
// Package signal
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package signal
import (
"sync"
)
type StopSignal int32
type exitWait struct {
mutex sync.Mutex
wg *sync.WaitGroup
deferFuns []func()
stopSignList []chan StopSignal
}
var exitWaitHandler *exitWait
func init() {
exitWaitHandler = &exitWait{
wg: &sync.WaitGroup{},
}
}
// ExitWaitFunDo 退出后等待处理完成
func ExitWaitFunDo(doFun func()) {
exitWaitHandler.wg.Add(1)
defer exitWaitHandler.wg.Done()
if doFun != nil {
doFun()
}
}
// AppDefer 应用退出后置操作
func AppDefer(deferFun ...func()) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
for _, funcItem := range deferFun {
if funcItem != nil {
exitWaitHandler.deferFuns = append(exitWaitHandler.deferFuns, funcItem)
}
}
}
// ListenStop 订阅app退出信号
func ListenStop(stopSig chan StopSignal) {
exitWaitHandler.mutex.Lock()
defer exitWaitHandler.mutex.Unlock()
exitWaitHandler.stopSignList = append(exitWaitHandler.stopSignList, stopSig)
}

View File

@@ -0,0 +1,51 @@
package simple
import (
"context"
"sync"
)
type EventFunc func(ctx context.Context, args ...interface{})
type sEvent struct {
sync.Mutex
list map[string][]EventFunc // 所有事件的列表
}
var event *sEvent
// InstanceEvent 事件实例
func InstanceEvent() *sEvent {
if event == nil {
event = &sEvent{
list: make(map[string][]EventFunc),
}
}
return event
}
// Register 往一个分组中注册事件
func (e *sEvent) Register(group string, callback EventFunc) {
e.Lock()
defer e.Unlock()
e.list[group] = append(e.list[group], callback)
}
// Call 回调一个分组的事件
func (e *sEvent) Call(group string, ctx context.Context, args ...interface{}) {
if events, ok := e.list[group]; ok {
for _, f := range events {
f(ctx, args...)
}
}
}
// Remove 移动一个分组的事件
func (e *sEvent) Remove(group string) {
delete(e.list, group)
}
// Clear 清空事件列表
func (e *sEvent) Clear() {
e.list = make(map[string][]EventFunc)
}

View File

@@ -8,35 +8,40 @@ package useragent
import ( import (
"fmt" "fmt"
"github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts"
"regexp" "regexp"
"strings" "strings"
) )
// GetOs 获取OS名称 // GetOs 获取OS名称
func GetOs(userAgent string) string { func GetOs(userAgent string) string {
osName := "Unknown" osName := consts.Unknown
if userAgent == "" { if userAgent == "" {
return osName return osName
} }
strRe, _ := regexp.Compile(`(?i:\((.*?)\))`) var (
userAgent = strRe.FindString(userAgent) strRe, _ = regexp.Compile(`(?i:\((.*?)\))`)
levelNames = ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr = make([]string, len(namesArr))
)
levelNames := ":micromessenger:dart:Windows NT:Windows Mobile:Windows Phone:Windows Phone OS:Macintosh|Macintosh:Mac OS:CrOS|CrOS:iPhone OS:iPad|iPad:OS:Android:Linux:blackberry:hpwOS:Series:Symbian:PalmOS:SymbianOS:J2ME:Sailfish:Bada:MeeGo:webOS|hpwOS:Maemo:" for k, name := range namesArr {
var regStrArr []string regStrArr[k] = fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name)
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/XxSs0-9_.]+)", name))
} }
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1) userAgent = strRe.FindString(userAgent)
name := "" var (
nameRe, _ = regexp.Compile(fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|")))
names = nameRe.FindAllString(userAgent, -1)
name = ""
)
for _, s := range names { for _, s := range names {
if name == "" { if len(name) == 0 {
name = strings.TrimSpace(s) name = strings.TrimSpace(s)
} else if len(name) > 0 { } else {
if strings.Contains(name, "Macintosh") && s != "" { if strings.Contains(name, "Macintosh") && s != "" {
name = strings.TrimSpace(s) name = strings.TrimSpace(s)
} else if strings.Contains(name, s) { } else if strings.Contains(name, s) {
@@ -62,30 +67,32 @@ func GetOs(userAgent string) string {
if name != "" { if name != "" {
osName = name osName = name
} }
return osName return osName
} }
// GetBrowser 获取浏览器名称 // GetBrowser 获取浏览器名称
func GetBrowser(userAgent string) string { func GetBrowser(userAgent string) string {
deviceName := "Unknown" var (
deviceName = consts.Unknown
levelNames = ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
namesArr = strings.Split(strings.Trim(levelNames, ":"), ":")
regStrArr []string
)
levelNames := ":VivoBrowser:QQDownload:QQBrowser:QQ:MQQBrowser:MicroMessenger:TencentTraveler:LBBROWSER:TaoBrowser:BrowserNG:UCWEB:TwonkyBeamBrowser:NokiaBrowser:OviBrowser:NF-Browser:OneBrowser:Obigo:DiigoBrowser:baidubrowser:baiduboxapp:xiaomi:Redmi:MI:Lumia:Micromax:MSIEMobile:IEMobile:EdgiOS:Yandex:Mercury:Openwave:TouchPad:UBrowser:Presto:Maxthon:MetaSr:Trident:Opera:IEMobile:Edge:Chrome:Chromium:OPR:CriOS:Firefox:FxiOS:fennec:CrMo:Safari:Nexus One:Nexus S:Nexus:Blazer:teashark:bolt:HTC:Dell:Motorola:Samsung:LG:Sony:SonyST:SonyLT:SonyEricsson:Asus:Palm:Vertu:Pantech:Fly:Wiko:i-mobile:Alcatel:Nintendo:Amoi:INQ:ONEPLUS:Tapatalk:PDA:Novarra-Vision:NetFront:Minimo:FlyFlow:Dolfin:Nokia:Series:AppleWebKit:Mobile:Mozilla:Version:"
var regStrArr []string
namesArr := strings.Split(strings.Trim(levelNames, ":"), ":")
for _, name := range namesArr { for _, name := range namesArr {
regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/0-9.]+)", name)) regStrArr = append(regStrArr, fmt.Sprintf("(%s[\\s?\\/0-9.]+)", name))
} }
regexpStr := fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ := regexp.Compile(regexpStr)
names := nameRe.FindAllString(userAgent, -1)
level := 0 var (
regexpStr = fmt.Sprintf("(?i:%s)", strings.Join(regStrArr, "|"))
nameRe, _ = regexp.Compile(regexpStr)
names = nameRe.FindAllString(userAgent, -1)
level = 0
)
for _, name := range names { for _, name := range names {
replaceRe, _ := regexp.Compile(`(?i:[\s?\/0-9.]+)`) replaceRe, _ := regexp.Compile(`(?i:[\s?\/0-9.]+)`)
n := replaceRe.ReplaceAllString(name, "") l := strings.Index(levelNames, fmt.Sprintf(":%s:", replaceRe.ReplaceAllString(name, "")))
l := strings.Index(levelNames, fmt.Sprintf(":%s:", n))
if level == 0 { if level == 0 {
deviceName = strings.TrimSpace(name) deviceName = strings.TrimSpace(name)
} }
@@ -95,7 +102,6 @@ func GetBrowser(userAgent string) string {
deviceName = strings.TrimSpace(name) deviceName = strings.TrimSpace(name)
} }
} }
return deviceName return deviceName
} }
@@ -119,6 +125,5 @@ func getWinOsNameWithWinNT(sName string) string {
break break
} }
} }
return osName return osName
} }

View File

@@ -3,18 +3,16 @@
// @Copyright Copyright (c) 2023 HotGo CLI // @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com> // @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package validate package validate
import ( import (
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
) )
// 包含判断 // 包含判断
// InSliceExistStr 判断字符或切片字符是否存在指定字符 // InSliceExistStr 判断字符或切片字符是否存在指定字符
func InSliceExistStr(elems interface{}, search string) bool { func InSliceExistStr(elems any, search string) bool {
switch elems.(type) { switch elems.(type) {
case []string: case []string:
elem := gconv.Strings(elems) elem := gconv.Strings(elems)
@@ -26,35 +24,15 @@ func InSliceExistStr(elems interface{}, search string) bool {
default: default:
return gconv.String(elems) == search return gconv.String(elems) == search
} }
return false return false
} }
// InSliceInt64 元素是否存在于切片中 // InSlice 元素是否存在于切片中
func InSliceInt64(slice []int64, key int64) bool { func InSlice[K comparable](slice []K, key K) bool {
if len(slice) == 0 { for _, v := range slice {
return false if v == key {
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
return true return true
} }
} }
return false return false
} }
func InSliceInt(slice []int, key int) bool {
if len(slice) == 0 {
return false
}
for i := 0; i < len(slice); i++ {
if slice[i] == key {
return true
}
}
return false
}
func InSliceString(slice []string, key string) bool {
return gstr.InArray(slice, key)
}