mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-08-26 16:46:14 +08:00
发布v2.13.1版本,更新内容请查看:https://github.com/bufanyun/hotgo/blob/v2.0/docs/guide-zh-CN/start-update-log.md
This commit is contained in:
@@ -11,11 +11,9 @@ import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/util/gmode"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/casbin"
|
||||
"hotgo/internal/library/hggen"
|
||||
"hotgo/internal/library/payment"
|
||||
"hotgo/internal/router"
|
||||
"hotgo/internal/service"
|
||||
"hotgo/internal/websocket"
|
||||
@@ -30,33 +28,23 @@ var (
|
||||
// 初始化http服务
|
||||
s := g.Server()
|
||||
|
||||
// 错误状态码接管
|
||||
s.BindStatusHandler(404, func(r *ghttp.Request) {
|
||||
r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…")
|
||||
})
|
||||
|
||||
s.BindStatusHandler(403, func(r *ghttp.Request) {
|
||||
r.Response.Writeln("403 - 网站拒绝显示此网页")
|
||||
})
|
||||
|
||||
// 初始化请求前回调
|
||||
s.BindHookHandler("/*any", ghttp.HookBeforeServe, service.Hook().BeforeServe)
|
||||
|
||||
// 请求响应结束后回调
|
||||
s.BindHookHandler("/*any", ghttp.HookAfterOutput, service.Hook().AfterOutput)
|
||||
|
||||
// 注册全局中间件
|
||||
s.BindMiddleware("/*any", []ghttp.HandlerFunc{
|
||||
service.Middleware().Ctx, // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
|
||||
service.Middleware().CORS, // 跨域中间件,自动处理跨域问题
|
||||
service.Middleware().Blacklist, // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
|
||||
service.Middleware().DemoLimit, // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
|
||||
service.Middleware().PreFilter, // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理
|
||||
service.Middleware().ResponseHandler, // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
|
||||
}...)
|
||||
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
|
||||
// 注册全局中间件
|
||||
group.Middleware(
|
||||
service.Middleware().Ctx, // 初始化请求上下文,一般需要第一个进行加载,后续中间件存在依赖关系
|
||||
service.Middleware().CORS, // 跨域中间件,自动处理跨域问题
|
||||
service.Middleware().Blacklist, // IP黑名单中间件,如果请求IP被后台拉黑,所有请求将被拒绝
|
||||
service.Middleware().DemoLimit, // 演示系統操作限制,当开启演示模式时,所有POST请求将被拒绝
|
||||
service.Middleware().PreFilter, // 请求输入预处理,api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可隐式预处理
|
||||
service.Middleware().ResponseHandler, // HTTP响应预处理,在业务处理完成后,对响应结果进行格式化和错误过滤,将处理后的数据发送给请求方
|
||||
)
|
||||
|
||||
// 注册后台路由
|
||||
router.Admin(ctx, group)
|
||||
|
||||
@@ -68,13 +56,12 @@ var (
|
||||
|
||||
// 注册前台页面路由
|
||||
router.Home(ctx, group)
|
||||
|
||||
// 注册插件路由
|
||||
addons.RegisterModulesRouter(ctx, group)
|
||||
})
|
||||
|
||||
// 设置插件静态目录映射
|
||||
addons.AddStaticPath(ctx, s)
|
||||
// 启动插件
|
||||
if err = addons.StartModules(ctx, &addons.Option{Server: s}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化casbin权限
|
||||
casbin.InitEnforcer(ctx)
|
||||
@@ -94,9 +81,7 @@ var (
|
||||
service.SysBlacklist().Load(ctx)
|
||||
|
||||
// 注册支付成功回调方法
|
||||
payment.RegisterNotifyCallMap(map[string]payment.NotifyCallFunc{
|
||||
consts.OrderGroupAdminOrder: service.AdminOrder().PayNotify, // 后台充值订单
|
||||
})
|
||||
service.Pay().RegisterNotifyCall()
|
||||
|
||||
serverWg.Add(1)
|
||||
|
||||
@@ -107,6 +92,7 @@ var (
|
||||
<-serverCloseSignal
|
||||
websocket.Stop() // 关闭websocket
|
||||
service.TCPServer().Stop(ctx) // 关闭tcp服务器
|
||||
addons.StopModules(ctx) // 停止插件
|
||||
_ = s.Shutdown() // 关闭http服务,主服务建议放在最后一个关闭
|
||||
g.Log().Debug(ctx, "http successfully closed ..")
|
||||
serverWg.Done()
|
||||
|
@@ -5,6 +5,17 @@
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package consts
|
||||
|
||||
import (
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dict.RegisterEnums("addonsGroupOptions", "插件分组", AddonsGroupOptions)
|
||||
dict.RegisterEnums("addonsInstallStatus", "插件安装状态", AddonsInstallStatusOptions)
|
||||
dict.RegisterEnums("addonsExtend", "插件扩展", AddonsExtendOptions)
|
||||
}
|
||||
|
||||
const (
|
||||
AddonsTag = "addons_" // 插件标签前缀
|
||||
AddonsDir = "addons" // 插件路径
|
||||
@@ -21,15 +32,16 @@ const (
|
||||
AddonsGroupBiz = 8 // 行业解决方案
|
||||
)
|
||||
|
||||
var AddonsGroupNameMap = map[int]string{
|
||||
AddonsGroupPlug: "功能扩展",
|
||||
AddonsGroupBusiness: "主要业务",
|
||||
AddonsGroupThirdParty: "第三方插件",
|
||||
AddonsGroupMiniApp: "小程序",
|
||||
AddonsGroupCustomer: "客户关系",
|
||||
AddonsGroupActivity: "营销及活动",
|
||||
AddonsGroupServices: "常用服务及工具",
|
||||
AddonsGroupBiz: "行业解决方案",
|
||||
// AddonsGroupOptions 插件分组选项
|
||||
var AddonsGroupOptions = []*model.Option{
|
||||
dict.GenInfoOption(AddonsGroupPlug, "功能扩展"),
|
||||
dict.GenInfoOption(AddonsGroupBusiness, "主要业务"),
|
||||
dict.GenInfoOption(AddonsGroupThirdParty, "第三方插件"),
|
||||
dict.GenInfoOption(AddonsGroupMiniApp, "小程序"),
|
||||
dict.GenInfoOption(AddonsGroupCustomer, "客户关系"),
|
||||
dict.GenInfoOption(AddonsGroupActivity, "营销及活动"),
|
||||
dict.GenInfoOption(AddonsGroupServices, "常用服务及工具"),
|
||||
dict.GenInfoOption(AddonsGroupBiz, "行业解决方案"),
|
||||
}
|
||||
|
||||
var AddonsGroupIconMap = map[int]string{
|
||||
@@ -49,8 +61,20 @@ const (
|
||||
AddonsInstallStatusUn = 3 // 已卸载
|
||||
)
|
||||
|
||||
var AddonsInstallStatusNameMap = map[int]string{
|
||||
AddonsInstallStatusOk: "已安装",
|
||||
AddonsInstallStatusNo: "未安装",
|
||||
AddonsInstallStatusUn: "已卸载",
|
||||
// AddonsInstallStatusOptions 插件安装状态
|
||||
var AddonsInstallStatusOptions = []*model.Option{
|
||||
dict.GenInfoOption(AddonsInstallStatusOk, "已安装"),
|
||||
dict.GenInfoOption(AddonsInstallStatusNo, "未安装"),
|
||||
dict.GenInfoOption(AddonsInstallStatusUn, "已卸载"),
|
||||
}
|
||||
|
||||
const (
|
||||
AddonsExtendResourcePublic = "resourcePublic"
|
||||
AddonsExtendResourceTemplate = "resourceTemplate"
|
||||
)
|
||||
|
||||
// AddonsExtendOptions 插件扩展选项
|
||||
var AddonsExtendOptions = []*model.Option{
|
||||
dict.GenInfoOption(AddonsExtendResourcePublic, "创建静态目录"),
|
||||
dict.GenInfoOption(AddonsExtendResourceTemplate, "创建模板目录"),
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ package consts
|
||||
|
||||
// cache
|
||||
const (
|
||||
CacheToken = "token" // 登录token
|
||||
CacheTokenBind = "token_bind" // 登录用户身份绑定
|
||||
CacheToken = "token" // 登录token
|
||||
CacheTokenBind = "token_bind" // 登录用户身份绑定
|
||||
CacheMultipartUpload = "multipart_upload" // 分片上传
|
||||
)
|
||||
|
@@ -5,7 +5,15 @@
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package consts
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dict.RegisterEnums("creditType", "资金变动类型", CreditTypeOptions)
|
||||
dict.RegisterEnums("creditGroup", "资金变动分组", CreditGroupOptions)
|
||||
}
|
||||
|
||||
const (
|
||||
CreditTypeBalance = "balance" // 余额
|
||||
@@ -23,63 +31,18 @@ const (
|
||||
)
|
||||
|
||||
// CreditTypeOptions 变动类型
|
||||
var CreditTypeOptions = []g.Map{
|
||||
{
|
||||
"key": CreditTypeBalance,
|
||||
"value": CreditTypeBalance,
|
||||
"label": "余额",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": CreditTypeIntegral,
|
||||
"value": CreditTypeIntegral,
|
||||
"label": "积分",
|
||||
"listClass": "info",
|
||||
},
|
||||
var CreditTypeOptions = []*model.Option{
|
||||
dict.GenSuccessOption(CreditTypeBalance, "余额"),
|
||||
dict.GenInfoOption(CreditTypeIntegral, "积分"),
|
||||
}
|
||||
|
||||
// CreditGroupOptions 变动分组
|
||||
var CreditGroupOptions = []g.Map{
|
||||
{
|
||||
"key": CreditGroupDecr,
|
||||
"value": CreditGroupDecr,
|
||||
"label": "扣款",
|
||||
"listClass": "warning",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupIncr,
|
||||
"value": CreditGroupIncr,
|
||||
"label": "加款",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupOpDecr,
|
||||
"value": CreditGroupOpDecr,
|
||||
"label": "操作扣款",
|
||||
"listClass": "warning",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupOpIncr,
|
||||
"value": CreditGroupOpIncr,
|
||||
"label": "操作加款",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupBalanceRefund,
|
||||
"value": CreditGroupBalanceRefund,
|
||||
"label": "余额退款",
|
||||
"listClass": "warning",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupBalanceRecharge,
|
||||
"value": CreditGroupBalanceRecharge,
|
||||
"label": "余额充值",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": CreditGroupApplyCash,
|
||||
"value": CreditGroupApplyCash,
|
||||
"label": "申请提现",
|
||||
"listClass": "info",
|
||||
},
|
||||
var CreditGroupOptions = []*model.Option{
|
||||
dict.GenWarningOption(CreditGroupDecr, "扣款"),
|
||||
dict.GenSuccessOption(CreditGroupIncr, "加款"),
|
||||
dict.GenWarningOption(CreditGroupOpDecr, "操作扣款"),
|
||||
dict.GenSuccessOption(CreditGroupOpIncr, "操作加款"),
|
||||
dict.GenWarningOption(CreditGroupBalanceRefund, "余额退款"),
|
||||
dict.GenSuccessOption(CreditGroupBalanceRecharge, "余额充值"),
|
||||
dict.GenInfoOption(CreditGroupApplyCash, "申请提现"),
|
||||
}
|
||||
|
@@ -5,7 +5,15 @@
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package consts
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dict.RegisterEnums("orderStatus", "订单状态", OrderStatusOptions)
|
||||
dict.RegisterEnums("acceptRefundStatus", "订单退款受理状态", OrderAcceptRefundOptions)
|
||||
}
|
||||
|
||||
// 订单分组
|
||||
// 为不同的业务订单设置不同的分组,分组可以设置不同的业务回调方法
|
||||
@@ -36,94 +44,23 @@ const (
|
||||
OrderStatusReturnReject = 9 // 拒绝退款
|
||||
)
|
||||
|
||||
var OrderStatusSlice = []int64{
|
||||
OrderStatusALL,
|
||||
OrderStatusNotPay, OrderStatusPay, OrderStatusShipments, OrderStatusDone, OrderStatusClose,
|
||||
OrderStatusReturnRequest, OrderStatusReturning, OrderStatusReturned, OrderStatusReturnReject,
|
||||
}
|
||||
|
||||
// OrderStatusOptions 订单状态选项
|
||||
var OrderStatusOptions = []g.Map{
|
||||
{
|
||||
"key": OrderStatusALL,
|
||||
"value": OrderStatusALL,
|
||||
"label": "全部",
|
||||
"listClass": "info",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusNotPay,
|
||||
"value": OrderStatusNotPay,
|
||||
"label": "待付款",
|
||||
"listClass": "info",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusPay,
|
||||
"value": OrderStatusPay,
|
||||
"label": "已付款",
|
||||
"listClass": "info",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusShipments,
|
||||
"value": OrderStatusShipments,
|
||||
"label": "已发货",
|
||||
"listClass": "info",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusDone,
|
||||
"value": OrderStatusDone,
|
||||
"label": "已完成",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusClose,
|
||||
"value": OrderStatusClose,
|
||||
"label": "已关闭",
|
||||
"listClass": "default",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturnRequest,
|
||||
"value": OrderStatusReturnRequest,
|
||||
"label": "申请退款",
|
||||
"listClass": "warning",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturning,
|
||||
"value": OrderStatusReturning,
|
||||
"label": "退款中",
|
||||
"listClass": "default",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturned,
|
||||
"value": OrderStatusReturned,
|
||||
"label": "已退款",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturnReject,
|
||||
"value": OrderStatusReturnReject,
|
||||
"label": "拒绝退款",
|
||||
"listClass": "error",
|
||||
},
|
||||
var OrderStatusOptions = []*model.Option{
|
||||
dict.GenInfoOption(OrderStatusALL, "全部"),
|
||||
dict.GenInfoOption(OrderStatusNotPay, "待付款"),
|
||||
dict.GenInfoOption(OrderStatusPay, "已付款"),
|
||||
dict.GenInfoOption(OrderStatusShipments, "已发货"),
|
||||
dict.GenSuccessOption(OrderStatusDone, "已完成"),
|
||||
dict.GenDefaultOption(OrderStatusClose, "已关闭"),
|
||||
dict.GenWarningOption(OrderStatusReturnRequest, "申请退款"),
|
||||
dict.GenDefaultOption(OrderStatusReturning, "退款中"),
|
||||
dict.GenErrorOption(OrderStatusReturned, "已退款"),
|
||||
dict.GenWarningOption(OrderStatusReturnReject, "拒绝退款"),
|
||||
}
|
||||
|
||||
// OrderAcceptRefundOptions 订单退款受理状态
|
||||
var OrderAcceptRefundOptions = []g.Map{
|
||||
{
|
||||
"key": OrderStatusReturnRequest,
|
||||
"value": OrderStatusReturnRequest,
|
||||
"label": "申请退款",
|
||||
"listClass": "warning",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturned,
|
||||
"value": OrderStatusReturned,
|
||||
"label": "已退款",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": OrderStatusReturnReject,
|
||||
"value": OrderStatusReturnReject,
|
||||
"label": "拒绝退款",
|
||||
"listClass": "error",
|
||||
},
|
||||
var OrderAcceptRefundOptions = []*model.Option{
|
||||
dict.GenWarningOption(OrderStatusReturnRequest, "申请退款"),
|
||||
dict.GenSuccessOption(OrderStatusReturned, "已退款"),
|
||||
dict.GenErrorOption(OrderStatusReturnReject, "拒绝退款"),
|
||||
}
|
||||
|
@@ -5,10 +5,17 @@
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package consts
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
import (
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
// 支付方式
|
||||
|
||||
func init() {
|
||||
dict.RegisterEnums("payType", "支付方式", PayTypeOptions)
|
||||
}
|
||||
|
||||
const (
|
||||
PayTypeALL = "" // 全部
|
||||
PayTypeWxPay = "wxpay" // 微信支付
|
||||
@@ -75,23 +82,8 @@ const (
|
||||
)
|
||||
|
||||
// PayTypeOptions 支付方式选项
|
||||
var PayTypeOptions = []g.Map{
|
||||
{
|
||||
"key": PayTypeWxPay,
|
||||
"value": PayTypeWxPay,
|
||||
"label": "微信支付",
|
||||
"listClass": "success",
|
||||
},
|
||||
{
|
||||
"key": PayTypeAliPay,
|
||||
"value": PayTypeAliPay,
|
||||
"label": "支付宝",
|
||||
"listClass": "info",
|
||||
},
|
||||
{
|
||||
"key": PayTypeQQPay,
|
||||
"value": PayTypeQQPay,
|
||||
"label": "QQ支付",
|
||||
"listClass": "default",
|
||||
},
|
||||
var PayTypeOptions = []*model.Option{
|
||||
dict.GenSuccessOption(PayTypeWxPay, "微信支付"),
|
||||
dict.GenInfoOption(PayTypeAliPay, "支付宝"),
|
||||
dict.GenDefaultOption(PayTypeQQPay, "QQ支付"),
|
||||
}
|
||||
|
@@ -7,5 +7,5 @@ package consts
|
||||
|
||||
// VersionApp HotGo版本
|
||||
const (
|
||||
VersionApp = "2.12.1"
|
||||
VersionApp = "2.13.1"
|
||||
)
|
||||
|
@@ -10,7 +10,6 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/admin/creditslog"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
@@ -38,12 +37,3 @@ func (c *cCreditsLog) Export(ctx context.Context, req *creditslog.ExportReq) (re
|
||||
err = service.AdminCreditsLog().Export(ctx, &req.CreditsLogListInp)
|
||||
return
|
||||
}
|
||||
|
||||
// Option 获取变动状态选项
|
||||
func (c *cCreditsLog) Option(_ context.Context, _ *creditslog.OptionReq) (res *creditslog.OptionRes, err error) {
|
||||
res = &creditslog.OptionRes{
|
||||
CreditType: consts.CreditTypeOptions,
|
||||
CreditGroup: consts.CreditGroupOptions,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ package admin
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/admin/order"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
@@ -30,16 +29,6 @@ func (c *cOrder) ApplyRefund(ctx context.Context, req *order.ApplyRefundReq) (re
|
||||
return
|
||||
}
|
||||
|
||||
// Option 获取订单状态选项
|
||||
func (c *cOrder) Option(ctx context.Context, req *order.OptionReq) (res *order.OptionRes, err error) {
|
||||
res = &order.OptionRes{
|
||||
Status: consts.OrderStatusOptions,
|
||||
AcceptRefundStatus: consts.OrderAcceptRefundOptions,
|
||||
PayType: consts.PayTypeOptions,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Create 创建充值订单
|
||||
func (c *cOrder) Create(ctx context.Context, req *order.CreateReq) (res *order.CreateRes, err error) {
|
||||
data, err := service.AdminOrder().Create(ctx, &req.OrderCreateInp)
|
||||
|
@@ -35,3 +35,25 @@ func (c *cUpload) UploadFile(ctx context.Context, _ *common.UploadFileReq) (res
|
||||
}
|
||||
return service.CommonUpload().UploadFile(ctx, uploadType, file)
|
||||
}
|
||||
|
||||
// CheckMultipart 检查文件分片
|
||||
func (c *cUpload) CheckMultipart(ctx context.Context, req *common.CheckMultipartReq) (res *common.CheckMultipartRes, err error) {
|
||||
data, err := service.CommonUpload().CheckMultipart(ctx, &req.CheckMultipartInp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = new(common.CheckMultipartRes)
|
||||
res.CheckMultipartModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (c *cUpload) UploadPart(ctx context.Context, req *common.UploadPartReq) (res *common.UploadPartRes, err error) {
|
||||
data, err := service.CommonUpload().UploadPart(ctx, &req.UploadPartInp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = new(common.UploadPartRes)
|
||||
res.UploadPartModel = data
|
||||
return
|
||||
}
|
||||
|
@@ -30,18 +30,6 @@ func (c *cAddons) List(ctx context.Context, req *addons.ListReq) (res *addons.Li
|
||||
return
|
||||
}
|
||||
|
||||
// Selects 获取指定信息
|
||||
func (c *cAddons) Selects(ctx context.Context, req *addons.SelectsReq) (res *addons.SelectsRes, err error) {
|
||||
data, err := service.SysAddons().Selects(ctx, &req.AddonsSelectsInp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
res = new(addons.SelectsRes)
|
||||
res.AddonsSelectsModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// Build 生成预览
|
||||
func (c *cAddons) Build(ctx context.Context, req *addons.BuildReq) (res *addons.BuildRes, err error) {
|
||||
err = service.SysAddons().Build(ctx, &req.AddonsBuildInp)
|
||||
|
@@ -1,14 +1,15 @@
|
||||
// Package sys
|
||||
// @Link https://github.com/bufanyun/hotgo
|
||||
// @Copyright Copyright (c) 2023 HotGo CLI
|
||||
// @Copyright Copyright (c) 2024 HotGo CLI
|
||||
// @Author Ms <133814250@qq.com>
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
// @AutoGenerate Version 2.11.5
|
||||
// @AutoGenerate Version 2.12.10
|
||||
package sys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hotgo/api/admin/curddemo"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
@@ -25,6 +26,10 @@ func (c *cCurdDemo) List(ctx context.Context, req *curddemo.ListReq) (res *curdd
|
||||
return
|
||||
}
|
||||
|
||||
if list == nil {
|
||||
list = []*sysin.CurdDemoListModel{}
|
||||
}
|
||||
|
||||
res = new(curddemo.ListRes)
|
||||
res.List = list
|
||||
res.PageRes.Pack(req, totalCount)
|
||||
|
@@ -11,26 +11,47 @@ import (
|
||||
"hotgo/internal/consts"
|
||||
)
|
||||
|
||||
var cacheResourcePath string
|
||||
|
||||
// GetResourcePath 获取插件资源路径
|
||||
func GetResourcePath(ctx context.Context) string {
|
||||
if len(cacheResourcePath) > 0 {
|
||||
return cacheResourcePath
|
||||
}
|
||||
basePath := g.Cfg().MustGet(ctx, "hotgo.addonsResourcePath").String()
|
||||
if basePath == "" {
|
||||
g.Log().Warning(ctx, "addons GetResourcePath not config found:'hotgo.addonsResourcePath', use default values:'resource'")
|
||||
basePath = "resource"
|
||||
}
|
||||
|
||||
cacheResourcePath = basePath
|
||||
return basePath
|
||||
}
|
||||
|
||||
// GetModulePath 获取指定模块相对路径
|
||||
func GetModulePath(name string) string {
|
||||
return "./" + consts.AddonsDir + "/" + name
|
||||
}
|
||||
|
||||
// ViewPath 默认的插件模板路径
|
||||
func ViewPath(name string) string {
|
||||
return consts.AddonsDir + "/" + name + "/" + "resource/template"
|
||||
// 模板路径:resource/addons/插件模块名称/template
|
||||
// 例如:resource/addons/hgexample/template
|
||||
// 如果你不喜欢现在的风格,可以自行调整
|
||||
func ViewPath(name, basePath string) string {
|
||||
return basePath + "/" + consts.AddonsDir + "/" + name + "/template"
|
||||
}
|
||||
|
||||
// StaticPath 默认的插件静态路映射关系
|
||||
// 最终效果:对外访问地址:/addons/插件模块名称;静态资源路径:/addons/插件模块名称/设置的子路径。
|
||||
// 如果你不喜欢现在的路由风格,可以自行调整
|
||||
func StaticPath(name, path string) (string, string) {
|
||||
return "/" + consts.AddonsDir + "/" + name, consts.AddonsDir + "/" + name + "/" + path
|
||||
// 静态资源路径:resource/public/addons/插件模块名称/public
|
||||
// 例如访问:http://127.0.0.1:8000/addons/hgexample/default 则指向文件-> resource/addons/hgexample/public/default
|
||||
// 如果你不喜欢现在的风格,可以自行调整
|
||||
func StaticPath(name, basePath string) (string, string) {
|
||||
return "/" + consts.AddonsDir + "/" + name, basePath + "/" + consts.AddonsDir + "/" + name + "/public"
|
||||
}
|
||||
|
||||
// RouterPrefix 路由前缀
|
||||
// 最终效果:/应用名称/插件模块名称/xxx/xxx。
|
||||
// 如果你不喜欢现在的路由风格,可以自行调整
|
||||
// 如果你不喜欢现在的风格,可以自行调整
|
||||
func RouterPrefix(ctx context.Context, app, name string) string {
|
||||
var prefix = "/"
|
||||
if app != "" {
|
||||
|
@@ -7,40 +7,54 @@ package addons
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/utility/validate"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BuildOption struct {
|
||||
Skeleton Skeleton
|
||||
Config *model.BuildAddonConfig
|
||||
Extend []string `json:"extend" dc:"扩展功能"`
|
||||
}
|
||||
|
||||
// Build 构建新插件
|
||||
func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err error) {
|
||||
func Build(ctx context.Context, option *BuildOption) (err error) {
|
||||
var (
|
||||
buildPath = "./" + consts.AddonsDir + "/" + sk.Name
|
||||
modulesPath = "./" + consts.AddonsDir + "/modules/" + sk.Name + ".go"
|
||||
webApiPath = gstr.Replace(conf.WebApiPath, "{$name}", sk.Name)
|
||||
webViewsPath = gstr.Replace(conf.WebViewsPath, "{$name}", sk.Name)
|
||||
resourcePath = GetResourcePath(ctx)
|
||||
buildPath = "./" + consts.AddonsDir + "/" + option.Skeleton.Name
|
||||
modulesPath = "./" + consts.AddonsDir + "/modules/" + option.Skeleton.Name + ".go"
|
||||
webApiPath = gstr.Replace(option.Config.WebApiPath, "{$name}", option.Skeleton.Name)
|
||||
webViewsPath = gstr.Replace(option.Config.WebViewsPath, "{$name}", option.Skeleton.Name)
|
||||
replaces = map[string]string{
|
||||
"@{.label}": sk.Label,
|
||||
"@{.name}": sk.Name,
|
||||
"@{.group}": strconv.Itoa(sk.Group),
|
||||
"@{.brief}": sk.Brief,
|
||||
"@{.description}": sk.Description,
|
||||
"@{.author}": sk.Author,
|
||||
"@{.version}": sk.Version,
|
||||
"@{.label}": option.Skeleton.Label,
|
||||
"@{.name}": option.Skeleton.Name,
|
||||
"@{.group}": strconv.Itoa(option.Skeleton.Group),
|
||||
"@{.brief}": option.Skeleton.Brief,
|
||||
"@{.description}": option.Skeleton.Description,
|
||||
"@{.author}": option.Skeleton.Author,
|
||||
"@{.version}": option.Skeleton.Version,
|
||||
"@{.hgVersion}": consts.VersionApp, // HG 版本
|
||||
}
|
||||
)
|
||||
|
||||
if resourcePath == "" {
|
||||
err = gerror.New("请先设置一个有效的插件资源路径,配置名称:'hotgo.addonsResourcePath'")
|
||||
return
|
||||
}
|
||||
|
||||
if err = checkBuildDir(buildPath, modulesPath, webApiPath, webViewsPath); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// scans directory recursively
|
||||
list, err := gfile.ScanDirFunc(conf.SrcPath, "*", true, func(path string) string {
|
||||
list, err := gfile.ScanDirFunc(option.Config.SrcPath, "*", true, func(path string) string {
|
||||
return path
|
||||
})
|
||||
|
||||
@@ -59,8 +73,8 @@ func Build(ctx context.Context, sk Skeleton, conf *model.BuildAddonConfig) (err
|
||||
}
|
||||
|
||||
flowFile := gstr.ReplaceByMap(path, map[string]string{
|
||||
gfile.RealPath(conf.SrcPath): "",
|
||||
".template": "",
|
||||
gfile.RealPath(option.Config.SrcPath): "",
|
||||
".template": "",
|
||||
})
|
||||
flowFile = buildPath + "/" + flowFile
|
||||
|
||||
@@ -90,6 +104,23 @@ 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 {
|
||||
return
|
||||
}
|
||||
|
||||
// 创建静态目录
|
||||
if validate.InSlice(option.Extend, consts.AddonsExtendResourcePublic) {
|
||||
_, staticPath := StaticPath(option.Skeleton.Name, resourcePath)
|
||||
content := fmt.Sprintf(resourcePublicDefaultFile, option.Skeleton.Label)
|
||||
if err = gfile.PutContents(staticPath+"/default", content); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 创建模板目录
|
||||
if validate.InSlice(option.Extend, consts.AddonsExtendResourceTemplate) {
|
||||
viewPath := ViewPath(option.Skeleton.Name, resourcePath)
|
||||
if err = gfile.PutContents(viewPath+"/home/index.html", resourceTemplateHomeFile); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -194,4 +194,39 @@ export function updateConfig(params) {
|
||||
}
|
||||
</style>
|
||||
`
|
||||
|
||||
resourcePublicDefaultFile = "Hello!这是创建插件 [%v] 时默认生成的一个静态目录文件,用于测试,当你看到这个提示时,说明已经联调成功啦!"
|
||||
|
||||
resourceTemplateHomeFile = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
|
||||
<meta name="keywords" content="@{.Keywords}"/>
|
||||
<meta name="description" content="@{.Description}"/>
|
||||
<title>@{.Title}</title>
|
||||
<script type="text/javascript" src="/resource/home/js/jquery-3.6.0.min.js"></script>
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="padding-top: 100px;text-align:center;">
|
||||
<h1><p>Hello,@{.Data.name}!!</p></h1>
|
||||
<h2><p>@{.Data.module}</p></h2>
|
||||
<h2><p>服务器时间:@{.Data.time}</p></h2>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</html>`
|
||||
)
|
||||
|
@@ -15,8 +15,16 @@ import (
|
||||
"hotgo/internal/model/input/form"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Option 模块启动选项
|
||||
type Option struct {
|
||||
Server *ghttp.Server // http服务器
|
||||
// 更多选项参数
|
||||
// ..
|
||||
}
|
||||
|
||||
// Skeleton 模块骨架
|
||||
type Skeleton struct {
|
||||
Label string `json:"label"` // 标识
|
||||
@@ -37,32 +45,42 @@ func (s *Skeleton) GetModule() Module {
|
||||
|
||||
// Module 插件模块
|
||||
type Module interface {
|
||||
Init(ctx context.Context) // 初始化
|
||||
InitRouter(ctx context.Context, group *ghttp.RouterGroup) // 初始化并注册路由
|
||||
Ctx() context.Context // 上下文
|
||||
GetSkeleton() *Skeleton // 架子
|
||||
Install(ctx context.Context) error // 安装模块
|
||||
Upgrade(ctx context.Context) error // 更新模块
|
||||
UnInstall(ctx context.Context) error // 卸载模块
|
||||
Start(option *Option) (err error) // 启动模块
|
||||
Stop() (err error) // 停止模块
|
||||
Ctx() context.Context // 上下文
|
||||
GetSkeleton() *Skeleton // 获取模块
|
||||
Install(ctx context.Context) (err error) // 安装模块
|
||||
Upgrade(ctx context.Context) (err error) // 更新模块
|
||||
UnInstall(ctx context.Context) (err error) // 卸载模块
|
||||
}
|
||||
|
||||
var (
|
||||
modules = make(map[string]Module, 0)
|
||||
modules = make(map[string]Module)
|
||||
mLock sync.Mutex
|
||||
)
|
||||
|
||||
// InitModules 初始化所有已注册模块
|
||||
func InitModules(ctx context.Context) {
|
||||
for _, module := range modules {
|
||||
module.Init(ctx)
|
||||
// StartModules 启动所有已安装模块
|
||||
func StartModules(ctx context.Context, option *Option) (err error) {
|
||||
for _, module := range filterInstalled() {
|
||||
if err = module.Start(option); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 为所有已安装模块设置静态资源路径
|
||||
AddStaticPath(ctx, option.Server)
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterModulesRouter 注册所有已安装模块路由
|
||||
func RegisterModulesRouter(ctx context.Context, group *ghttp.RouterGroup) {
|
||||
// StopModules 停止所有已安装模块
|
||||
func StopModules(ctx context.Context) {
|
||||
for _, module := range filterInstalled() {
|
||||
module.InitRouter(ctx, group)
|
||||
if err := module.Stop(); err != nil {
|
||||
g.Log().Warningf(ctx, "StopModules err:%v, module:%v", err.Error(), module.GetSkeleton().Name)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RegisterModule 注册模块
|
||||
@@ -123,9 +141,20 @@ func GetModuleRealPath(name string) string {
|
||||
|
||||
// NewView 初始化一个插件的模板引擎
|
||||
func NewView(ctx context.Context, name string) *gview.View {
|
||||
view := gview.New()
|
||||
basePath := GetResourcePath(ctx)
|
||||
if basePath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := view.SetPath(ViewPath(name)); err != nil {
|
||||
view := gview.New()
|
||||
path := ViewPath(name, basePath)
|
||||
|
||||
if !gfile.IsDir(gfile.RealPath(path)) {
|
||||
g.Log().Warningf(ctx, "NewView template path does not exist:%v,default use of main module template.", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := view.SetPath(path); err != nil {
|
||||
g.Log().Warningf(ctx, "NewView SetPath err:%+v", err)
|
||||
return nil
|
||||
}
|
||||
@@ -145,12 +174,8 @@ func NewView(ctx context.Context, name string) *gview.View {
|
||||
}
|
||||
|
||||
// AddStaticPath 设置插件静态目录映射
|
||||
func AddStaticPath(ctx context.Context, server *ghttp.Server, p ...string) {
|
||||
basePath := g.Cfg().MustGet(ctx, "server.serverRoot").String()
|
||||
if len(p) > 0 {
|
||||
basePath = p[0]
|
||||
}
|
||||
|
||||
func AddStaticPath(ctx context.Context, server *ghttp.Server) {
|
||||
basePath := GetResourcePath(ctx)
|
||||
if basePath == "" {
|
||||
return
|
||||
}
|
||||
@@ -160,7 +185,7 @@ func AddStaticPath(ctx context.Context, server *ghttp.Server, p ...string) {
|
||||
prefix, path := StaticPath(name, basePath)
|
||||
if !gres.Contains(path) {
|
||||
if _, err := gfile.Search(path); err != nil {
|
||||
g.Log().Warningf(ctx, `AddStaticPath failed: %v`, err)
|
||||
g.Log().Warningf(ctx, `addons AddStaticPath failed: %v`, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
23
server/internal/library/cache/cache.go
vendored
23
server/internal/library/cache/cache.go
vendored
@@ -11,8 +11,6 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"hotgo/internal/library/cache/file"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
// cache 缓存驱动
|
||||
@@ -29,33 +27,24 @@ func Instance() *gcache.Cache {
|
||||
// SetAdapter 设置缓存适配器
|
||||
func SetAdapter(ctx context.Context) {
|
||||
var adapter gcache.Adapter
|
||||
conf, err := service.SysConfig().GetLoadCache(ctx)
|
||||
if err != nil {
|
||||
g.Log().Fatalf(ctx, "cache init err:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if conf == nil {
|
||||
conf = new(model.CacheConfig)
|
||||
g.Log().Info(ctx, "no cache driver is configured. default memory cache is used.")
|
||||
}
|
||||
|
||||
switch conf.Adapter {
|
||||
switch g.Cfg().MustGet(ctx, "cache.adapter").String() {
|
||||
case "redis":
|
||||
adapter = gcache.NewAdapterRedis(g.Redis())
|
||||
case "file":
|
||||
if conf.FileDir == "" {
|
||||
fileDir := g.Cfg().MustGet(ctx, "cache.fileDir").String()
|
||||
if fileDir == "" {
|
||||
g.Log().Fatal(ctx, "file path must be configured for file caching.")
|
||||
return
|
||||
}
|
||||
|
||||
if !gfile.Exists(conf.FileDir) {
|
||||
if err := gfile.Mkdir(conf.FileDir); err != nil {
|
||||
if !gfile.Exists(fileDir) {
|
||||
if err := gfile.Mkdir(fileDir); err != nil {
|
||||
g.Log().Fatalf(ctx, "failed to create the cache directory. procedure, err:%+v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
adapter = file.NewAdapterFile(conf.FileDir)
|
||||
adapter = file.NewAdapterFile(fileDir)
|
||||
default:
|
||||
adapter = gcache.NewAdapterMemory()
|
||||
}
|
||||
|
61
server/internal/library/dict/dict.go
Normal file
61
server/internal/library/dict/dict.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Package dict
|
||||
// @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 dict
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"hotgo/internal/model"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
BuiltinId int64 = -1 // 内置字典ID
|
||||
EnumsId int64 = -2 // 枚举字典ID
|
||||
FuncId int64 = -3 // 方法字典ID
|
||||
)
|
||||
|
||||
var NotExistKeyError = errors.New("not exist key")
|
||||
|
||||
// GetOptions 获取内置选项
|
||||
func GetOptions(ctx context.Context, key string) (opts []*model.Option, err error) {
|
||||
opts = GetEnumsOptions(key)
|
||||
if opts != nil {
|
||||
return
|
||||
}
|
||||
return GetFuncOptions(ctx, key)
|
||||
}
|
||||
|
||||
// GetOptionsById 通过类型ID获取内置选项
|
||||
func GetOptionsById(ctx context.Context, id int64) (opts []*model.Option, err error) {
|
||||
for _, v := range GetAllEnums() {
|
||||
if v.Id == id {
|
||||
return v.Opts, nil
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range GetAllFunc() {
|
||||
if v.Id == id {
|
||||
return LoadFuncOptions(ctx, v)
|
||||
}
|
||||
}
|
||||
|
||||
err = NotExistKeyError
|
||||
return
|
||||
}
|
||||
|
||||
// GenIdHash 生成字典id
|
||||
func GenIdHash(str string, t int64) int64 {
|
||||
prefix := 10000 * t
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte("dict" + str))
|
||||
|
||||
idStr := fmt.Sprintf("%d%d", prefix, int64(h.Sum32()))
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
return id
|
||||
}
|
106
server/internal/library/dict/dict_option.go
Normal file
106
server/internal/library/dict/dict_option.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Package dict
|
||||
// @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 dict
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hash/fnv"
|
||||
"hotgo/internal/model"
|
||||
)
|
||||
|
||||
// GenDefaultOption 生成默认表格回显样式
|
||||
func GenDefaultOption(key interface{}, label string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: "default",
|
||||
}
|
||||
}
|
||||
|
||||
func GenSuccessOption(key interface{}, label string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: "success",
|
||||
}
|
||||
}
|
||||
|
||||
func GenWarningOption(key interface{}, label string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: "warning",
|
||||
}
|
||||
}
|
||||
|
||||
func GenErrorOption(key interface{}, label string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: "error",
|
||||
}
|
||||
}
|
||||
|
||||
func GenInfoOption(key interface{}, label string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: "info",
|
||||
}
|
||||
}
|
||||
|
||||
// GenCustomOption 生成自定义表格回显样式
|
||||
func GenCustomOption(key interface{}, label string, custom string) *model.Option {
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: custom,
|
||||
}
|
||||
}
|
||||
|
||||
// GenHashOption 根据不同label以hash算法生成表格回显样式
|
||||
func GenHashOption(key interface{}, label string) *model.Option {
|
||||
strings := []string{"default", "primary", "info", "success", "warning", "error"}
|
||||
hash := fnv.New32()
|
||||
|
||||
tag := "default"
|
||||
if _, err := hash.Write(gconv.Bytes(label)); err == nil {
|
||||
index := int(hash.Sum32()) % len(strings)
|
||||
tag = strings[index]
|
||||
}
|
||||
return &model.Option{
|
||||
Key: key,
|
||||
Label: label,
|
||||
Value: key,
|
||||
ListClass: tag,
|
||||
}
|
||||
}
|
||||
|
||||
// GetOptionLabel 通过key找到label
|
||||
func GetOptionLabel(ses []*model.Option, key interface{}) string {
|
||||
for _, v := range ses {
|
||||
if gconv.String(v.Key) == gconv.String(key) {
|
||||
return v.Label
|
||||
}
|
||||
}
|
||||
return `Unknown`
|
||||
}
|
||||
|
||||
// HasOptionKey 是否存在指定key
|
||||
func HasOptionKey(ses []*model.Option, key interface{}) bool {
|
||||
for _, v := range ses {
|
||||
if gconv.String(v.Key) == gconv.String(key) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
72
server/internal/library/dict/dict_register_enums.go
Normal file
72
server/internal/library/dict/dict_register_enums.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Package dict
|
||||
// @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 dict
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hotgo/internal/model"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type EnumsOption struct {
|
||||
Id int64 // 字典ID,由系统自动生成
|
||||
Key string // 字典选项key
|
||||
Label string // 字典选项标签名称
|
||||
Opts []*model.Option // 数据选项
|
||||
}
|
||||
|
||||
var (
|
||||
enumsOptions = make(map[string]*EnumsOption)
|
||||
eLock sync.Mutex
|
||||
)
|
||||
|
||||
// GetAllEnums 获取所有枚举字典
|
||||
func GetAllEnums() map[string]*EnumsOption {
|
||||
return enumsOptions
|
||||
}
|
||||
|
||||
// RegisterEnums 注册枚举字典选项
|
||||
func RegisterEnums(key, label string, opts []*model.Option) {
|
||||
eLock.Lock()
|
||||
defer eLock.Unlock()
|
||||
|
||||
if len(key) == 0 {
|
||||
panic("字典key不能为空")
|
||||
}
|
||||
|
||||
if _, ok := enumsOptions[key]; ok {
|
||||
panic(fmt.Sprintf("重复注册枚举字典选项:%v", key))
|
||||
}
|
||||
|
||||
for _, v := range opts {
|
||||
v.Type = key
|
||||
}
|
||||
enumsOptions[key] = &EnumsOption{
|
||||
Id: GenIdHash(key, EnumsId),
|
||||
Key: key,
|
||||
Label: label,
|
||||
Opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// SaveEnums 更新枚举字典选项
|
||||
func SaveEnums(key, label string, opts []*model.Option) {
|
||||
eLock.Lock()
|
||||
defer eLock.Unlock()
|
||||
if _, ok := enumsOptions[key]; ok {
|
||||
delete(enumsOptions, key)
|
||||
}
|
||||
RegisterEnums(key, label, opts)
|
||||
}
|
||||
|
||||
// GetEnumsOptions 获取指定枚举字典的数据选项
|
||||
func GetEnumsOptions(key string) []*model.Option {
|
||||
enums, ok := enumsOptions[key]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return enums.Opts
|
||||
}
|
131
server/internal/library/dict/dict_register_func.go
Normal file
131
server/internal/library/dict/dict_register_func.go
Normal file
@@ -0,0 +1,131 @@
|
||||
// Package dict
|
||||
// @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 dict
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"hotgo/internal/model"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// FuncDict 方法字典,实现本接口即可使用内置方法字典
|
||||
type FuncDict func(ctx context.Context) (res []*model.Option, err error)
|
||||
|
||||
type FuncOption struct {
|
||||
Id int64 // 字典ID,由系统自动生成
|
||||
Key string // 字典选项key
|
||||
Label string // 字典选项标签名称
|
||||
Fun FuncDict // 字典方法
|
||||
Cache bool // 是否缓存数据选项
|
||||
Opts []*model.Option // 缓存的数据选项
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
var (
|
||||
funcOptions = make(map[string]*FuncOption)
|
||||
fLock sync.Mutex
|
||||
)
|
||||
|
||||
// GetAllFunc 获取所有方法字典
|
||||
func GetAllFunc() map[string]*FuncOption {
|
||||
return funcOptions
|
||||
}
|
||||
|
||||
// RegisterFunc 注册方法字典选项
|
||||
func RegisterFunc(key, label string, fun FuncDict, cache ...bool) {
|
||||
fLock.Lock()
|
||||
defer fLock.Unlock()
|
||||
|
||||
if len(key) == 0 {
|
||||
panic("字典key不能为空")
|
||||
}
|
||||
|
||||
if _, ok := funcOptions[key]; ok {
|
||||
panic(fmt.Sprintf("重复注册方法选项:%v", key))
|
||||
}
|
||||
|
||||
isCache := false
|
||||
if len(cache) > 0 {
|
||||
isCache = cache[0]
|
||||
}
|
||||
|
||||
funcOptions[key] = &FuncOption{
|
||||
Id: GenIdHash(key, FuncId),
|
||||
Key: key,
|
||||
Label: label,
|
||||
Fun: fun,
|
||||
Cache: isCache,
|
||||
Opts: nil,
|
||||
}
|
||||
}
|
||||
|
||||
// SaveFunc 更新方法字典选项
|
||||
func SaveFunc(key, label string, fun FuncDict, cache ...bool) {
|
||||
fLock.Lock()
|
||||
defer fLock.Unlock()
|
||||
if _, ok := funcOptions[key]; ok {
|
||||
delete(funcOptions, key)
|
||||
}
|
||||
RegisterFunc(key, label, fun, cache...)
|
||||
}
|
||||
|
||||
// ClearFuncCache 清理指定方法缓存选项
|
||||
func ClearFuncCache(key string) (err error) {
|
||||
fun, ok := funcOptions[key]
|
||||
if !ok {
|
||||
err = NotExistKeyError
|
||||
return
|
||||
}
|
||||
|
||||
fun.Lock()
|
||||
defer fun.Unlock()
|
||||
|
||||
if fun.Opts != nil {
|
||||
fun.Opts = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetFuncOptions 获取指定方法字典的数据选项
|
||||
func GetFuncOptions(ctx context.Context, key string) (res []*model.Option, err error) {
|
||||
fun, ok := funcOptions[key]
|
||||
if !ok {
|
||||
err = NotExistKeyError
|
||||
return
|
||||
}
|
||||
return LoadFuncOptions(ctx, fun)
|
||||
}
|
||||
|
||||
// LoadFuncOptions 加载指定方法字典的数据选项
|
||||
func LoadFuncOptions(ctx context.Context, fun *FuncOption) (res []*model.Option, err error) {
|
||||
if fun.Cache && fun.Opts != nil {
|
||||
res = fun.Opts
|
||||
return
|
||||
}
|
||||
|
||||
fun.Lock()
|
||||
defer fun.Unlock()
|
||||
|
||||
if fun.Cache && fun.Opts != nil {
|
||||
res = fun.Opts
|
||||
return
|
||||
}
|
||||
|
||||
res, err = fun.Fun(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for k := range res {
|
||||
res[k].Type = fun.Key
|
||||
}
|
||||
|
||||
if fun.Cache {
|
||||
fun.Opts = res
|
||||
}
|
||||
return
|
||||
}
|
@@ -44,8 +44,9 @@ type cBuild struct {
|
||||
}
|
||||
|
||||
const (
|
||||
cBuildBrief = `cross-building go project for lots of platforms`
|
||||
cBuildEg = `
|
||||
cBuildDefaultFile = "main.go"
|
||||
cBuildBrief = `cross-building go project for lots of platforms`
|
||||
cBuildEg = `
|
||||
gf build main.go
|
||||
gf build main.go --ps public,template
|
||||
gf build main.go --cgo
|
||||
@@ -123,7 +124,7 @@ type cBuildInput struct {
|
||||
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
|
||||
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
|
||||
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
|
||||
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
|
||||
Path string `short:"p" name:"path" brief:"output binary directory path, default is '.'" d:"."`
|
||||
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
|
||||
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
|
||||
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
|
||||
@@ -152,12 +153,13 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
|
||||
var (
|
||||
parser = gcmd.ParserFromCtx(ctx)
|
||||
file = parser.GetArg(2).String()
|
||||
file = in.File
|
||||
)
|
||||
if len(file) < 1 {
|
||||
if file == "" {
|
||||
file = parser.GetArg(2).String()
|
||||
// Check and use the main.go file.
|
||||
if gfile.Exists("main.go") {
|
||||
file = "main.go"
|
||||
if gfile.Exists(cBuildDefaultFile) {
|
||||
file = cBuildDefaultFile
|
||||
} else {
|
||||
mlog.Fatal("build file path is empty or main.go not found in current working directory")
|
||||
}
|
||||
@@ -239,13 +241,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
} else {
|
||||
genv.MustSet("CGO_ENABLED", "0")
|
||||
}
|
||||
var (
|
||||
cmd = ""
|
||||
ext = ""
|
||||
)
|
||||
for system, item := range platformMap {
|
||||
cmd = ""
|
||||
ext = ""
|
||||
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
|
||||
continue
|
||||
}
|
||||
@@ -258,58 +254,22 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
// For example:
|
||||
// `gf build`
|
||||
// `gf build -o main.exe`
|
||||
if runtime.GOOS == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
var outputPath string
|
||||
if len(in.Output) > 0 {
|
||||
outputPath = "-o " + in.Output
|
||||
} else {
|
||||
outputPath = "-o " + in.Name + ext
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s %s`,
|
||||
outputPath, ldFlags, in.Extra, file,
|
||||
c.doBinaryBuild(
|
||||
ctx, file,
|
||||
in.Output, in.Path,
|
||||
runtime.GOOS, runtime.GOARCH, in.Name, ldFlags, in.Extra,
|
||||
in.ExitWhenError,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
// Cross-building, output the compiled binary to specified path.
|
||||
if system == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
genv.MustSet("GOOS", system)
|
||||
genv.MustSet("GOARCH", arch)
|
||||
|
||||
var outputPath string
|
||||
if len(in.Output) > 0 {
|
||||
outputPath = "-o " + in.Output
|
||||
} else {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s/%s%s",
|
||||
in.Path, system+"_"+arch, in.Name, ext,
|
||||
)
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s%s`,
|
||||
outputPath, ldFlags, in.Extra, file,
|
||||
c.doBinaryBuild(
|
||||
ctx, file,
|
||||
in.Output, in.Path,
|
||||
system, arch, in.Name, ldFlags, in.Extra,
|
||||
in.ExitWhenError,
|
||||
false,
|
||||
)
|
||||
}
|
||||
mlog.Debug(fmt.Sprintf("build for GOOS=%s GOARCH=%s", system, arch))
|
||||
mlog.Debug(cmd)
|
||||
// It's not necessary printing the complete command string.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
|
||||
mlog.Printf(
|
||||
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
|
||||
system, arch, gstr.Trim(result),
|
||||
`you may use command option "--debug" to enable debug info and check the details`,
|
||||
)
|
||||
if in.ExitWhenError {
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
mlog.Debug(gstr.Trim(result))
|
||||
}
|
||||
// single binary building.
|
||||
if len(customSystems) == 0 && len(customArches) == 0 {
|
||||
goto buildDone
|
||||
@@ -322,6 +282,68 @@ buildDone:
|
||||
return
|
||||
}
|
||||
|
||||
func (c cBuild) doBinaryBuild(
|
||||
ctx context.Context,
|
||||
filePath string,
|
||||
outputPath, dirPath string,
|
||||
system, arch, name, ldFlags, extra string,
|
||||
exitWhenError bool,
|
||||
singleBuild bool,
|
||||
) {
|
||||
var (
|
||||
cmd string
|
||||
ext string
|
||||
)
|
||||
// Cross-building, output the compiled binary to specified path.
|
||||
if system == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
genv.MustSet("GOOS", system)
|
||||
genv.MustSet("GOARCH", arch)
|
||||
|
||||
if outputPath != "" {
|
||||
outputPath = "-o " + outputPath
|
||||
} else {
|
||||
if dirPath == "" {
|
||||
dirPath = "."
|
||||
} else {
|
||||
dirPath = gstr.TrimRight(dirPath, "/")
|
||||
}
|
||||
if singleBuild {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s%s",
|
||||
dirPath, name, ext,
|
||||
)
|
||||
} else {
|
||||
outputPath = fmt.Sprintf(
|
||||
"-o %s/%s/%s%s",
|
||||
dirPath, system+"_"+arch, name, ext,
|
||||
)
|
||||
}
|
||||
}
|
||||
cmd = fmt.Sprintf(
|
||||
`go build %s -ldflags "%s" %s%s`,
|
||||
outputPath, ldFlags, extra, filePath,
|
||||
)
|
||||
mlog.Debug(fmt.Sprintf("build for GOOS=%s GOARCH=%s", system, arch))
|
||||
mlog.Debug(cmd)
|
||||
// It's not necessary printing the complete command string, filtering ldFlags.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
|
||||
mlog.Printf(
|
||||
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
|
||||
system, arch, gstr.Trim(result),
|
||||
`you may use command option "--debug" to enable debug info and check the details`,
|
||||
)
|
||||
if exitWhenError {
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
mlog.Debug(gstr.Trim(result))
|
||||
}
|
||||
}
|
||||
|
||||
// getBuildInVarStr retrieves and returns the custom build-in variables in configuration
|
||||
// file as json.
|
||||
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
|
||||
|
@@ -99,6 +99,7 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
|
||||
|
||||
if len(in.WatchPaths) == 1 {
|
||||
in.WatchPaths = strings.Split(in.WatchPaths[0], ",")
|
||||
mlog.Printf("watchPaths: %v", in.WatchPaths)
|
||||
}
|
||||
|
||||
app := &cRunApp{
|
||||
@@ -109,8 +110,9 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
|
||||
WatchPaths: in.WatchPaths,
|
||||
}
|
||||
dirty := gtype.NewBool()
|
||||
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
|
||||
if gfile.ExtName(event.Path) != "go" && !matchWatchPaths(app.WatchPaths, event.Path) {
|
||||
|
||||
callbackFunc := func(event *gfsnotify.Event) {
|
||||
if gfile.ExtName(event.Path) != "go" {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,10 +127,22 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
|
||||
mlog.Printf(`watched file changes: %s`, event.String())
|
||||
app.Run(ctx)
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
|
||||
if len(app.WatchPaths) > 0 {
|
||||
for _, path := range app.WatchPaths {
|
||||
_, err = gfsnotify.Add(gfile.RealPath(path), callbackFunc)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err = gfsnotify.Add(gfile.RealPath("."), callbackFunc)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
go app.Run(ctx)
|
||||
select {}
|
||||
}
|
||||
|
@@ -0,0 +1,151 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
func Test_Build_Single(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `t.test`
|
||||
binaryPath = gtest.DataPath(`build`, `single`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: cBuildDefaultFile,
|
||||
Name: binaryName,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Output(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `tt`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, `tt`)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, `tt`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Output: "./tt/tt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_Path(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `single`)
|
||||
pwd = gfile.Pwd()
|
||||
dirName = "ttt"
|
||||
binaryName = `main`
|
||||
binaryDirPath = gtest.DataPath(`build`, `single`, dirName)
|
||||
binaryPath = gtest.DataPath(`build`, `single`, dirName, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
Path: "ttt",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Single_VarMap(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `varmap`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryName = `main`
|
||||
binaryPath = gtest.DataPath(`build`, `varmap`, binaryName)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPath), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
VarMap: map[string]interface{}{
|
||||
"a": "1",
|
||||
"b": "2",
|
||||
},
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPath), true)
|
||||
|
||||
result, err := gproc.ShellExec(ctx, binaryPath)
|
||||
t.AssertNil(err)
|
||||
t.Assert(gstr.Contains(result, `a: 1`), true)
|
||||
t.Assert(gstr.Contains(result, `b: 2`), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Build_Multiple(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
buildPath = gtest.DataPath(`build`, `multiple`)
|
||||
pwd = gfile.Pwd()
|
||||
binaryDirPath = gtest.DataPath(`build`, `multiple`, `temp`)
|
||||
binaryPathLinux = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `linux_amd64`, `ttt`)
|
||||
binaryPathWindows = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `windows_amd64`, `ttt.exe`)
|
||||
f = cBuild{}
|
||||
)
|
||||
defer gfile.Chdir(pwd)
|
||||
defer gfile.Remove(binaryDirPath)
|
||||
err := gfile.Chdir(buildPath)
|
||||
t.AssertNil(err)
|
||||
|
||||
t.Assert(gfile.Exists(binaryPathLinux), false)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), false)
|
||||
_, err = f.Index(ctx, cBuildInput{
|
||||
File: "multiple.go",
|
||||
Name: "ttt",
|
||||
Version: "v1.1",
|
||||
Arch: "amd64",
|
||||
System: "linux, windows",
|
||||
Path: "temp",
|
||||
})
|
||||
t.AssertNil(err)
|
||||
t.Assert(gfile.Exists(binaryPathLinux), true)
|
||||
t.Assert(gfile.Exists(binaryPathWindows), true)
|
||||
})
|
||||
}
|
@@ -7,13 +7,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genctrl"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Gen_Ctrl_Default(t *testing.T) {
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
@@ -209,3 +210,261 @@ func Test_Gen_Dao_TypeMapping(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func execSqlFile(db gdb.DB, filePath string, args ...any) error {
|
||||
sqlContent := fmt.Sprintf(
|
||||
gfile.GetContents(filePath),
|
||||
args...,
|
||||
)
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err := db.Exec(ctx, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_Issue2572(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table1 = "user1"
|
||||
table2 = "user2"
|
||||
issueDirPath = gtest.DataPath(`issue`, `2572`)
|
||||
)
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql1.sql`)))
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql2.sql`)))
|
||||
defer dropTableWithDb(db, table1)
|
||||
defer dropTableWithDb(db, table2)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Copy(issueDirPath, path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Remove(path)
|
||||
|
||||
pwd := gfile.Pwd()
|
||||
err = gfile.Chdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Chdir(pwd)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(generatedFiles), 8)
|
||||
for i, generatedFile := range generatedFiles {
|
||||
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
|
||||
}
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/internal/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/internal/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/do/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/do/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/entity/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/entity/user_2.go"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Gen_Dao_Issue2616(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
db = testDB
|
||||
table1 = "user1"
|
||||
table2 = "user2"
|
||||
issueDirPath = gtest.DataPath(`issue`, `2616`)
|
||||
)
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql1.sql`)))
|
||||
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql2.sql`)))
|
||||
defer dropTableWithDb(db, table1)
|
||||
defer dropTableWithDb(db, table2)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: false,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Copy(issueDirPath, path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Remove(path)
|
||||
|
||||
pwd := gfile.Pwd()
|
||||
err = gfile.Chdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
defer gfile.Chdir(pwd)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
|
||||
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
|
||||
t.AssertNil(err)
|
||||
t.Assert(len(generatedFiles), 8)
|
||||
for i, generatedFile := range generatedFiles {
|
||||
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
|
||||
}
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/internal/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/internal/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/dao/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/do/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/do/user_2.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/entity/user_1.go"), true)
|
||||
t.Assert(gstr.InArray(generatedFiles, "/model/entity/user_2.go"), true)
|
||||
|
||||
// Key string to check if overwrite the dao files.
|
||||
// dao user1 is not be overwritten as configured in config.yaml.
|
||||
// dao user2 is to be overwritten as configured in config.yaml.
|
||||
var (
|
||||
keyStr = `// I am not overwritten.`
|
||||
daoUser1Content = gfile.GetContents(path + "/dao/user_1.go")
|
||||
daoUser2Content = gfile.GetContents(path + "/dao/user_2.go")
|
||||
)
|
||||
t.Assert(gstr.Contains(daoUser1Content, keyStr), true)
|
||||
t.Assert(gstr.Contains(daoUser2Content, keyStr), false)
|
||||
})
|
||||
}
|
||||
|
||||
// https://github.com/gogf/gf/issues/2746
|
||||
func Test_Gen_Dao_Issue2746(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
err error
|
||||
mdb gdb.DB
|
||||
link2746 = "mariadb:root:12345678@tcp(127.0.0.1:3307)/test?loc=Local&parseTime=true"
|
||||
table = "issue2746"
|
||||
sqlContent = fmt.Sprintf(
|
||||
gtest.DataContent(`issue`, `2746`, `sql.sql`),
|
||||
table,
|
||||
)
|
||||
)
|
||||
mdb, err = gdb.New(gdb.ConfigNode{
|
||||
Link: link2746,
|
||||
})
|
||||
t.AssertNil(err)
|
||||
|
||||
array := gstr.SplitAndTrim(sqlContent, ";")
|
||||
for _, v := range array {
|
||||
if _, err = mdb.Exec(ctx, v); err != nil {
|
||||
t.AssertNil(err)
|
||||
}
|
||||
}
|
||||
defer dropTableWithDb(mdb, table)
|
||||
|
||||
var (
|
||||
path = gfile.Temp(guid.S())
|
||||
group = "test"
|
||||
in = gendao.CGenDaoInput{
|
||||
Path: path,
|
||||
Link: link2746,
|
||||
Tables: "",
|
||||
TablesEx: "",
|
||||
Group: group,
|
||||
Prefix: "",
|
||||
RemovePrefix: "",
|
||||
JsonCase: "SnakeScreaming",
|
||||
ImportPrefix: "",
|
||||
DaoPath: "",
|
||||
DoPath: "",
|
||||
EntityPath: "",
|
||||
TplDaoIndexPath: "",
|
||||
TplDaoInternalPath: "",
|
||||
TplDaoDoPath: "",
|
||||
TplDaoEntityPath: "",
|
||||
StdTime: false,
|
||||
WithTime: false,
|
||||
GJsonSupport: true,
|
||||
OverwriteDao: false,
|
||||
DescriptionTag: false,
|
||||
NoJsonTag: false,
|
||||
NoModelComment: false,
|
||||
Clear: false,
|
||||
TypeMapping: nil,
|
||||
}
|
||||
)
|
||||
err = gutil.FillStructWithDefault(&in)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = gfile.Mkdir(path)
|
||||
t.AssertNil(err)
|
||||
|
||||
_, err = gendao.CGenDao{}.Dao(ctx, in)
|
||||
t.AssertNil(err)
|
||||
defer gfile.Remove(path)
|
||||
|
||||
var (
|
||||
file = filepath.FromSlash(path + "/model/entity/issue_2746.go")
|
||||
expectContent = gtest.DataContent(`issue`, `2746`, `issue_2746.go`)
|
||||
)
|
||||
t.Assert(expectContent, gfile.GetContents(file))
|
||||
})
|
||||
}
|
||||
|
@@ -7,13 +7,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/guid"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"hotgo/internal/library/hggen/internal/cmd/genservice"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Gen_Service_Default(t *testing.T) {
|
||||
|
@@ -202,6 +202,7 @@ type (
|
||||
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
|
||||
|
||||
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
|
||||
genItems *CGenDaoInternalGenItems
|
||||
}
|
||||
CGenDaoOutput struct{}
|
||||
|
||||
@@ -220,6 +221,7 @@ type (
|
||||
)
|
||||
|
||||
func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
|
||||
in.genItems = newCGenDaoInternalGenItems()
|
||||
if g.Cfg().Available(ctx) {
|
||||
v := g.Cfg().MustGet(ctx, CGenDaoConfig)
|
||||
if v.IsSlice() {
|
||||
@@ -232,12 +234,16 @@ func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput,
|
||||
} else {
|
||||
doGenDaoForArray(ctx, -1, in)
|
||||
}
|
||||
doClear(in.genItems)
|
||||
mlog.Print("done!")
|
||||
return
|
||||
}
|
||||
|
||||
// doGenDaoForArray implements the "gen dao" command for configuration array.
|
||||
func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
if in.genItems == nil {
|
||||
in.genItems = newCGenDaoInternalGenItems()
|
||||
}
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
@@ -312,6 +318,8 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
newTableNames[i] = newTableName
|
||||
}
|
||||
|
||||
in.genItems.Scale()
|
||||
|
||||
// Dao: index and internal.
|
||||
generateDao(ctx, CGenDaoInternalInput{
|
||||
CGenDaoInput: in,
|
||||
@@ -333,6 +341,8 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
|
||||
TableNames: tableNames,
|
||||
NewTableNames: newTableNames,
|
||||
})
|
||||
|
||||
in.genItems.SetClear(in.Clear)
|
||||
}
|
||||
|
||||
func getImportPartContent(ctx context.Context, source string, isDo bool, appendImports []string) string {
|
||||
|
@@ -7,22 +7,40 @@
|
||||
package gendao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/utility/mlog"
|
||||
"hotgo/internal/library/hggen/internal/utility/utils"
|
||||
)
|
||||
|
||||
func doClear(ctx context.Context, dirPath string, force bool) {
|
||||
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
func doClear(items *CGenDaoInternalGenItems) {
|
||||
var allGeneratedFilePaths = make([]string, 0)
|
||||
for _, item := range items.Items {
|
||||
allGeneratedFilePaths = append(allGeneratedFilePaths, item.GeneratedFilePaths...)
|
||||
}
|
||||
for _, file := range files {
|
||||
if force || utils.IsFileDoNotEdit(file) {
|
||||
if err = gfile.Remove(file); err != nil {
|
||||
for i, v := range allGeneratedFilePaths {
|
||||
allGeneratedFilePaths[i] = gfile.RealPath(v)
|
||||
}
|
||||
for _, item := range items.Items {
|
||||
if !item.Clear {
|
||||
continue
|
||||
}
|
||||
doClearItem(item, allGeneratedFilePaths)
|
||||
}
|
||||
}
|
||||
|
||||
func doClearItem(item CGenDaoInternalGenItem, allGeneratedFilePaths []string) {
|
||||
var generatedFilePaths = make([]string, 0)
|
||||
for _, dirPath := range item.StorageDirPaths {
|
||||
filePaths, err := gfile.ScanDirFile(dirPath, "*.go", true)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
generatedFilePaths = append(generatedFilePaths, filePaths...)
|
||||
}
|
||||
for _, filePath := range generatedFilePaths {
|
||||
if !gstr.InArray(allGeneratedFilePaths, filePath) {
|
||||
if err := gfile.Remove(filePath); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
}
|
||||
|
@@ -30,9 +30,7 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
|
||||
dirPathDao = gfile.Join(in.Path, in.DaoPath)
|
||||
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
|
||||
)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDao, true)
|
||||
}
|
||||
in.genItems.AppendDirPath(dirPathDao)
|
||||
for i := 0; i < len(in.TableNames); i++ {
|
||||
generateDaoSingle(ctx, generateDaoSingleInput{
|
||||
CGenDaoInternalInput: in,
|
||||
@@ -108,6 +106,8 @@ type generateDaoIndexInput struct {
|
||||
|
||||
func generateDaoIndex(in generateDaoIndexInput) {
|
||||
path := filepath.FromSlash(gfile.Join(in.DirPathDao, in.FileName+".go"))
|
||||
// It should add path to result slice whenever it would generate the path file or not.
|
||||
in.genItems.AppendGeneratedFilePath(path)
|
||||
if in.OverwriteDao || !gfile.Exists(path) {
|
||||
indexContent := gstr.ReplaceByMap(
|
||||
getTemplateFromPathOrDefault(in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent),
|
||||
@@ -151,6 +151,7 @@ func generateDaoInternal(in generateDaoInternalInput) {
|
||||
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),
|
||||
})
|
||||
modelContent = replaceDefaultVar(in.CGenDaoInternalInput, modelContent)
|
||||
in.genItems.AppendGeneratedFilePath(path)
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
|
@@ -24,9 +24,7 @@ import (
|
||||
|
||||
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathDo = filepath.FromSlash(gfile.Join(in.Path, in.DoPath))
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathDo, false)
|
||||
}
|
||||
in.genItems.AppendDirPath(dirPathDo)
|
||||
in.NoJsonTag = true
|
||||
in.DescriptionTag = false
|
||||
in.NoModelComment = false
|
||||
@@ -66,6 +64,7 @@ func generateDo(ctx context.Context, in CGenDaoInternalInput) {
|
||||
gstr.CaseCamel(newTableName),
|
||||
structDefinition,
|
||||
)
|
||||
in.genItems.AppendGeneratedFilePath(doFilePath)
|
||||
err = gfile.PutContents(doFilePath, strings.TrimSpace(modelContent))
|
||||
if err != nil {
|
||||
mlog.Fatalf(`writing content to "%s" failed: %v`, doFilePath, err)
|
||||
|
@@ -22,9 +22,7 @@ import (
|
||||
|
||||
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
|
||||
if in.Clear {
|
||||
doClear(ctx, dirPathEntity, false)
|
||||
}
|
||||
in.genItems.AppendDirPath(dirPathEntity)
|
||||
// Model content.
|
||||
for i, tableName := range in.TableNames {
|
||||
fieldMap, err := in.DB.TableFields(ctx, tableName)
|
||||
@@ -51,7 +49,7 @@ func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
|
||||
appendImports,
|
||||
)
|
||||
)
|
||||
|
||||
in.genItems.AppendGeneratedFilePath(entityFilePath)
|
||||
err = gfile.PutContents(entityFilePath, strings.TrimSpace(entityContent))
|
||||
if err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", entityFilePath, err)
|
||||
|
@@ -0,0 +1,53 @@
|
||||
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gendao
|
||||
|
||||
type (
|
||||
CGenDaoInternalGenItems struct {
|
||||
index int
|
||||
Items []CGenDaoInternalGenItem
|
||||
}
|
||||
CGenDaoInternalGenItem struct {
|
||||
Clear bool
|
||||
StorageDirPaths []string
|
||||
GeneratedFilePaths []string
|
||||
}
|
||||
)
|
||||
|
||||
func newCGenDaoInternalGenItems() *CGenDaoInternalGenItems {
|
||||
return &CGenDaoInternalGenItems{
|
||||
index: -1,
|
||||
Items: make([]CGenDaoInternalGenItem, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *CGenDaoInternalGenItems) Scale() {
|
||||
i.Items = append(i.Items, CGenDaoInternalGenItem{
|
||||
StorageDirPaths: make([]string, 0),
|
||||
GeneratedFilePaths: make([]string, 0),
|
||||
Clear: false,
|
||||
})
|
||||
i.index++
|
||||
}
|
||||
|
||||
func (i *CGenDaoInternalGenItems) SetClear(clear bool) {
|
||||
i.Items[i.index].Clear = clear
|
||||
}
|
||||
|
||||
func (i CGenDaoInternalGenItems) AppendDirPath(storageDirPath string) {
|
||||
i.Items[i.index].StorageDirPaths = append(
|
||||
i.Items[i.index].StorageDirPaths,
|
||||
storageDirPath,
|
||||
)
|
||||
}
|
||||
|
||||
func (i CGenDaoInternalGenItems) AppendGeneratedFilePath(generatedFilePath string) {
|
||||
i.Items[i.index].GeneratedFilePaths = append(
|
||||
i.Items[i.index].GeneratedFilePaths,
|
||||
generatedFilePath,
|
||||
)
|
||||
}
|
@@ -174,7 +174,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
|
||||
// Parse single logic package folder.
|
||||
var (
|
||||
// StructName => FunctionDefinitions
|
||||
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
|
||||
srcPkgInterfaceMap = gmap.NewListMap()
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
importAliasToPathMap = gmap.NewStrStrMap() // for conflict imports check. alias => import path(with `"`)
|
||||
importPathToAliasMap = gmap.NewStrStrMap() // for conflict imports check. import path(with `"`) => alias
|
||||
|
@@ -12,6 +12,7 @@ import (
|
||||
"go/token"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
@@ -99,10 +100,9 @@ func (c CGenService) calculateCodeCommented(in CGenServiceInput, fileContent str
|
||||
}
|
||||
|
||||
func (c CGenService) calculateInterfaceFunctions(
|
||||
in CGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray,
|
||||
in CGenServiceInput, fileContent string, srcPkgInterfaceMap *gmap.ListMap,
|
||||
) (err error) {
|
||||
var (
|
||||
ok bool
|
||||
matches [][]string
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
)
|
||||
@@ -142,9 +142,11 @@ func (c CGenService) calculateInterfaceFunctions(
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
|
||||
if !srcPkgInterfaceMap.Contains(structName) {
|
||||
srcPkgInterfaceFuncArray = garray.NewStrArray()
|
||||
srcPkgInterfaceMap.Set(structName, srcPkgInterfaceFuncArray)
|
||||
} else {
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap.Get(structName).(*garray.StrArray)
|
||||
}
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
}
|
||||
@@ -165,8 +167,8 @@ func (c CGenService) calculateInterfaceFunctions(
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
if !srcPkgInterfaceMap.Contains(structName) {
|
||||
srcPkgInterfaceMap.Set(structName, garray.NewStrArray())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
@@ -23,7 +24,7 @@ import (
|
||||
type generateServiceFilesInput struct {
|
||||
CGenServiceInput
|
||||
DstFilePath string // Absolute file path for generated service go file.
|
||||
SrcStructFunctions map[string]*garray.StrArray
|
||||
SrcStructFunctions *gmap.ListMap
|
||||
SrcImportedPackages []string
|
||||
SrcPackageName string
|
||||
DstPackageName string
|
||||
@@ -46,7 +47,8 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
// Type definitions.
|
||||
generatedContent += "type("
|
||||
generatedContent += "\n"
|
||||
for structName, funcArray := range in.SrcStructFunctions {
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName, funcArray := key.(string), value.(*garray.StrArray)
|
||||
allFuncArray.Append(funcArray.Slice()...)
|
||||
// Add comments to a method.
|
||||
for index, funcName := range funcArray.Slice() {
|
||||
@@ -60,7 +62,8 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
"{FuncDefinition}": funcArray.Join("\n\t"),
|
||||
}))
|
||||
generatedContent += "\n"
|
||||
}
|
||||
return true
|
||||
})
|
||||
generatedContent += ")"
|
||||
generatedContent += "\n"
|
||||
|
||||
@@ -70,17 +73,19 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatingInterfaceCheck string
|
||||
)
|
||||
// Variable definitions.
|
||||
for structName := range in.SrcStructFunctions {
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
return true
|
||||
}
|
||||
variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
}))
|
||||
variableContent += "\n"
|
||||
}
|
||||
return true
|
||||
})
|
||||
if variableContent != "" {
|
||||
generatedContent += "var("
|
||||
generatedContent += "\n"
|
||||
@@ -89,17 +94,19 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
|
||||
generatedContent += "\n"
|
||||
}
|
||||
// Variable register function definitions.
|
||||
for structName := range in.SrcStructFunctions {
|
||||
in.SrcStructFunctions.Iterator(func(key, value interface{}) bool {
|
||||
structName := key.(string)
|
||||
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
|
||||
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
|
||||
continue
|
||||
return true
|
||||
}
|
||||
generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
|
||||
"{StructName}": structName,
|
||||
"{InterfaceName}": "I" + structName,
|
||||
}))
|
||||
generatedContent += "\n\n"
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// Replace empty braces that have new line.
|
||||
generatedContent, _ = gregex.ReplaceString(`{[\s\t]+}`, `{}`, generatedContent)
|
||||
|
5
server/internal/library/hggen/internal/cmd/testdata/build/multiple/multiple.go
vendored
Normal file
5
server/internal/library/hggen/internal/cmd/testdata/build/multiple/multiple.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
5
server/internal/library/hggen/internal/cmd/testdata/build/single/main.go
vendored
Normal file
5
server/internal/library/hggen/internal/cmd/testdata/build/single/main.go
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
|
||||
}
|
12
server/internal/library/hggen/internal/cmd/testdata/build/varmap/go.mod
vendored
Normal file
12
server/internal/library/hggen/internal/cmd/testdata/build/varmap/go.mod
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
module github.com/gogf/gf/cmd/gf/cmd/gf/testdata/vardump/v2
|
||||
|
||||
go 1.18
|
||||
|
||||
require github.com/gogf/gf/v2 v2.6.1
|
||||
|
||||
require (
|
||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/gogf/gf/v2 => ../../../../../../../
|
27
server/internal/library/hggen/internal/cmd/testdata/build/varmap/go.sum
vendored
Normal file
27
server/internal/library/hggen/internal/cmd/testdata/build/varmap/go.sum
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
|
||||
go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
|
||||
go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
|
||||
go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
|
||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
13
server/internal/library/hggen/internal/cmd/testdata/build/varmap/main.go
vendored
Normal file
13
server/internal/library/hggen/internal/cmd/testdata/build/varmap/main.go
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gbuild"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for k, v := range gbuild.Data() {
|
||||
fmt.Printf("%s: %v\n", k, v)
|
||||
}
|
||||
}
|
@@ -8,6 +8,7 @@ package article
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"hotgo/internal/library/hggen/internal/cmd/testdata/genservice/service"
|
||||
)
|
||||
|
||||
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/config.yaml
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/config.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "user1"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
group: "sys"
|
||||
clear: true
|
||||
overwriteDao: true
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "user2"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
group: "book"
|
||||
clear: true
|
||||
overwriteDao: true
|
||||
|
||||
|
||||
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/internal/user_3.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/internal/user_3.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User3Dao is the data access object for table user3.
|
||||
type User3Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User3Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User3Columns defines and stores column names for table user3.
|
||||
type User3Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user3Columns holds the columns for table user3.
|
||||
var user3Columns = User3Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser3Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser3Dao() *User3Dao {
|
||||
return &User3Dao{
|
||||
group: "sys",
|
||||
table: "user3",
|
||||
columns: user3Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User3Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User3Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User3Dao) Columns() User3Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User3Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User3Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User3Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/internal/user_4.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/internal/user_4.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User4Dao is the data access object for table user4.
|
||||
type User4Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User4Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User4Columns defines and stores column names for table user4.
|
||||
type User4Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user4Columns holds the columns for table user4.
|
||||
var user4Columns = User4Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser4Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser4Dao() *User4Dao {
|
||||
return &User4Dao{
|
||||
group: "book",
|
||||
table: "user4",
|
||||
columns: user4Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User4Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User4Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User4Dao) Columns() User4Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User4Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User4Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User4Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
27
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/user_3.go
vendored
Normal file
27
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/user_3.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser3Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser3Dao = *internal.User3Dao
|
||||
|
||||
// user3Dao is the data access object for table user3.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user3Dao struct {
|
||||
internalUser3Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User3 is globally public accessible object for table user3 operations.
|
||||
User3 = user3Dao{
|
||||
internal.NewUser3Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
27
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/user_4.go
vendored
Normal file
27
server/internal/library/hggen/internal/cmd/testdata/issue/2572/dao/user_4.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser4Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser4Dao = *internal.User4Dao
|
||||
|
||||
// user4Dao is the data access object for table user4.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user4Dao struct {
|
||||
internalUser4Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User4 is globally public accessible object for table user4 operations.
|
||||
User4 = user4Dao{
|
||||
internal.NewUser4Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
22
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/do/user_3.go
vendored
Normal file
22
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/do/user_3.go
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User1 is the golang structure of table user1 for DAO operations like Where/Data.
|
||||
type User1 struct {
|
||||
g.Meta `orm:"table:user1, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
22
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/do/user_4.go
vendored
Normal file
22
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/do/user_4.go
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User2 is the golang structure of table user2 for DAO operations like Where/Data.
|
||||
type User2 struct {
|
||||
g.Meta `orm:"table:user2, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/entity/user_3.go
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/entity/user_3.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User1 is the golang structure for table user1.
|
||||
type User1 struct {
|
||||
Id uint `json:"ID" description:"User ID"`
|
||||
Passport string `json:"PASSPORT" description:"User Passport"`
|
||||
Password string `json:"PASSWORD" description:"User Password"`
|
||||
Nickname string `json:"NICKNAME" description:"User Nickname"`
|
||||
Score float64 `json:"SCORE" description:"Total score amount."`
|
||||
CreateAt *gtime.Time `json:"CREATE_AT" description:"Created Time"`
|
||||
UpdateAt *gtime.Time `json:"UPDATE_AT" description:"Updated Time"`
|
||||
}
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/entity/user_4.go
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2572/model/entity/user_4.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User2 is the golang structure for table user2.
|
||||
type User2 struct {
|
||||
Id uint `json:"ID" description:"User ID"`
|
||||
Passport string `json:"PASSPORT" description:"User Passport"`
|
||||
Password string `json:"PASSWORD" description:"User Password"`
|
||||
Nickname string `json:"NICKNAME" description:"User Nickname"`
|
||||
Score float64 `json:"SCORE" description:"Total score amount."`
|
||||
CreateAt *gtime.Time `json:"CREATE_AT" description:"Created Time"`
|
||||
UpdateAt *gtime.Time `json:"UPDATE_AT" description:"Updated Time"`
|
||||
}
|
10
server/internal/library/hggen/internal/cmd/testdata/issue/2572/sql1.sql
vendored
Normal file
10
server/internal/library/hggen/internal/cmd/testdata/issue/2572/sql1.sql
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `user1` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`passport` varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
`password` varchar(45) NOT NULL COMMENT 'User Password',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',
|
||||
`create_at` datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
`update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
10
server/internal/library/hggen/internal/cmd/testdata/issue/2572/sql2.sql
vendored
Normal file
10
server/internal/library/hggen/internal/cmd/testdata/issue/2572/sql2.sql
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `user2` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`passport` varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
`password` varchar(45) NOT NULL COMMENT 'User Password',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',
|
||||
`create_at` datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
`update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/config.yaml
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/config.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "user1"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
group: "sys"
|
||||
clear: true
|
||||
overwriteDao: false
|
||||
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables: "user2"
|
||||
descriptionTag: true
|
||||
noModelComment: true
|
||||
group: "book"
|
||||
clear: true
|
||||
overwriteDao: true
|
||||
|
||||
|
||||
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_1.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_1.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User1Dao is the data access object for table user1.
|
||||
type User1Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User1Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User1Columns defines and stores column names for table user1.
|
||||
type User1Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user1Columns holds the columns for table user1.
|
||||
var user1Columns = User1Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser1Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser1Dao() *User1Dao {
|
||||
return &User1Dao{
|
||||
group: "sys",
|
||||
table: "user1",
|
||||
columns: user1Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User1Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User1Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User1Dao) Columns() User1Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User1Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User1Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User1Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_2.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_2.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User2Dao is the data access object for table user2.
|
||||
type User2Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User2Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User2Columns defines and stores column names for table user2.
|
||||
type User2Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user2Columns holds the columns for table user2.
|
||||
var user2Columns = User2Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser2Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser2Dao() *User2Dao {
|
||||
return &User2Dao{
|
||||
group: "sys",
|
||||
table: "user2",
|
||||
columns: user2Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User2Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User2Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User2Dao) Columns() User2Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User2Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User2Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User2Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_3.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_3.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User3Dao is the data access object for table user3.
|
||||
type User3Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User3Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User3Columns defines and stores column names for table user3.
|
||||
type User3Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user3Columns holds the columns for table user3.
|
||||
var user3Columns = User3Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser3Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser3Dao() *User3Dao {
|
||||
return &User3Dao{
|
||||
group: "sys",
|
||||
table: "user3",
|
||||
columns: user3Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User3Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User3Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User3Dao) Columns() User3Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User3Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User3Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User3Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_4.go
vendored
Normal file
85
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/internal/user_4.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
// User4Dao is the data access object for table user4.
|
||||
type User4Dao struct {
|
||||
table string // table is the underlying table name of the DAO.
|
||||
group string // group is the database configuration group name of current DAO.
|
||||
columns User4Columns // columns contains all the column names of Table for convenient usage.
|
||||
}
|
||||
|
||||
// User4Columns defines and stores column names for table user4.
|
||||
type User4Columns struct {
|
||||
Id string // User ID
|
||||
Passport string // User Passport
|
||||
Password string // User Password
|
||||
Nickname string // User Nickname
|
||||
Score string // Total score amount.
|
||||
CreateAt string // Created Time
|
||||
UpdateAt string // Updated Time
|
||||
}
|
||||
|
||||
// user4Columns holds the columns for table user4.
|
||||
var user4Columns = User4Columns{
|
||||
Id: "id",
|
||||
Passport: "passport",
|
||||
Password: "password",
|
||||
Nickname: "nickname",
|
||||
Score: "score",
|
||||
CreateAt: "create_at",
|
||||
UpdateAt: "update_at",
|
||||
}
|
||||
|
||||
// NewUser4Dao creates and returns a new DAO object for table data access.
|
||||
func NewUser4Dao() *User4Dao {
|
||||
return &User4Dao{
|
||||
group: "book",
|
||||
table: "user4",
|
||||
columns: user4Columns,
|
||||
}
|
||||
}
|
||||
|
||||
// DB retrieves and returns the underlying raw database management object of current DAO.
|
||||
func (dao *User4Dao) DB() gdb.DB {
|
||||
return g.DB(dao.group)
|
||||
}
|
||||
|
||||
// Table returns the table name of current dao.
|
||||
func (dao *User4Dao) Table() string {
|
||||
return dao.table
|
||||
}
|
||||
|
||||
// Columns returns all column names of current dao.
|
||||
func (dao *User4Dao) Columns() User4Columns {
|
||||
return dao.columns
|
||||
}
|
||||
|
||||
// Group returns the configuration group name of database of current dao.
|
||||
func (dao *User4Dao) Group() string {
|
||||
return dao.group
|
||||
}
|
||||
|
||||
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
|
||||
func (dao *User4Dao) Ctx(ctx context.Context) *gdb.Model {
|
||||
return dao.DB().Model(dao.table).Safe().Ctx(ctx)
|
||||
}
|
||||
|
||||
// Transaction wraps the transaction logic using function f.
|
||||
// It rollbacks the transaction and returns the error from function f if it returns non-nil error.
|
||||
// It commits the transaction and returns nil if function f returns nil.
|
||||
//
|
||||
// Note that, you should not Commit or Rollback the transaction in function f
|
||||
// as it is automatically handled by this function.
|
||||
func (dao *User4Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
|
||||
return dao.Ctx(ctx).Transaction(ctx, f)
|
||||
}
|
29
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_1.go
vendored
Normal file
29
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_1.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
// I am not overwritten.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser1Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser1Dao = *internal.User1Dao
|
||||
|
||||
// user1Dao is the data access object for table user1.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user1Dao struct {
|
||||
internalUser1Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User1 is globally public accessible object for table user1 operations.
|
||||
User1 = user1Dao{
|
||||
internal.NewUser1Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
29
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_2.go
vendored
Normal file
29
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_2.go
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
// I am not overwritten.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser2Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser2Dao = *internal.User2Dao
|
||||
|
||||
// user2Dao is the data access object for table user2.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user2Dao struct {
|
||||
internalUser2Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User2 is globally public accessible object for table user2 operations.
|
||||
User2 = user2Dao{
|
||||
internal.NewUser2Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
27
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_3.go
vendored
Normal file
27
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_3.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser3Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser3Dao = *internal.User3Dao
|
||||
|
||||
// user3Dao is the data access object for table user3.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user3Dao struct {
|
||||
internalUser3Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User3 is globally public accessible object for table user3 operations.
|
||||
User3 = user3Dao{
|
||||
internal.NewUser3Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
27
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_4.go
vendored
Normal file
27
server/internal/library/hggen/internal/cmd/testdata/issue/2616/dao/user_4.go
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"/internal"
|
||||
)
|
||||
|
||||
// internalUser4Dao is internal type for wrapping internal DAO implements.
|
||||
type internalUser4Dao = *internal.User4Dao
|
||||
|
||||
// user4Dao is the data access object for table user4.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type user4Dao struct {
|
||||
internalUser4Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// User4 is globally public accessible object for table user4 operations.
|
||||
User4 = user4Dao{
|
||||
internal.NewUser4Dao(),
|
||||
}
|
||||
)
|
||||
|
||||
// Fill with you ideas below.
|
22
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/do/user_3.go
vendored
Normal file
22
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/do/user_3.go
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User1 is the golang structure of table user1 for DAO operations like Where/Data.
|
||||
type User1 struct {
|
||||
g.Meta `orm:"table:user1, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
22
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/do/user_4.go
vendored
Normal file
22
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/do/user_4.go
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package do
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User2 is the golang structure of table user2 for DAO operations like Where/Data.
|
||||
type User2 struct {
|
||||
g.Meta `orm:"table:user2, do:true"`
|
||||
Id interface{} // User ID
|
||||
Passport interface{} // User Passport
|
||||
Password interface{} // User Password
|
||||
Nickname interface{} // User Nickname
|
||||
Score interface{} // Total score amount.
|
||||
CreateAt *gtime.Time // Created Time
|
||||
UpdateAt *gtime.Time // Updated Time
|
||||
}
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/entity/user_3.go
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/entity/user_3.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User1 is the golang structure for table user1.
|
||||
type User1 struct {
|
||||
Id uint `json:"ID" description:"User ID"`
|
||||
Passport string `json:"PASSPORT" description:"User Passport"`
|
||||
Password string `json:"PASSWORD" description:"User Password"`
|
||||
Nickname string `json:"NICKNAME" description:"User Nickname"`
|
||||
Score float64 `json:"SCORE" description:"Total score amount."`
|
||||
CreateAt *gtime.Time `json:"CREATE_AT" description:"Created Time"`
|
||||
UpdateAt *gtime.Time `json:"UPDATE_AT" description:"Updated Time"`
|
||||
}
|
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/entity/user_4.go
vendored
Normal file
20
server/internal/library/hggen/internal/cmd/testdata/issue/2616/model/entity/user_4.go
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// User2 is the golang structure for table user2.
|
||||
type User2 struct {
|
||||
Id uint `json:"ID" description:"User ID"`
|
||||
Passport string `json:"PASSPORT" description:"User Passport"`
|
||||
Password string `json:"PASSWORD" description:"User Password"`
|
||||
Nickname string `json:"NICKNAME" description:"User Nickname"`
|
||||
Score float64 `json:"SCORE" description:"Total score amount."`
|
||||
CreateAt *gtime.Time `json:"CREATE_AT" description:"Created Time"`
|
||||
UpdateAt *gtime.Time `json:"UPDATE_AT" description:"Updated Time"`
|
||||
}
|
10
server/internal/library/hggen/internal/cmd/testdata/issue/2616/sql1.sql
vendored
Normal file
10
server/internal/library/hggen/internal/cmd/testdata/issue/2616/sql1.sql
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `user1` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`passport` varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
`password` varchar(45) NOT NULL COMMENT 'User Password',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',
|
||||
`create_at` datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
`update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
10
server/internal/library/hggen/internal/cmd/testdata/issue/2616/sql2.sql
vendored
Normal file
10
server/internal/library/hggen/internal/cmd/testdata/issue/2616/sql2.sql
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
CREATE TABLE `user2` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`passport` varchar(45) NOT NULL COMMENT 'User Passport',
|
||||
`password` varchar(45) NOT NULL COMMENT 'User Password',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`score` decimal(10,2) unsigned DEFAULT NULL COMMENT 'Total score amount.',
|
||||
`create_at` datetime DEFAULT NULL COMMENT 'Created Time',
|
||||
`update_at` datetime DEFAULT NULL COMMENT 'Updated Time',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
18
server/internal/library/hggen/internal/cmd/testdata/issue/2746/issue_2746.go
vendored
Normal file
18
server/internal/library/hggen/internal/cmd/testdata/issue/2746/issue_2746.go
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
)
|
||||
|
||||
// Issue2746 is the golang structure for table issue2746.
|
||||
type Issue2746 struct {
|
||||
Id uint `json:"ID" ` // User ID
|
||||
Nickname string `json:"NICKNAME" ` // User Nickname
|
||||
Tag *gjson.Json `json:"TAG" ` //
|
||||
Info string `json:"INFO" ` //
|
||||
Tag2 *gjson.Json `json:"TAG_2" ` // Tag2
|
||||
}
|
9
server/internal/library/hggen/internal/cmd/testdata/issue/2746/sql.sql
vendored
Normal file
9
server/internal/library/hggen/internal/cmd/testdata/issue/2746/sql.sql
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE %s (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'User ID',
|
||||
`nickname` varchar(45) NOT NULL COMMENT 'User Nickname',
|
||||
`tag` json NOT NULL,
|
||||
`info` longtext DEFAULT NULL,
|
||||
`tag2` json COMMENT 'Tag2',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
@@ -9,6 +9,7 @@ package utils
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/tools/imports"
|
||||
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
|
@@ -7,6 +7,7 @@ package views
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
@@ -235,6 +236,18 @@ func (l *gCurd) DoBuild(ctx context.Context, in *CurdBuildInput) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
db, err := g.DB().Open(ParseDBConfigNodeLink(&gdb.ConfigNode{Link: in.PreviewIn.DaoConfig.Link}))
|
||||
if err != nil {
|
||||
err = gerror.Newf("连接数据库失败,请检查配置文件[server/hack/config.yaml]数据库配置是否正确!err:%v", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
if err = db.Ping(); err != nil {
|
||||
err = gerror.Newf("数据库访问异常,请检查配置文件[server/hack/config.yaml]数据库配置是否正确!err:%v", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 前置操作
|
||||
if len(in.BeforeEvent) > 0 {
|
||||
for name, f := range in.BeforeEvent {
|
||||
|
@@ -8,9 +8,11 @@ package views
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/utility/convert"
|
||||
)
|
||||
@@ -64,36 +66,66 @@ func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreview
|
||||
}
|
||||
|
||||
var (
|
||||
options = make(g.Map)
|
||||
dictTypeIds []int64
|
||||
dictTypeList []*DictType
|
||||
options = make(g.Map)
|
||||
dictTypeIds []int64
|
||||
dictTypeList []*DictType
|
||||
builtinDictTypeIds []int64
|
||||
builtinDictTypeList []*DictType
|
||||
)
|
||||
|
||||
for _, field := range in.masterFields {
|
||||
if field.DictType > 0 {
|
||||
dictTypeIds = append(dictTypeIds, field.DictType)
|
||||
}
|
||||
|
||||
if field.DictType < 0 {
|
||||
builtinDictTypeIds = append(builtinDictTypeIds, field.DictType)
|
||||
}
|
||||
}
|
||||
|
||||
dictTypeIds = convert.UniqueSlice(dictTypeIds)
|
||||
if len(dictTypeIds) == 0 {
|
||||
builtinDictTypeIds = convert.UniqueSlice(builtinDictTypeIds)
|
||||
|
||||
if len(dictTypeIds) == 0 && len(builtinDictTypeIds) == 0 {
|
||||
options["has"] = false
|
||||
return options, nil
|
||||
}
|
||||
|
||||
err := g.Model("sys_dict_type").Ctx(ctx).
|
||||
Fields("id", "type").
|
||||
WhereIn("id", dictTypeIds).
|
||||
Scan(&dictTypeList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(dictTypeIds) > 0 {
|
||||
err := g.Model("sys_dict_type").Ctx(ctx).
|
||||
Fields("id", "type").
|
||||
WhereIn("id", dictTypeIds).
|
||||
Scan(&dictTypeList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(dictTypeList) == 0 {
|
||||
if len(builtinDictTypeIds) > 0 {
|
||||
for _, id := range builtinDictTypeIds {
|
||||
opts, err := dict.GetOptionsById(ctx, id)
|
||||
if err != nil && !errors.Is(err, dict.NotExistKeyError) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(opts) > 0 {
|
||||
row := new(DictType)
|
||||
row.Id = id
|
||||
row.Type = opts[0].Type
|
||||
builtinDictTypeList = append(builtinDictTypeList, row)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(dictTypeList) == 0 && len(builtinDictTypeList) == 0 {
|
||||
options["has"] = false
|
||||
return options, nil
|
||||
}
|
||||
|
||||
if len(builtinDictTypeList) > 0 {
|
||||
dictTypeList = append(dictTypeList, builtinDictTypeList...)
|
||||
}
|
||||
|
||||
options["has"] = true
|
||||
|
||||
var (
|
||||
@@ -109,7 +141,7 @@ func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreview
|
||||
for _, v := range dictTypeList {
|
||||
// 字段映射字典
|
||||
for _, field := range in.masterFields {
|
||||
if field.DictType > 0 && v.Id == field.DictType {
|
||||
if field.DictType != 0 && v.Id == field.DictType {
|
||||
in.options.dictMap[field.TsName] = v.Type
|
||||
switchLoadOptions = fmt.Sprintf("%s case '%s':\n item.componentProps.options = options.value.%s;\n break;\n", switchLoadOptions, field.TsName, v.Type)
|
||||
}
|
||||
@@ -129,7 +161,6 @@ func (l *gCurd) generateWebModelDictOptions(ctx context.Context, in *CurdPreview
|
||||
options["interface"] = interfaceOptionsBuffer.String()
|
||||
options["const"] = constOptionsBuffer.String()
|
||||
options["load"] = loadOptionsBuffer.String()
|
||||
|
||||
return options, nil
|
||||
}
|
||||
|
||||
|
@@ -7,11 +7,13 @@ package views
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
@@ -175,3 +177,46 @@ func IsIndexPK(index string) bool {
|
||||
func IsIndexUNI(index string) bool {
|
||||
return gstr.ToUpper(index) == gstr.ToUpper(consts.GenCodesIndexUNI)
|
||||
}
|
||||
|
||||
// ParseDBConfigNodeLink 解析数据库连接配置
|
||||
func ParseDBConfigNodeLink(node *gdb.ConfigNode) *gdb.ConfigNode {
|
||||
const linkPattern = `(\w+):([\w\-\$]*):(.*?)@(\w+?)\((.+?)\)/{0,1}([^\?]*)\?{0,1}(.*)`
|
||||
const defaultCharset = `utf8`
|
||||
const defaultProtocol = `tcp`
|
||||
|
||||
var match []string
|
||||
if node.Link != "" {
|
||||
match, _ = gregex.MatchString(linkPattern, node.Link)
|
||||
if len(match) > 5 {
|
||||
node.Type = match[1]
|
||||
node.User = match[2]
|
||||
node.Pass = match[3]
|
||||
node.Protocol = match[4]
|
||||
array := gstr.Split(match[5], ":")
|
||||
if len(array) == 2 && node.Protocol != "file" {
|
||||
node.Host = array[0]
|
||||
node.Port = array[1]
|
||||
node.Name = match[6]
|
||||
} else {
|
||||
node.Name = match[5]
|
||||
}
|
||||
if len(match) > 6 && match[7] != "" {
|
||||
node.Extra = match[7]
|
||||
}
|
||||
node.Link = ""
|
||||
}
|
||||
}
|
||||
if node.Extra != "" {
|
||||
if m, _ := gstr.Parse(node.Extra); len(m) > 0 {
|
||||
_ = gconv.Struct(m, &node)
|
||||
}
|
||||
}
|
||||
// Default value checks.
|
||||
if node.Charset == "" {
|
||||
node.Charset = defaultCharset
|
||||
}
|
||||
if node.Protocol == "" {
|
||||
node.Protocol = defaultProtocol
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ import (
|
||||
|
||||
const (
|
||||
whoisApi = "https://whois.pconline.com.cn/ipJson.jsp?json=true&ip="
|
||||
dyndns = "http://members.3322.org/dyndns/getip"
|
||||
dyndns = "http://members.3322.org/dyndns/getip" // 备用:"https://ifconfig.co/ip"
|
||||
)
|
||||
|
||||
type IpLocationData struct {
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package tcp_test
|
||||
// @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 tcp_test
|
||||
|
||||
import (
|
||||
|
@@ -5,13 +5,65 @@
|
||||
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
|
||||
package storager
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"hotgo/internal/model/entity"
|
||||
)
|
||||
|
||||
// FileMeta 文件元数据
|
||||
type FileMeta struct {
|
||||
Filename string // 文件名称
|
||||
Size int64 // 文件大小
|
||||
Kind string // 文件上传类型
|
||||
MimeType string // 文件扩展类型
|
||||
NaiveType string // NaiveUI类型
|
||||
Ext string // 文件扩展名
|
||||
Md5 string // 文件hash
|
||||
Filename string `json:"filename"` // 文件名称
|
||||
Size int64 `json:"size"` // 文件大小
|
||||
Kind string `json:"kind"` // 文件上传类型
|
||||
MimeType string `json:"mimeType"` // 文件扩展类型
|
||||
NaiveType string `json:"naiveType"` // NaiveUI类型
|
||||
Ext string `json:"ext"` // 文件扩展名
|
||||
Md5 string `json:"md5"` // 文件hash
|
||||
}
|
||||
|
||||
// MultipartProgress 分片进度
|
||||
type MultipartProgress struct {
|
||||
UploadId string `json:"uploadId"` // 上传事件ID
|
||||
ThirdUploadId string `json:"thirdUploadId"` // 第三方上传事件ID
|
||||
Meta *FileMeta `json:"meta"` // 文件元数据
|
||||
ShardCount int `json:"shardCount"` // 分片数量
|
||||
UploadedIndex []int `json:"uploadedIndex"` // 已上传的分片索引
|
||||
CreatedAt *gtime.Time `json:"createdAt"` // 创建时间
|
||||
}
|
||||
|
||||
// CheckMultipartParams 检查文件分片
|
||||
type CheckMultipartParams struct {
|
||||
UploadType string `json:"uploadType" dc:"文件类型"`
|
||||
FileName string `json:"fileName" dc:"文件名称"`
|
||||
Size int64 `json:"size" dc:"文件大小"`
|
||||
Md5 string `json:"md5" dc:"文件md5值"`
|
||||
ShardCount int `json:"shardCount" dc:"分片数量"`
|
||||
meta *FileMeta
|
||||
}
|
||||
|
||||
type CheckMultipartModel struct {
|
||||
UploadId string `json:"uploadId" dc:"上传事件ID"`
|
||||
Attachment *entity.SysAttachment `json:"attachment" dc:"附件"`
|
||||
WaitUploadIndex []int `json:"waitUploadIndex" dc:"等待上传的分片索引"`
|
||||
Progress float64 `json:"progress" dc:"上传进度"`
|
||||
SizeFormat string `json:"sizeFormat" dc:"文件大小"`
|
||||
}
|
||||
|
||||
// UploadPartParams 分片上传
|
||||
type UploadPartParams struct {
|
||||
UploadId string `json:"uploadId" dc:"上传事件ID"`
|
||||
UploadType string `json:"uploadType" dc:"文件类型"`
|
||||
FileName string `json:"fileName" dc:"文件名称"`
|
||||
Size int64 `json:"size" dc:"文件大小"`
|
||||
Md5 string `json:"md5" dc:"文件md5值"`
|
||||
Index int `json:"index" dc:"分片索引"`
|
||||
File *ghttp.UploadFile `json:"file" type:"file" dc:"分片文件"`
|
||||
mp *MultipartProgress
|
||||
}
|
||||
|
||||
type UploadPartModel struct {
|
||||
Attachment *entity.SysAttachment `json:"attachment" dc:"附件"`
|
||||
Progress float64 `json:"progress" dc:"上传进度"`
|
||||
Finish bool `json:"finish" dc:"是否完成"`
|
||||
}
|
||||
|
@@ -14,18 +14,26 @@ import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/grand"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/cache"
|
||||
"hotgo/internal/library/contexts"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/utility/convert"
|
||||
"hotgo/utility/format"
|
||||
"hotgo/utility/url"
|
||||
"hotgo/utility/validate"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UploadDrive 存储驱动
|
||||
type UploadDrive interface {
|
||||
// Upload 上传
|
||||
Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath string, err error)
|
||||
// CreateMultipart 创建分片事件
|
||||
CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error)
|
||||
// UploadPart 上传分片
|
||||
UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error)
|
||||
}
|
||||
|
||||
// New 初始化存储驱动
|
||||
@@ -70,6 +78,31 @@ func DoUpload(ctx context.Context, typ string, file *ghttp.UploadFile) (result *
|
||||
return
|
||||
}
|
||||
|
||||
if err = ValidateFileMeta(typ, meta); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err = HasFile(ctx, meta.Md5)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 相同存储相同身份才复用
|
||||
if result != nil && result.Drive == config.Drive && result.MemberId == contexts.GetUserId(ctx) && result.AppId == contexts.GetModule(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
// 上传到驱动
|
||||
fullPath, err := New(config.Drive).Upload(ctx, file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 写入附件记录
|
||||
return write(ctx, meta, fullPath)
|
||||
}
|
||||
|
||||
// ValidateFileMeta 验证文件元数据
|
||||
func ValidateFileMeta(typ string, meta *FileMeta) (err error) {
|
||||
if _, err = GetFileMimeType(meta.Ext); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -123,24 +156,7 @@ func DoUpload(ctx context.Context, typ string, file *ghttp.UploadFile) (result *
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
result, err = hasFile(ctx, meta.Md5)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 相同存储相同身份才复用
|
||||
if result != nil && result.Drive == config.Drive && result.MemberId == contexts.GetUserId(ctx) && result.AppId == contexts.GetModule(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
// 上传到驱动
|
||||
fullPath, err := New(config.Drive).Upload(ctx, file)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 写入附件记录
|
||||
return write(ctx, meta, fullPath)
|
||||
return
|
||||
}
|
||||
|
||||
// LastUrl 根据驱动获取最终文件访问地址
|
||||
@@ -225,8 +241,8 @@ func write(ctx context.Context, meta *FileMeta, fullPath string) (models *entity
|
||||
return
|
||||
}
|
||||
|
||||
// hasFile 检查附件是否存在
|
||||
func hasFile(ctx context.Context, md5 string) (res *entity.SysAttachment, err error) {
|
||||
// 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
|
||||
@@ -238,10 +254,147 @@ func hasFile(ctx context.Context, md5 string) (res *entity.SysAttachment, err er
|
||||
|
||||
// 只有在上传时才会检查md5值,如果附件存在则更新最后上传时间,保证上传列表更新显示在最前面
|
||||
if res.Id > 0 {
|
||||
_, _ = GetModel(ctx).WherePri(res.Id).Data(g.Map{
|
||||
update := g.Map{
|
||||
"status": consts.StatusEnabled,
|
||||
"updated_at": gtime.Now(),
|
||||
}).Update()
|
||||
}
|
||||
_, _ = GetModel(ctx).WherePri(res.Id).Data(update).Update()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CheckMultipart 检查文件分片
|
||||
func CheckMultipart(ctx context.Context, in *CheckMultipartParams) (res *CheckMultipartModel, err error) {
|
||||
res = new(CheckMultipartModel)
|
||||
|
||||
meta := new(FileMeta)
|
||||
meta.Filename = in.FileName
|
||||
meta.Size = in.Size
|
||||
meta.Ext = Ext(in.FileName)
|
||||
meta.Kind = GetFileKind(meta.Ext)
|
||||
meta.MimeType, err = GetFileMimeType(meta.Ext)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 兼容naiveUI
|
||||
naiveType := "text/plain"
|
||||
if IsImgType(Ext(in.FileName)) {
|
||||
naiveType = ""
|
||||
}
|
||||
meta.NaiveType = naiveType
|
||||
meta.Md5 = in.Md5
|
||||
|
||||
if err = ValidateFileMeta(in.UploadType, meta); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := HasFile(ctx, in.Md5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 文件已存在,直接返回。相同存储相同身份才复用
|
||||
if result != nil && result.Drive == config.Drive && result.MemberId == contexts.GetUserId(ctx) && result.AppId == contexts.GetModule(ctx) {
|
||||
res.Attachment = result
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < in.ShardCount; i++ {
|
||||
res.WaitUploadIndex = append(res.WaitUploadIndex, i+1)
|
||||
}
|
||||
|
||||
in.meta = meta
|
||||
progress, err := GetOrCreateMultipartProgress(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(progress.UploadedIndex) > 0 {
|
||||
res.WaitUploadIndex = convert.DifferenceSlice(progress.UploadedIndex, res.WaitUploadIndex)
|
||||
}
|
||||
|
||||
if len(res.WaitUploadIndex) == 0 {
|
||||
res.WaitUploadIndex = make([]int, 0)
|
||||
}
|
||||
res.UploadId = progress.UploadId
|
||||
res.Progress = CalcUploadProgress(progress.UploadedIndex, progress.ShardCount)
|
||||
res.SizeFormat = format.FileSize(progress.Meta.Size)
|
||||
return
|
||||
}
|
||||
|
||||
// CalcUploadProgress 计算上传进度
|
||||
func CalcUploadProgress(uploadedIndex []int, shardCount int) float64 {
|
||||
return format.Round2Float64(float64(len(uploadedIndex)) / float64(shardCount) * 100)
|
||||
}
|
||||
|
||||
// GenUploadId 生成上传ID
|
||||
func GenUploadId(ctx context.Context, md5 string) string {
|
||||
return fmt.Sprintf("%v:%v:%v@%v", md5, contexts.GetUserId(ctx), contexts.GetModule(ctx), config.Drive)
|
||||
}
|
||||
|
||||
// GetOrCreateMultipartProgress 获取或创建分片上传事件进度
|
||||
func GetOrCreateMultipartProgress(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
uploadId := GenUploadId(ctx, in.Md5)
|
||||
res, err = GetMultipartProgress(ctx, uploadId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if res != nil {
|
||||
return res, nil
|
||||
}
|
||||
return New(config.Drive).CreateMultipart(ctx, in)
|
||||
}
|
||||
|
||||
// GetMultipartProgress 获取分片上传事件进度
|
||||
func GetMultipartProgress(ctx context.Context, uploadId string) (res *MultipartProgress, err error) {
|
||||
key := fmt.Sprintf("%v:%v", consts.CacheMultipartUpload, uploadId)
|
||||
get, err := cache.Instance().Get(ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = get.Scan(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipartProgress 创建分片上传事件进度
|
||||
func CreateMultipartProgress(ctx context.Context, in *MultipartProgress) (err error) {
|
||||
key := fmt.Sprintf("%v:%v", consts.CacheMultipartUpload, in.UploadId)
|
||||
return cache.Instance().Set(ctx, key, in, time.Hour*24*7)
|
||||
}
|
||||
|
||||
// UpdateMultipartProgress 更新分片上传事件进度
|
||||
func UpdateMultipartProgress(ctx context.Context, in *MultipartProgress) (err error) {
|
||||
key := fmt.Sprintf("%v:%v", consts.CacheMultipartUpload, in.UploadId)
|
||||
return cache.Instance().Set(ctx, key, in, time.Hour*24*7)
|
||||
}
|
||||
|
||||
// DelMultipartProgress 删除分片上传事件进度
|
||||
func DelMultipartProgress(ctx context.Context, in *MultipartProgress) (err error) {
|
||||
key := fmt.Sprintf("%v:%v", consts.CacheMultipartUpload, in.UploadId)
|
||||
_, err = cache.Instance().Remove(ctx, key)
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
in.mp, err = GetMultipartProgress(ctx, in.UploadId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if in.mp == nil {
|
||||
err = gerror.New("分片事件不存在,请重新上传!")
|
||||
return
|
||||
}
|
||||
|
||||
if validate.InSlice(in.mp.UploadedIndex, in.Index) {
|
||||
err = gerror.New("该分片已上传过了")
|
||||
return
|
||||
}
|
||||
|
||||
res, err = New(config.Drive).UploadPart(ctx, in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -45,3 +45,15 @@ func (d *CosDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath
|
||||
_, err = client.Object.Put(ctx, fullPath, f2, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *CosDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *CosDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
@@ -10,7 +10,11 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -45,3 +49,102 @@ func (d *LocalDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPa
|
||||
fullPath = config.LocalPath + nowDate + "/" + fileName
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *LocalDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (mp *MultipartProgress, err error) {
|
||||
mp = new(MultipartProgress)
|
||||
mp.UploadId = GenUploadId(ctx, in.Md5)
|
||||
mp.Meta = in.meta
|
||||
mp.ShardCount = in.ShardCount
|
||||
mp.UploadedIndex = make([]int, 0)
|
||||
mp.CreatedAt = gtime.Now()
|
||||
if err = CreateMultipartProgress(ctx, mp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *LocalDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
sp := g.Cfg().MustGet(ctx, "server.serverRoot")
|
||||
if sp.IsEmpty() {
|
||||
err = gerror.New("本地上传驱动必须配置静态路径!")
|
||||
return
|
||||
}
|
||||
|
||||
spStr := strings.Trim(sp.String(), "/") + "/"
|
||||
|
||||
if config.LocalPath == "" {
|
||||
err = gerror.New("本地上传驱动必须配置本地存储路径!")
|
||||
return
|
||||
}
|
||||
|
||||
// 分片文件存放路径
|
||||
partFilePath := spStr + config.LocalPath + "tmp/" + in.Md5
|
||||
|
||||
// 写入文件
|
||||
in.File.Filename = gconv.String(in.Index)
|
||||
if _, err = in.File.Save(partFilePath, false); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 更新上传进度
|
||||
in.mp.UploadedIndex = append(in.mp.UploadedIndex, in.Index)
|
||||
if err = UpdateMultipartProgress(ctx, in.mp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = new(UploadPartModel)
|
||||
|
||||
// 已全部上传完毕
|
||||
if len(in.mp.UploadedIndex) == in.mp.ShardCount {
|
||||
// 删除进度统计
|
||||
if err = DelMultipartProgress(ctx, in.mp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 合并文件
|
||||
finalDirPath := GenFullPath(config.LocalPath, gfile.Ext(in.mp.Meta.Filename))
|
||||
if err = MergePartFile(partFilePath, spStr+finalDirPath); err != nil {
|
||||
err = gerror.Newf("合并分片文件出错:%v", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 删除临时分片
|
||||
if err = os.RemoveAll(partFilePath); err != nil {
|
||||
err = gerror.Newf("删除临时分片文件出错:%v", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 写入附件记录
|
||||
attachment, err := write(ctx, in.mp.Meta, finalDirPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.Finish = true
|
||||
res.Progress = 100
|
||||
res.Attachment = attachment
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// 计算上传进度
|
||||
res.Progress = CalcUploadProgress(in.mp.UploadedIndex, in.mp.ShardCount)
|
||||
return
|
||||
}
|
||||
|
||||
// MergePartFile 合并分片文件
|
||||
func MergePartFile(srcPath, dstPath string) (err error) {
|
||||
dir, err := os.ReadDir(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, file := range dir {
|
||||
filePath := filepath.Join(srcPath, file.Name())
|
||||
if err = gfile.PutBytesAppend(dstPath, gfile.GetBytes(filePath)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@@ -62,3 +62,15 @@ func (d *MinioDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPa
|
||||
_, err = client.PutObject(ctx, config.MinioBucket, fullPath, reader, file.Size, opts)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *MinioDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *MinioDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
@@ -45,3 +45,15 @@ func (d *OssDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPath
|
||||
err = bucket.PutObject(fullPath, f2)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *OssDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *OssDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
@@ -55,3 +55,15 @@ func (d *QiNiuDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullPa
|
||||
err = storage.NewFormUploader(&cfg).Put(ctx, &storage.PutRet{}, token, fullPath, f2, file.Size, &storage.PutExtra{})
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *QiNiuDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *QiNiuDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
@@ -48,3 +48,15 @@ func (d *UCloudDrive) Upload(ctx context.Context, file *ghttp.UploadFile) (fullP
|
||||
err = client.IOPut(f2, fullPath, "")
|
||||
return
|
||||
}
|
||||
|
||||
// CreateMultipart 创建分片事件
|
||||
func (d *UCloudDrive) CreateMultipart(ctx context.Context, in *CheckMultipartParams) (res *MultipartProgress, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (d *UCloudDrive) UploadPart(ctx context.Context, in *UploadPartParams) (res *UploadPartModel, err error) {
|
||||
err = gerror.New("当前驱动暂不支持分片上传!")
|
||||
return
|
||||
}
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package admin
|
||||
// @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 admin
|
||||
|
||||
import (
|
||||
|
@@ -11,7 +11,10 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/dao"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/library/hgorm"
|
||||
"hotgo/internal/model"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/adminin"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/service"
|
||||
@@ -25,6 +28,7 @@ func NewAdminPost() *sAdminPost {
|
||||
|
||||
func init() {
|
||||
service.RegisterAdminPost(NewAdminPost())
|
||||
dict.RegisterFunc("adminPostOption", "岗位选项", service.AdminPost().Option)
|
||||
}
|
||||
|
||||
// Delete 删除
|
||||
@@ -156,6 +160,24 @@ func (s *sAdminPost) List(ctx context.Context, in *adminin.PostListInp) (list []
|
||||
return
|
||||
}
|
||||
|
||||
// Option 岗位选项
|
||||
func (s *sAdminPost) Option(ctx context.Context) (opts []*model.Option, err error) {
|
||||
var list []*entity.AdminPost
|
||||
if err = dao.AdminPost.Ctx(ctx).OrderAsc(dao.AdminPost.Columns().Sort).Scan(&list); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(list) == 0 {
|
||||
opts = make([]*model.Option, 0)
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range list {
|
||||
opts = append(opts, dict.GenHashOption(v.Id, v.Name))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetMemberByStartName 获取指定用户的第一岗位
|
||||
func (s *sAdminPost) GetMemberByStartName(ctx context.Context, memberId int64) (name string, err error) {
|
||||
// 默认取第一岗位
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package admin
|
||||
// @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 admin
|
||||
|
||||
import (
|
||||
@@ -237,7 +242,7 @@ func (s *sAdminSite) handleLogin(ctx context.Context, mb *entity.AdminMember) (r
|
||||
}
|
||||
|
||||
var dept *entity.AdminDept
|
||||
if err = g.Model("admin_dept").Ctx(ctx).Fields("id,status").Where("id", mb.DeptId).Scan(&dept); err != nil || dept == nil {
|
||||
if err = dao.AdminDept.Ctx(ctx).Fields("id,status").Where("id", mb.DeptId).Scan(&dept); err != nil || dept == nil {
|
||||
err = gerror.Wrap(err, "获取部门信息失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
@@ -279,7 +284,7 @@ func (s *sAdminSite) handleLogin(ctx context.Context, mb *entity.AdminMember) (r
|
||||
// BindUserContext 绑定用户上下文
|
||||
func (s *sAdminSite) BindUserContext(ctx context.Context, claims *model.Identity) (err error) {
|
||||
var mb *entity.AdminMember
|
||||
if err = g.Model("admin_member").Ctx(ctx).Where("id", claims.Id).Scan(&mb); err != nil {
|
||||
if err = dao.AdminMember.Ctx(ctx).Where("id", claims.Id).Scan(&mb); err != nil {
|
||||
err = gerror.Wrap(err, "获取用户信息失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
@@ -295,7 +300,7 @@ func (s *sAdminSite) BindUserContext(ctx context.Context, claims *model.Identity
|
||||
}
|
||||
|
||||
var role *entity.AdminRole
|
||||
if err = g.Model("admin_role").Ctx(ctx).Fields("id,key,status").Where("id", mb.RoleId).Scan(&role); err != nil || role == nil {
|
||||
if err = dao.AdminRole.Ctx(ctx).Fields("id,key,status").Where("id", mb.RoleId).Scan(&role); err != nil || role == nil {
|
||||
err = gerror.Wrap(err, "获取角色信息失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
@@ -306,7 +311,7 @@ func (s *sAdminSite) BindUserContext(ctx context.Context, claims *model.Identity
|
||||
}
|
||||
|
||||
var dept *entity.AdminDept
|
||||
if err = g.Model("admin_dept").Ctx(ctx).Fields("id,status").Where("id", mb.DeptId).Scan(&dept); err != nil || dept == nil {
|
||||
if err = dao.AdminDept.Ctx(ctx).Fields("id,status").Where("id", mb.DeptId).Scan(&dept); err != nil || dept == nil {
|
||||
err = gerror.Wrap(err, "获取部门信息失败,请稍后重试!")
|
||||
return
|
||||
}
|
||||
|
@@ -38,3 +38,25 @@ func (s *sCommonUpload) UploadFile(ctx context.Context, uploadType string, file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CheckMultipart 检查文件分片
|
||||
func (s *sCommonUpload) CheckMultipart(ctx context.Context, in *sysin.CheckMultipartInp) (res *sysin.CheckMultipartModel, err error) {
|
||||
data, err := storager.CheckMultipart(ctx, in.CheckMultipartParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = new(sysin.CheckMultipartModel)
|
||||
res.CheckMultipartModel = data
|
||||
return
|
||||
}
|
||||
|
||||
// UploadPart 上传分片
|
||||
func (s *sCommonUpload) UploadPart(ctx context.Context, in *sysin.UploadPartInp) (res *sysin.UploadPartModel, err error) {
|
||||
data, err := storager.UploadPart(ctx, in.UploadPartParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = new(sysin.UploadPartModel)
|
||||
res.UploadPartModel = data
|
||||
return
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ func (s *sHook) accessLog(r *ghttp.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var ctx = contexts.Detach(r.Context())
|
||||
var ctx = r.Context()
|
||||
if contexts.Get(ctx) == nil {
|
||||
return
|
||||
}
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package hook
|
||||
// @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 hook
|
||||
|
||||
import (
|
||||
@@ -65,7 +70,7 @@ func (s *sHook) lastAdminActive(r *ghttp.Request) {
|
||||
}
|
||||
|
||||
var (
|
||||
ctx = contexts.Detach(r.Context())
|
||||
ctx = r.Context()
|
||||
member = contexts.GetUser(ctx)
|
||||
)
|
||||
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package middleware
|
||||
// @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 middleware
|
||||
|
||||
import (
|
||||
|
@@ -30,10 +30,11 @@ import (
|
||||
)
|
||||
|
||||
type sMiddleware struct {
|
||||
LoginUrl string // 登录路由地址
|
||||
DemoWhiteList g.Map // 演示模式放行的路由白名单
|
||||
FilterRoutes map[string]ghttp.RouterItem // 支持预处理的web路由
|
||||
routeMutex sync.Mutex
|
||||
LoginUrl string // 登录路由地址
|
||||
DemoWhiteList g.Map // 演示模式放行的路由白名单
|
||||
NotRecordRequest g.Map // 不记录请求数据的路由(当前请求数据过大时会影响响应效率,可以将路径放到该选项中改善)
|
||||
FilterRoutes map[string]ghttp.RouterItem // 支持预处理的web路由
|
||||
routeMutex sync.Mutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -48,6 +49,10 @@ func NewMiddleware() *sMiddleware {
|
||||
"/admin/site/mobileLogin": struct{}{}, // 手机号登录
|
||||
"/admin/genCodes/preview": struct{}{}, // 预览代码
|
||||
},
|
||||
NotRecordRequest: g.Map{
|
||||
"/admin/upload/file": struct{}{}, // 上传文件
|
||||
"/admin/upload/uploadPart": struct{}{}, // 上传分片
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,8 +68,11 @@ func (s *sMiddleware) Ctx(r *ghttp.Request) {
|
||||
r.SetCtx(ctx)
|
||||
}
|
||||
|
||||
data := g.Map{
|
||||
"request.body": gjson.New(r.GetBodyString()),
|
||||
data := make(g.Map)
|
||||
if _, ok := s.NotRecordRequest[r.URL.Path]; ok {
|
||||
data["request.body"] = gjson.New(nil)
|
||||
} else {
|
||||
data["request.body"] = gjson.New(r.GetBodyString())
|
||||
}
|
||||
|
||||
contexts.Init(r, &model.Context{
|
||||
@@ -75,6 +83,8 @@ func (s *sMiddleware) Ctx(r *ghttp.Request) {
|
||||
if len(r.Cookie.GetSessionId()) == 0 {
|
||||
r.Cookie.SetSessionId(gctx.CtxId(r.Context()))
|
||||
}
|
||||
|
||||
r.SetCtx(r.GetNeverDoneCtx())
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
@@ -98,7 +108,7 @@ func (s *sMiddleware) CORS(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
// DemoLimit 演示系統操作限制
|
||||
// DemoLimit 演示系统操作限制
|
||||
func (s *sMiddleware) DemoLimit(r *ghttp.Request) {
|
||||
isDemo := g.Cfg().MustGet(r.Context(), "hotgo.isDemo", false)
|
||||
if !isDemo.Bool() {
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package middleware
|
||||
// @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 middleware
|
||||
|
||||
import (
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package middleware
|
||||
// @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 middleware
|
||||
|
||||
import (
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package middleware
|
||||
// @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 middleware
|
||||
|
||||
import (
|
||||
@@ -36,9 +41,19 @@ func (s *sMiddleware) GetFilterRoutes(r *ghttp.Request) map[string]ghttp.RouterI
|
||||
return s.FilterRoutes
|
||||
}
|
||||
|
||||
// GenFilterRouteKey 生成路由唯一key
|
||||
func (s *sMiddleware) GenFilterRouteKey(router *ghttp.Router) string {
|
||||
return router.Method + " " + router.Uri
|
||||
// GenFilterRequestKey 根据请求生成唯一key
|
||||
func (s *sMiddleware) GenFilterRequestKey(r *ghttp.Request) string {
|
||||
return s.GenRouteKey(r.Method, r.Request.URL.Path)
|
||||
}
|
||||
|
||||
// GenFilterRouteKey 根据路由生成唯一key
|
||||
func (s *sMiddleware) GenFilterRouteKey(r *ghttp.Router) string {
|
||||
return s.GenRouteKey(r.Method, r.Uri)
|
||||
}
|
||||
|
||||
// GenRouteKey 生成唯一key
|
||||
func (s *sMiddleware) GenRouteKey(method, path string) string {
|
||||
return method + " " + path
|
||||
}
|
||||
|
||||
// PreFilter 请求输入预处理
|
||||
|
@@ -22,6 +22,16 @@ import (
|
||||
func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
|
||||
r.Middleware.Next()
|
||||
|
||||
// 错误状态码接管
|
||||
switch r.Response.Status {
|
||||
case 403:
|
||||
r.Response.Writeln("403 - 网站拒绝显示此网页")
|
||||
return
|
||||
case 404:
|
||||
r.Response.Writeln("404 - 你似乎来到了没有知识存在的荒原…")
|
||||
return
|
||||
}
|
||||
|
||||
contentType := getContentType(r)
|
||||
// 已存在响应
|
||||
if contentType != consts.HTTPContentTypeStream && r.Response.BufferLength() > 0 && contexts.Get(r.Context()).Response != nil {
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package pay
|
||||
// @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 pay
|
||||
|
||||
// 订单创建
|
||||
|
@@ -1,3 +1,8 @@
|
||||
// Package pay
|
||||
// @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 pay
|
||||
|
||||
// 异步通知
|
||||
@@ -15,8 +20,16 @@ import (
|
||||
"hotgo/internal/library/payment"
|
||||
"hotgo/internal/model/entity"
|
||||
"hotgo/internal/model/input/payin"
|
||||
"hotgo/internal/service"
|
||||
)
|
||||
|
||||
// RegisterNotifyCall 注册支付成功回调方法
|
||||
func (s *sPay) RegisterNotifyCall() {
|
||||
payment.RegisterNotifyCallMap(map[string]payment.NotifyCallFunc{
|
||||
consts.OrderGroupAdminOrder: service.AdminOrder().PayNotify, // 后台充值订单
|
||||
})
|
||||
}
|
||||
|
||||
// Notify 异步通知
|
||||
func (s *sPay) Notify(ctx context.Context, in *payin.PayNotifyInp) (res *payin.PayNotifyModel, err error) {
|
||||
data, err := payment.New(in.PayType).Notify(ctx, payin.NotifyInp{})
|
||||
|
@@ -11,10 +11,10 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"hotgo/internal/consts"
|
||||
"hotgo/internal/library/addons"
|
||||
"hotgo/internal/library/dict"
|
||||
"hotgo/internal/model/input/form"
|
||||
"hotgo/internal/model/input/sysin"
|
||||
"hotgo/internal/service"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type sSysAddons struct{}
|
||||
@@ -83,8 +83,7 @@ func (s *sSysAddons) List(ctx context.Context, in *sysin.AddonsListInp) (list []
|
||||
row.Skeleton.Logo = consts.AddonsGroupIconMap[row.Skeleton.Group]
|
||||
}
|
||||
|
||||
row.GroupName = consts.AddonsGroupNameMap[row.Skeleton.Group]
|
||||
|
||||
row.GroupName = dict.GetOptionLabel(consts.AddonsGroupOptions, row.Skeleton.Group)
|
||||
list = append(list, row)
|
||||
i++
|
||||
}
|
||||
@@ -93,42 +92,23 @@ func (s *sSysAddons) List(ctx context.Context, in *sysin.AddonsListInp) (list []
|
||||
return
|
||||
}
|
||||
|
||||
// Selects 选项
|
||||
func (s *sSysAddons) Selects(ctx context.Context, in *sysin.AddonsSelectsInp) (res *sysin.AddonsSelectsModel, err error) {
|
||||
res = new(sysin.AddonsSelectsModel)
|
||||
for k, v := range consts.AddonsGroupNameMap {
|
||||
res.GroupType = append(res.GroupType, &form.Select{
|
||||
Value: k,
|
||||
Name: v,
|
||||
Label: v,
|
||||
})
|
||||
}
|
||||
sort.Sort(res.GroupType)
|
||||
|
||||
for k, v := range consts.AddonsInstallStatusNameMap {
|
||||
res.Status = append(res.Status, &form.Select{
|
||||
Value: k,
|
||||
Name: v,
|
||||
Label: v,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Sort(res.Status)
|
||||
return
|
||||
}
|
||||
|
||||
// Build 提交生成
|
||||
func (s *sSysAddons) Build(ctx context.Context, in *sysin.AddonsBuildInp) (err error) {
|
||||
genConfig, err := service.SysConfig().GetLoadGenerate(ctx)
|
||||
config, err := service.SysConfig().GetLoadGenerate(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if genConfig == nil || genConfig.Addon == nil {
|
||||
if config == nil || config.Addon == nil {
|
||||
err = gerror.New("没有找到有效的生成或插件配置,请检查配置文件是否正常")
|
||||
return
|
||||
}
|
||||
return addons.Build(ctx, in.Skeleton, genConfig.Addon)
|
||||
|
||||
option := new(addons.BuildOption)
|
||||
option.Config = config.Addon
|
||||
option.Skeleton = in.Skeleton
|
||||
option.Extend = in.Extend
|
||||
return addons.Build(ctx, option)
|
||||
}
|
||||
|
||||
// Install 安装模块
|
||||
|
@@ -64,7 +64,7 @@ func (s *sSysBlacklist) Edit(ctx context.Context, in *sysin.BlacklistEditInp) (e
|
||||
return
|
||||
}
|
||||
|
||||
// Status 更新部门状态
|
||||
// Status 更新状态
|
||||
func (s *sSysBlacklist) Status(ctx context.Context, in *sysin.BlacklistStatusInp) (err error) {
|
||||
defer s.VariableLoad(ctx, err)
|
||||
// 修改
|
||||
@@ -72,7 +72,7 @@ func (s *sSysBlacklist) Status(ctx context.Context, in *sysin.BlacklistStatusInp
|
||||
return
|
||||
}
|
||||
|
||||
// View 获取指定字典类型信息
|
||||
// View 获取指定信息
|
||||
func (s *sSysBlacklist) View(ctx context.Context, in *sysin.BlacklistViewInp) (res *sysin.BlacklistViewModel, err error) {
|
||||
err = dao.SysBlacklist.Ctx(ctx).Where("id", in.Id).Scan(&res)
|
||||
return
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user