mirror of
				https://github.com/bufanyun/hotgo.git
				synced 2025-11-04 16:23:43 +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:
		
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 平台简介
 | 
			
		||||
* 基于全新Go Frame 2+Vue3+Naive UI+uniapp开发的全栖框架,为二次开发而生,适合中小型完整应用开发。
 | 
			
		||||
* 基于全新GoFrame2+Vue3+NaiveUI+uniapp开发的全栖框架,为二次开发而生,适合中小型完整应用开发。
 | 
			
		||||
* 前端采用Naive-Ui-Admin、Vue、Naive UI、uniapp。
 | 
			
		||||
 | 
			
		||||
## 演示地址
 | 
			
		||||
@@ -42,21 +42,21 @@
 | 
			
		||||
 | 
			
		||||
## 特征
 | 
			
		||||
* 高生产率:极强的可扩展性,应用化、模块化、插件化机制敏捷开发,几分钟即可搭建一个应用开发骨架。
 | 
			
		||||
* 多应用入口:多入口分为 Admin (后台)、Home (前台页面)、Api (对外通用接口)、Websocket (即时通讯接口),不同的业务,进入不同的应用入口。
 | 
			
		||||
* 多应用入口:多入口分为 Admin (后台)、Home (前台页面)、Api (对外通用接口)、WebSocket (即时通讯接口),不同的业务,进入不同的应用入口。
 | 
			
		||||
* 极致的插件化: 微核架构,功能隔离,高可定制性,可以渐进式开发,亦可以多人协同开发。支持一键创建插件模板、一键安装、更新、卸载插件、可以非常方便的将插件迁移到新项目中。
 | 
			
		||||
* 快速生成代码:无需编写代码,只需创建表进行简单配置就能生成一个完善的 CURD、树表等常用的开发代码,其中所需表单控件也是勾选即可直接生成。
 | 
			
		||||
* 认证机制:采用 JWT 的用户状态认证及 casbin 的权限认证
 | 
			
		||||
* 路由模式:得益于 goframe2.0 提供了规范化的路由注册方式,无需注解自动生成api文档
 | 
			
		||||
* 路由模式:得益于 GoFrame 提供了规范化的路由注册方式,无需注解自动生成api文档
 | 
			
		||||
* 模块化设计,面向接口开发
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 后台内置功能
 | 
			
		||||
## 内置功能
 | 
			
		||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
 | 
			
		||||
2. 部门管理:配置系统组织机构(公司、部门、岗位),树结构展现支持数据权限。
 | 
			
		||||
3. 岗位管理:配置系统用户所属担任职务。
 | 
			
		||||
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
 | 
			
		||||
5. 角色管理:角色菜单权限分配、设置角色按机构或按上下级关系进行数据范围权限划分。
 | 
			
		||||
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
 | 
			
		||||
6. 字典管理:对系统中经常使用的一些特定数据进行维护,支持枚举字典和自定义方法字典。
 | 
			
		||||
7. 配置管理:对系统动态配置常用参数。
 | 
			
		||||
8. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
 | 
			
		||||
9. 登录日志:系统登录日志记录查询包含登录异常。
 | 
			
		||||
@@ -68,10 +68,10 @@
 | 
			
		||||
15. 代码生成:支持自动化生成前后端代码。CURD关联表、树表、消息队列、定时任务一键生成等。
 | 
			
		||||
16. 插件应用:支持一键生成插件模板,每个插件之间开发隔离,拥有独立多应用入口、独立配置。完美支持多人协同开发、插件插拔不会对原系统产生影响等。
 | 
			
		||||
17. 服务监控:监视当前系统CPU、内存、磁盘、网络、堆栈等相关信息。
 | 
			
		||||
18. 附件管理:文件图片上传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储、minio等多种上传驱动,后台一键切换配置,并集成了文件选择器。
 | 
			
		||||
18. 附件管理:文件图片上传,大文件分片上传、断点续传,支持本地、阿里云oss、腾讯云cos、ucloud对象存储、七牛云对象存储、minio等多种上传驱动,后台一键切换配置,并集成了文件选择器。
 | 
			
		||||
19. TCP服务:基于gtcp的服务应用,支持长连接、断线重连、服务认证、路由分发、RPC消息、拦截器和数据绑定等。简化和规范了服务器开发流程。
 | 
			
		||||
20. 消息队列:同时兼容 kafka、redis、rocketmq、磁盘队列,一键配置切换到场景适用的MQ。
 | 
			
		||||
21. 通知公告:采用websocket实时推送在线用户最新通知、公告、私信消息。
 | 
			
		||||
21. 通知公告:采用WebSocket实时推送在线用户最新通知、公告、私信消息。
 | 
			
		||||
22. 地区编码:整合国内通用省市区编码,运用于项目于一身,支持动态省市区选项。
 | 
			
		||||
23. 常用工具:集成常用的工具包和命令行工具,可以快速开发自定义命令行,多种启动入口。
 | 
			
		||||
 | 
			
		||||
@@ -132,7 +132,7 @@
 | 
			
		||||
 | 
			
		||||
* 本项目包含的第三方源码和二进制文件之版权信息另行标注。
 | 
			
		||||
 | 
			
		||||
* 版权所有Copyright © 2020-2023 by Ms (https://github.com/bufanyun/hotgo)
 | 
			
		||||
* 版权所有Copyright © 2020-2024 by Ms (https://github.com/bufanyun/hotgo)
 | 
			
		||||
 | 
			
		||||
* All rights reserved。
 | 
			
		||||
 | 
			
		||||
@@ -154,7 +154,7 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
[MIT © HotGo-2023](./LICENSE)
 | 
			
		||||
[MIT © HotGo-2024](./LICENSE)
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
- [消息队列](sys-queue.md)
 | 
			
		||||
- [功能扩展库](sys-library.md)
 | 
			
		||||
- [工具方法](sys-utility.md)
 | 
			
		||||
- Websocket服务器
 | 
			
		||||
- [WebSocket服务器](sys-websocket-server.md)
 | 
			
		||||
- [TCP服务器](sys-tcp-server.md)
 | 
			
		||||
- [单元测试](sys-test.md)
 | 
			
		||||
 | 
			
		||||
@@ -40,8 +40,7 @@
 | 
			
		||||
 | 
			
		||||
### 前端开发
 | 
			
		||||
- [表单组件](web-form.md)
 | 
			
		||||
- Websocket客户端
 | 
			
		||||
- 工具库
 | 
			
		||||
- [WebSocket客户端](sys-websocket-client.md)
 | 
			
		||||
- [独立部署](web-deploy.md)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,8 +19,9 @@
 | 
			
		||||
 | 
			
		||||
1. /server/addons/hgexample/                   # 插件模块目录
 | 
			
		||||
2. /server/addons/modules/hgexample.go         # 隐式注册插件文件
 | 
			
		||||
3. /web/src/api/addons/hgexample               # webApi目录
 | 
			
		||||
4. /web/src/views/addons/hgexample             # web页面目录
 | 
			
		||||
3. /server/resource/addons/hgexample           # 静态资源和页面模板目录,属于扩展功能选项,勾选对应选项后才会生成
 | 
			
		||||
4. /web/src/api/addons/hgexample               # webApi目录
 | 
			
		||||
5. /web/src/views/addons/hgexample             # web页面目录
 | 
			
		||||
 | 
			
		||||
# 默认情况下没有为web页面生成菜单权限,因为在实际场景中插件不一定需要用到web页面,所以如有需要请手动到后台 权限管理 -> 菜单权限->自行添加菜单和配置权限
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -30,13 +30,13 @@ 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) // 卸载模块
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								docs/guide-zh-CN/images/sys-library-dict.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/guide-zh-CN/images/sys-library-dict.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 97 KiB  | 
@@ -26,6 +26,6 @@
 | 
			
		||||
> 需要本地具有 git node golang 环境
 | 
			
		||||
 | 
			
		||||
- node版本 >= 16.0.0
 | 
			
		||||
- golang版本 >= v1.19
 | 
			
		||||
- mysql 引擎需要是 innoDB
 | 
			
		||||
- golang版本 >= 1.19
 | 
			
		||||
- mysql版本 >= 5.7,引擎需要是 innoDB
 | 
			
		||||
- IDE推荐:Goland
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
 | 
			
		||||
- node版本 >= v16.0.0
 | 
			
		||||
- golang版本 >= v1.19
 | 
			
		||||
- goframe版本 >=v2.6.1
 | 
			
		||||
- goframe版本 >=v2.6.4
 | 
			
		||||
- mysql版本 >=5.7
 | 
			
		||||
 | 
			
		||||
> 必须先看[环境搭建文档](start-environment.md),如果安装遇到问题务必先查看[常见问题文档](start-issue.md)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,20 @@
 | 
			
		||||
 | 
			
		||||
> 如果升级(覆盖)代码后打开会出现 sql 报错, 请检查更新的数据库格式或自行调整
 | 
			
		||||
 | 
			
		||||
### v2.13.1
 | 
			
		||||
updated 2024.3.7
 | 
			
		||||
 | 
			
		||||
- 增加:增加内置数据字典类型:`枚举字典`和`自定义方法字典`,支持代码生成时关联选项使用
 | 
			
		||||
- 增加:增加大文件上传,支持分片上传、断点续传,存储驱动已适配`本地存储`
 | 
			
		||||
- 增加:插件模块增加停止服务回调接口,调整静态资源默认存放位置,创建插件选项增加可选扩展功能
 | 
			
		||||
- 增加:功能案例插件增加`30+`常用组件示例,增加`websocket`消息收发测试
 | 
			
		||||
- 增加:文档增`加功能扩展库`、`websocket服务器`、`websocket客户端`使用说明,当前版本文档已完善
 | 
			
		||||
- 修复:修复省市区无法添加地区问题
 | 
			
		||||
- 优化:gf版本升级到v2.6.4
 | 
			
		||||
- 优化:优化缓存组件依赖关系
 | 
			
		||||
- 优化:调整部分前端表格自适应宽度
 | 
			
		||||
- 优化:HTTP错误码接管统一改为由响应中间件处理
 | 
			
		||||
 | 
			
		||||
### v2.12.1
 | 
			
		||||
updated 2023.12.29
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -105,7 +105,7 @@ graph TD
 | 
			
		||||
#### 如何区分部门和下级用户?
 | 
			
		||||
 | 
			
		||||
- 在实际使用时,部门更多的是在公司或机构中使用,可以通过在 组织管理 -> 后台用户 ->为用户绑定部门
 | 
			
		||||
- 下级用户在代理商或分销系统中比较常见,后台用户由谁添加的,那么被添加的用户就是其下级用户。后续也将开放邀请码绑定下级功能。
 | 
			
		||||
- 下级用户在代理商或分销系统中比较常见,后台用户由谁添加的,那么被添加的用户就是其下级用户
 | 
			
		||||
 | 
			
		||||
#### 如何判断数据是谁的?
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
- 缓存驱动
 | 
			
		||||
- 请求上下文
 | 
			
		||||
- JWT
 | 
			
		||||
- 数据字典
 | 
			
		||||
- 地理定位(待写)
 | 
			
		||||
- 通知(待写)
 | 
			
		||||
 | 
			
		||||
@@ -151,6 +152,159 @@ func test(ctx context.Context) {
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 数据字典
 | 
			
		||||
 | 
			
		||||
- hotgo增加了对枚举字典和自定义方法字典的内置支持,从而在系统中经常使用的一些特定数据维护基础上做出了增强。
 | 
			
		||||
 | 
			
		||||
#### 字典数据选项
 | 
			
		||||
- 文件路径:server/internal/model/dict.go
 | 
			
		||||
```go
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
// Option 字典数据选项
 | 
			
		||||
type Option struct {
 | 
			
		||||
	Key       interface{} `json:"key"`
 | 
			
		||||
	Label     string      `json:"label"     description:"字典标签"`
 | 
			
		||||
	Value     interface{} `json:"value"     description:"字典键值"`
 | 
			
		||||
	ValueType string      `json:"valueType" description:"键值数据类型"`
 | 
			
		||||
	Type      string      `json:"type"      description:"字典类型"`
 | 
			
		||||
	ListClass string      `json:"listClass" description:"表格回显样式"`
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 枚举字典
 | 
			
		||||
- 适用于系统开发期间内置的枚举数据,这样即维护了枚举值,又关联了数据字典
 | 
			
		||||
 | 
			
		||||
##### 一个例子
 | 
			
		||||
- 定义枚举值和字典数据选项,并注册字典类型
 | 
			
		||||
- 文件路径:server/internal/consts/credit_log.go
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package consts
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"hotgo/internal/library/dict"
 | 
			
		||||
	"hotgo/internal/model"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	dict.RegisterEnums("creditType", "资金变动类型", CreditTypeOptions)
 | 
			
		||||
	dict.RegisterEnums("creditGroup", "资金变动分组", CreditGroupOptions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CreditTypeBalance  = "balance"  // 余额
 | 
			
		||||
	CreditTypeIntegral = "integral" // 积分
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CreditGroupDecr            = "decr"             // 扣款
 | 
			
		||||
	CreditGroupIncr            = "incr"             // 加款
 | 
			
		||||
	CreditGroupOpDecr          = "op_decr"          // 操作扣款
 | 
			
		||||
	CreditGroupOpIncr          = "op_incr"          // 操作加款
 | 
			
		||||
	CreditGroupBalanceRecharge = "balance_recharge" // 余额充值
 | 
			
		||||
	CreditGroupBalanceRefund   = "balance_refund"   // 余额退款
 | 
			
		||||
	CreditGroupApplyCash       = "apply_cash"       // 申请提现
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CreditTypeOptions 变动类型
 | 
			
		||||
var CreditTypeOptions = []*model.Option{
 | 
			
		||||
	dict.GenSuccessOption(CreditTypeBalance, "余额"),
 | 
			
		||||
	dict.GenInfoOption(CreditTypeIntegral, "积分"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreditGroupOptions 变动分组
 | 
			
		||||
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, "申请提现"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 自定义方法字典
 | 
			
		||||
- 适用于非固定选项,如数据是从某个表/文件读取或从第三方读取,数据需要进行转换时使用
 | 
			
		||||
 | 
			
		||||
##### 方法字典接口
 | 
			
		||||
- 文件路径:server/internal/consts/credit_log.go
 | 
			
		||||
```go
 | 
			
		||||
package dict
 | 
			
		||||
 | 
			
		||||
// FuncDict 方法字典,实现本接口即可使用内置方法字典
 | 
			
		||||
type FuncDict func(ctx context.Context) (res []*model.Option, err error)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
##### 一个例子
 | 
			
		||||
- 定义获取字典数据方法,并注册字典类型
 | 
			
		||||
- 文件路径:server/internal/logic/admin/post.go
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package admin
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/errors/gerror"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"hotgo/internal/consts"
 | 
			
		||||
	"hotgo/internal/dao"
 | 
			
		||||
	"hotgo/internal/library/dict"
 | 
			
		||||
	"hotgo/internal/model"
 | 
			
		||||
	"hotgo/internal/model/entity"
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type sAdminPost struct{}
 | 
			
		||||
 | 
			
		||||
func NewAdminPost() *sAdminPost {
 | 
			
		||||
    return &sAdminPost{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
    service.RegisterAdminPost(NewAdminPost())
 | 
			
		||||
    dict.RegisterFunc("adminPostOption", "岗位选项", service.AdminPost().Option)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 代码生成支持
 | 
			
		||||
- 内置的枚举字典和自定义方法字典在生成代码时可以直接进行选择,生成代码格式和系统字典管理写法一致
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### 内置字典和系统字典的区分
 | 
			
		||||
 | 
			
		||||
##### 主要区别
 | 
			
		||||
- 系统字典由表:`hg_sys_dict_type`和`hg_sys_dict_data`共同进行维护,使用时需通过后台到字典管理中进行添加
 | 
			
		||||
- 内置字典是系统开发期间在代码层面事先定义和注册好的数据选项
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
##### 数据格式区别
 | 
			
		||||
- 系统字典所有ID都是大于0的int64类型
 | 
			
		||||
- 内置字典ID都是小于0的int64类型。枚举字典以20000开头,如:-200001381053496;方法字典以30000开头,如:-30000892528327;开头以外数字是根据数据选项的`key`值进行哈希算法得出
 | 
			
		||||
 | 
			
		||||
### 地理定位
 | 
			
		||||
```go
 | 
			
		||||
// 待写
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ func main()  {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 注册支付回调
 | 
			
		||||
- 在文件`server/internal/global/pay.go` 加入你的业务订单分组回调方法,当订单支付成功验签通过后会自动进行回调,参考以下:
 | 
			
		||||
- 在文件`server/internal/logic/pay/notify.go` 加入你的业务订单分组回调方法,当订单支付成功验签通过后会自动进行回调,参考以下:
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package global
 | 
			
		||||
@@ -66,12 +66,13 @@ import (
 | 
			
		||||
	"hotgo/internal/service"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 注册支付成功回调方法
 | 
			
		||||
func payNotifyCall() {
 | 
			
		||||
	payment.RegisterNotifyCall(consts.OrderGroupAdminOrder, service.AdminOrder().PayNotify) // 后台充值订单
 | 
			
		||||
	// ...
 | 
			
		||||
// RegisterNotifyCall 注册支付成功回调方法
 | 
			
		||||
func (s *sPay) RegisterNotifyCall() {
 | 
			
		||||
	payment.RegisterNotifyCallMap(map[string]payment.NotifyCallFunc{
 | 
			
		||||
		consts.OrderGroupAdminOrder: service.AdminOrder().PayNotify, // 后台充值订单
 | 
			
		||||
		// ...
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 订单退款
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
- 服务认证
 | 
			
		||||
- 更多
 | 
			
		||||
 | 
			
		||||
> HotGo基于GF框架的TCP服务器组件,提供了一个简单而灵活的方式快速搭建基于TCP的服务应用。集成了许多常用功能,如长连接、服务认证、路由分发、RPC消息、拦截器和数据绑定等,大大简化和规范了服务器开发流程。
 | 
			
		||||
> HotGo基于GoFrame的TCP服务器组件,提供了一个简单而灵活的方式快速搭建基于TCP的服务应用。集成了许多常用功能,如长连接、服务认证、路由分发、RPC消息、拦截器和数据绑定等,大大简化和规范了服务器开发流程。
 | 
			
		||||
 | 
			
		||||
### 配置文件
 | 
			
		||||
- 配置文件:server/manifest/config/config.yaml
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
## WebHook
 | 
			
		||||
 | 
			
		||||
待写
 | 
			
		||||
请参考:https://goframe.org/pages/viewpage.action?pageId=1114387
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										210
									
								
								docs/guide-zh-CN/sys-websocket-client.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								docs/guide-zh-CN/sys-websocket-client.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
			
		||||
## WebSocket客户端
 | 
			
		||||
 | 
			
		||||
目录
 | 
			
		||||
 | 
			
		||||
- 全局消息监听
 | 
			
		||||
- 单页面消息监听
 | 
			
		||||
- 发送消息
 | 
			
		||||
 | 
			
		||||
> 基于WebSocket服务器,hotgo还对客户端的上做了一些封装,使其使用起来更加方便
 | 
			
		||||
- [WebSocket服务器](sys-websocket-server.md)
 | 
			
		||||
 | 
			
		||||
###  全局消息监听
 | 
			
		||||
- 所有全局的消息监听都在这里
 | 
			
		||||
- 文件路径:web/src/utils/websocket/registerMessage.ts
 | 
			
		||||
```ts
 | 
			
		||||
import { TABS_ROUTES } from '@/store/mutation-types';
 | 
			
		||||
import { SocketEnum } from '@/enums/socketEnum';
 | 
			
		||||
import { useUserStoreWidthOut } from '@/store/modules/user';
 | 
			
		||||
import { notificationStoreWidthOut } from '@/store/modules/notification';
 | 
			
		||||
import { addOnMessage, WebSocketMessage } from '@/utils/websocket/index';
 | 
			
		||||
 | 
			
		||||
// 注册全局消息监听
 | 
			
		||||
export function registerGlobalMessage() {
 | 
			
		||||
  // 心跳
 | 
			
		||||
  addOnMessage(SocketEnum.EventPing, function (_message: WebSocketMessage) {
 | 
			
		||||
    // console.log('ping..');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 强制退出
 | 
			
		||||
  addOnMessage(SocketEnum.EventKick, function (_message: WebSocketMessage) {
 | 
			
		||||
    const useUserStore = useUserStoreWidthOut();
 | 
			
		||||
    useUserStore.logout().then(() => {
 | 
			
		||||
      // 移除标签页
 | 
			
		||||
      localStorage.removeItem(TABS_ROUTES);
 | 
			
		||||
      location.reload();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 消息通知
 | 
			
		||||
  addOnMessage(SocketEnum.EventNotice, function (message: WebSocketMessage) {
 | 
			
		||||
    const notificationStore = notificationStoreWidthOut();
 | 
			
		||||
    notificationStore.triggerNewMessages(message.data);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // 更多全局消息处理都可以在这里注册
 | 
			
		||||
  // ...
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 单页面消息监听
 | 
			
		||||
- 当你只需要某个页面使用WebSocket,这将是一个不错的选择,下面是一个简单的演示例子
 | 
			
		||||
- 文件路径:web/src/views/addons/hgexample/portal/websocketTest.vue
 | 
			
		||||
```vue
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div class="n-layout-page-header">
 | 
			
		||||
      <n-card :bordered="false" title="测试websocket">
 | 
			
		||||
        尝试在下方输入框中输入任意文字消息内容,发送后websocket服务器收到会原样返回
 | 
			
		||||
      </n-card>
 | 
			
		||||
    </div>
 | 
			
		||||
    <n-card :bordered="false" class="proCard">
 | 
			
		||||
      <n-space vertical>
 | 
			
		||||
        <n-input-group style="width: 520px">
 | 
			
		||||
          <n-input
 | 
			
		||||
            @keyup.enter="sendMessage"
 | 
			
		||||
            :style="{ width: '78%' }"
 | 
			
		||||
            placeholder="请输入消息内容"
 | 
			
		||||
            :on-focus="onFocus"
 | 
			
		||||
            :on-blur="onBlur"
 | 
			
		||||
            v-model:value="inputMessage"
 | 
			
		||||
          />
 | 
			
		||||
          <n-button type="primary" @click="sendMessage"> 发送消息</n-button>
 | 
			
		||||
        </n-input-group>
 | 
			
		||||
 | 
			
		||||
        <div class="mt-5"></div>
 | 
			
		||||
 | 
			
		||||
        <n-timeline :icon-size="20">
 | 
			
		||||
          <n-timeline-item color="grey" content="输入中.." v-if="isInput">
 | 
			
		||||
            <template #icon>
 | 
			
		||||
              <n-icon>
 | 
			
		||||
                <MessageOutlined />
 | 
			
		||||
              </n-icon>
 | 
			
		||||
            </template>
 | 
			
		||||
          </n-timeline-item>
 | 
			
		||||
 | 
			
		||||
          <n-timeline-item
 | 
			
		||||
            v-for="item in messages"
 | 
			
		||||
            :key="item"
 | 
			
		||||
            :type="item.type == Enum.SendType ? 'success' : 'info'"
 | 
			
		||||
            :title="item.type == Enum.SendType ? '发送消息' : '收到消息'"
 | 
			
		||||
            :content="item.content"
 | 
			
		||||
            :time="item.time"
 | 
			
		||||
          >
 | 
			
		||||
            <template #icon>
 | 
			
		||||
              <n-icon>
 | 
			
		||||
                <SendOutlined v-if="item.type == Enum.SendType" />
 | 
			
		||||
                <SoundOutlined v-if="item.type == Enum.ReceiveType" />
 | 
			
		||||
              </n-icon>
 | 
			
		||||
            </template>
 | 
			
		||||
          </n-timeline-item>
 | 
			
		||||
        </n-timeline>
 | 
			
		||||
      </n-space>
 | 
			
		||||
    </n-card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
  import { onBeforeUnmount, onMounted, ref } from 'vue';
 | 
			
		||||
  import { MessageOutlined, SendOutlined, SoundOutlined } from '@vicons/antd';
 | 
			
		||||
  import { format } from 'date-fns';
 | 
			
		||||
  import { addOnMessage, removeOnMessage, sendMsg, WebSocketMessage } from '@/utils/websocket';
 | 
			
		||||
  import { useMessage } from 'naive-ui';
 | 
			
		||||
 | 
			
		||||
  interface Message {
 | 
			
		||||
    type: Enum;
 | 
			
		||||
    content: string;
 | 
			
		||||
    time: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const message = useMessage();
 | 
			
		||||
  const messages = ref<Message[]>([]);
 | 
			
		||||
  const inputMessage = ref('你好,HotGo');
 | 
			
		||||
  const isInput = ref(false);
 | 
			
		||||
  const testMessageEvent = 'admin/addons/hgexample/testMessage';
 | 
			
		||||
 | 
			
		||||
  enum Enum {
 | 
			
		||||
    SendType = 1, // 发送类型
 | 
			
		||||
    ReceiveType = 2, // 接受类型
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function onFocus() {
 | 
			
		||||
    isInput.value = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function onBlur() {
 | 
			
		||||
    isInput.value = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function sendMessage() {
 | 
			
		||||
    if (inputMessage.value == '') {
 | 
			
		||||
      message.error('消息内容不能为空');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 发送消息
 | 
			
		||||
    sendMsg(testMessageEvent, {
 | 
			
		||||
      message: inputMessage.value,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const msg: Message = {
 | 
			
		||||
      type: Enum.SendType,
 | 
			
		||||
      content: inputMessage.value,
 | 
			
		||||
      time: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
 | 
			
		||||
    };
 | 
			
		||||
    insertMessage(msg);
 | 
			
		||||
    inputMessage.value = '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 存入本地记录
 | 
			
		||||
  function insertMessage(msg: Message): void {
 | 
			
		||||
    messages.value.unshift(msg); // 在头部插入消息
 | 
			
		||||
    if (messages.value.length > 10) {
 | 
			
		||||
      messages.value = messages.value.slice(0, 10); // 如果超过10个,则只保留最前面10个
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const onMessage = (res: WebSocketMessage) => {
 | 
			
		||||
    const msg: Message = {
 | 
			
		||||
      type: Enum.ReceiveType,
 | 
			
		||||
      content: res.data.message,
 | 
			
		||||
      time: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
 | 
			
		||||
    };
 | 
			
		||||
    insertMessage(msg);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  onMounted(() => {
 | 
			
		||||
    // 在当前页面注册消息监听
 | 
			
		||||
    addOnMessage(testMessageEvent, onMessage);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  onBeforeUnmount(() => {
 | 
			
		||||
    // 移除消息监听
 | 
			
		||||
    removeOnMessage(testMessageEvent);
 | 
			
		||||
  });
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 发送消息
 | 
			
		||||
- 向服务器发送一条消息
 | 
			
		||||
```ts
 | 
			
		||||
  import { sendMsg } from '@/utils/websocket';
 | 
			
		||||
 | 
			
		||||
    const event = 'admin/addons/hgexample/testMessage'; // 消息路由
 | 
			
		||||
    const data: object | null = {  // 消息内容
 | 
			
		||||
        message: 'message content...',
 | 
			
		||||
    };
 | 
			
		||||
    const isRetry = false; // 发送失败是否重试,不传默认为true
 | 
			
		||||
 | 
			
		||||
    // 基本使用 
 | 
			
		||||
    sendMsg(event, data);
 | 
			
		||||
 | 
			
		||||
    // 无消息内容 
 | 
			
		||||
    sendMsg(event);
 | 
			
		||||
 | 
			
		||||
    // 发送失败不重试 
 | 
			
		||||
    sendMsg(event, data, isRetry);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										143
									
								
								docs/guide-zh-CN/sys-websocket-server.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								docs/guide-zh-CN/sys-websocket-server.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,143 @@
 | 
			
		||||
## WebSocket服务器
 | 
			
		||||
 | 
			
		||||
目录
 | 
			
		||||
 | 
			
		||||
- 一个基本的消息收发例子
 | 
			
		||||
- 常用方法
 | 
			
		||||
- HTTP接口
 | 
			
		||||
- 其他
 | 
			
		||||
 | 
			
		||||
> hotgo提供了一个WebSocket服务器,随`HTTP服务`启停。集成了许多常用功能,如JWT身份认证、路由消息处理器、一对一消息/群组消息/广播消息、在线用户管理、心跳保持等,大大简化和规范了WebSocket服务器的开发流程。
 | 
			
		||||
- [Websocket客户端](sys-websocket-client.md)
 | 
			
		||||
 | 
			
		||||
###  一个基本的消息收发例子
 | 
			
		||||
- 这是一个基本的消息接收并进行处理的简单例子
 | 
			
		||||
 | 
			
		||||
#### 1.消息处理接口
 | 
			
		||||
- 消息处理在设计上采用了接口化的思路。只需要实现以下接口,即可进行WebSocket消息注册
 | 
			
		||||
- 文件路径:server/internal/websocket/model.go
 | 
			
		||||
```go
 | 
			
		||||
package websocket
 | 
			
		||||
 | 
			
		||||
// EventHandler 消息处理器
 | 
			
		||||
type EventHandler func(client *Client, req *WRequest)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 2.定义消息处理方法
 | 
			
		||||
- 以下是功能案例中的一个简单演示,实现了消息处理接口,并将收到的消息原样发送给客户端
 | 
			
		||||
- 文件路径:server/addons/hgexample/controller/websocket/handler/index.go
 | 
			
		||||
```go
 | 
			
		||||
package handler
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/encoding/gjson"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"hotgo/internal/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Index = cIndex{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cIndex struct{}
 | 
			
		||||
 | 
			
		||||
// TestMessage 测试消息
 | 
			
		||||
func (c *cIndex) TestMessage(client *websocket.Client, req *websocket.WRequest) {
 | 
			
		||||
	g.Log().Infof(client.Context(), "收到客户端测试消息:%v", gjson.New(req).String())
 | 
			
		||||
	// 将收到的消息原样发送给客户端
 | 
			
		||||
	websocket.SendSuccess(client, req.Event, req.Data) 
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### 3.注册消息
 | 
			
		||||
- 定义消息处理方法后,需要将其注册到WebSocket消息处理器,一般放在对应应用模块的`router/websocket.go`下即可
 | 
			
		||||
- 文件路径:server/addons/hgexample/router/websocket.go
 | 
			
		||||
```go
 | 
			
		||||
package router
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
	"hotgo/addons/hgexample/controller/websocket"
 | 
			
		||||
	"hotgo/addons/hgexample/controller/websocket/handler"
 | 
			
		||||
	ws "hotgo/internal/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// WebSocket ws路由配置
 | 
			
		||||
func WebSocket(ctx context.Context, group *ghttp.RouterGroup) {
 | 
			
		||||
	// 注册消息路由
 | 
			
		||||
	ws.RegisterMsg(ws.EventHandlers{
 | 
			
		||||
		"admin/addons/hgexample/testMessage": handler.Index.TestMessage, // 测试消息
 | 
			
		||||
	})
 | 
			
		||||
	
 | 
			
		||||
	// 这里"admin/addons/hgexample/testMessage"代表的是一个消息处理ID,可以自定义。建议的格式是和HTTP接口格式保持一致,这样还可以便于对用户请求的消息进行权限验证
 | 
			
		||||
	// 客户端连接后,向WebSocket服务器发送event为"admin/addons/hgexample/testMessage"的消息时,会调用TestMessage方法
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 到此,你已了解了WebSocket消息接收并进行处理的基本流程
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 常用方法
 | 
			
		||||
- websocket服务器还提供了一些常用的方法,下面只对部分进行说明
 | 
			
		||||
```go
 | 
			
		||||
func test() {
 | 
			
		||||
	websocket.SendToAll()      // 发送全部客户端
 | 
			
		||||
	websocket.SendToClientID() // 发送单个客户端
 | 
			
		||||
	websocket.SendToUser()     // 发送单个用户
 | 
			
		||||
	websocket.SendToTag()      // 发送某个标签、群组
 | 
			
		||||
 | 
			
		||||
    client := websocket.Manager().GetClient(id)         // 通过连接ID获取客户端连接
 | 
			
		||||
    client := websocket.Manager().GetUserClient(userId) // 通过用户ID获取客户端连接,因为用户是可多端登录的,这里返回的是一个切片
 | 
			
		||||
    
 | 
			
		||||
    websocket.SendSuccess(client, "admin/addons/hgexample/testMessage", "消息内容")           // 向指定客户端发送一条成功的消息
 | 
			
		||||
    websocket.SendError(client, "admin/addons/hgexample/testMessage", gerror.New("错误内容")) // 向指定客户端发送一条失败的消息
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### HTTP接口
 | 
			
		||||
- 你还可以通过http接口方式调用WebSocket发送消息
 | 
			
		||||
- 参考文件:server/internal/controller/websocket/send.go
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 其他
 | 
			
		||||
- WebSocket被连接时需验证用户认证中间件,所以用户必须登录成功后才能连接成功
 | 
			
		||||
- 参考文件:server/internal/logic/middleware/weboscket_auth.go
 | 
			
		||||
```go
 | 
			
		||||
package middleware
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/errors/gcode"
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
	"github.com/gogf/gf/v2/text/gstr"
 | 
			
		||||
	"hotgo/internal/consts"
 | 
			
		||||
	"hotgo/internal/library/response"
 | 
			
		||||
	"hotgo/utility/simple"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// WebSocketAuth websocket鉴权中间件
 | 
			
		||||
func (s *sMiddleware) WebSocketAuth(r *ghttp.Request) {
 | 
			
		||||
	var (
 | 
			
		||||
		ctx  = r.Context()
 | 
			
		||||
		path = gstr.Replace(r.URL.Path, simple.RouterPrefix(ctx, consts.AppWebSocket), "", 1)
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// 不需要验证登录的路由地址
 | 
			
		||||
	if s.IsExceptLogin(ctx, consts.AppWebSocket, path) {
 | 
			
		||||
		r.Middleware.Next()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 将用户信息传递到上下文中
 | 
			
		||||
	if err := s.DeliverUserContext(r); err != nil {
 | 
			
		||||
		response.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.Middleware.Next()
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- 如果您不要求用户进行登录即可使用 WebSocket,那么需要对身份验证中间件进行修改。然而,这样做会降低连接的安全性,并且无法应用于需要确定用户身份的情景,因此并不建议采取这种策略
 | 
			
		||||
@@ -21,6 +21,7 @@
 | 
			
		||||
- 单文件上传 UploadFile
 | 
			
		||||
- 多文件上传 UploadFile
 | 
			
		||||
- 文件选择器 FileChooser
 | 
			
		||||
- 大文件上传 MultipartUpload
 | 
			
		||||
- 开关 Switch
 | 
			
		||||
- 评分 Rate
 | 
			
		||||
- 省市区选择器 CitySelector
 | 
			
		||||
@@ -795,6 +796,33 @@ type FileType = 'image' | 'doc' | 'audio' | 'video' | 'zip' | 'other' | 'default
 | 
			
		||||
<FileChooser v-model:value="value" :maxNumber="10" fileType="image" />
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 大文件上传 MultipartUpload
 | 
			
		||||
- 基础用法
 | 
			
		||||
```vue
 | 
			
		||||
<template>
 | 
			
		||||
  <MultipartUpload ref="multipartUploadRef" @onFinish="handleFinishCall" />
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
import MultipartUpload from '@/components/Upload/multipartUpload.vue';
 | 
			
		||||
import { Attachment } from '@/components/FileChooser/src/model';
 | 
			
		||||
const multipartUploadRef = ref();
 | 
			
		||||
 | 
			
		||||
// 打开上传Modal
 | 
			
		||||
function handleMultipartUpload() {
 | 
			
		||||
  multipartUploadRef.value.openModal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 上传成功回调附件内容
 | 
			
		||||
function handleFinishCall(result: Attachment, success: boolean) {
 | 
			
		||||
  if (success) {
 | 
			
		||||
    reloadTable();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 开关 Switch
 | 
			
		||||
```vue
 | 
			
		||||
<template>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,6 @@
 | 
			
		||||
// Package addons
 | 
			
		||||
// @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 addons
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								server/addons/hgexample/api/admin/comp/import.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								server/addons/hgexample/api/admin/comp/import.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
// Package comp
 | 
			
		||||
// @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 comp
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ImportExcelReq 导入Excel
 | 
			
		||||
type ImportExcelReq struct {
 | 
			
		||||
	g.Meta `path:"/comp/importExcel" method:"post" tags:"功能案例" summary:"导入Excel"`
 | 
			
		||||
	File   *ghttp.UploadFile `json:"file" type:"file" dc:"分片文件"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ImportExcelSheet struct {
 | 
			
		||||
	Sheet string     `json:"sheet"`
 | 
			
		||||
	Rows  [][]string `json:"rows"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ImportExcelRes struct {
 | 
			
		||||
	Sheets []*ImportExcelSheet `json:"sheets"`
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								server/addons/hgexample/controller/admin/sys/comp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								server/addons/hgexample/controller/admin/sys/comp.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
// Package sys
 | 
			
		||||
// @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 sys
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/xuri/excelize/v2"
 | 
			
		||||
	"hotgo/addons/hgexample/api/admin/comp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Comp = cComp{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cComp struct{}
 | 
			
		||||
 | 
			
		||||
// ImportExcel 导入Excel
 | 
			
		||||
func (c *cComp) ImportExcel(ctx context.Context, req *comp.ImportExcelReq) (res *comp.ImportExcelRes, err error) {
 | 
			
		||||
	file, err := req.File.Open()
 | 
			
		||||
	defer file.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	excel, err := excelize.OpenReader(file)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer excel.Close()
 | 
			
		||||
 | 
			
		||||
	res = new(comp.ImportExcelRes)
 | 
			
		||||
	sheetList := excel.GetSheetList()
 | 
			
		||||
	for _, sheet := range sheetList {
 | 
			
		||||
		item := new(comp.ImportExcelSheet)
 | 
			
		||||
		item.Sheet = sheet
 | 
			
		||||
		item.Rows, err = excel.GetRows(sheet)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		res.Sheets = append(res.Sheets, item)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
// Package handler
 | 
			
		||||
// @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 handler
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogf/gf/v2/encoding/gjson"
 | 
			
		||||
	"github.com/gogf/gf/v2/frame/g"
 | 
			
		||||
	"hotgo/internal/websocket"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Index = cIndex{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cIndex struct{}
 | 
			
		||||
 | 
			
		||||
// TestMessage 测试消息
 | 
			
		||||
func (c *cIndex) TestMessage(client *websocket.Client, req *websocket.WRequest) {
 | 
			
		||||
	g.Log().Infof(client.Context(), "收到客户端测试消息:%v", gjson.New(req).String())
 | 
			
		||||
	// 将收到的消息原样发送给客户端
 | 
			
		||||
	websocket.SendSuccess(client, req.Event, req.Data)
 | 
			
		||||
}
 | 
			
		||||
@@ -47,20 +47,25 @@ func newModule() {
 | 
			
		||||
	addons.RegisterModule(m)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Init 初始化
 | 
			
		||||
func (m *module) Init(ctx context.Context) {
 | 
			
		||||
	global.Init(ctx, m.skeleton)
 | 
			
		||||
	// ...
 | 
			
		||||
// Start 启动模块
 | 
			
		||||
func (m *module) Start(option *addons.Option) (err error) {
 | 
			
		||||
	// 初始化模块
 | 
			
		||||
	global.Init(m.ctx, m.skeleton)
 | 
			
		||||
 | 
			
		||||
	// 注册插件路由
 | 
			
		||||
	option.Server.Group("/", func(group *ghttp.RouterGroup) {
 | 
			
		||||
		group.Middleware(service.Middleware().Addon)
 | 
			
		||||
		router.Admin(m.ctx, group)
 | 
			
		||||
		router.Api(m.ctx, group)
 | 
			
		||||
		router.Home(m.ctx, group)
 | 
			
		||||
		router.WebSocket(m.ctx, group)
 | 
			
		||||
	})
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InitRouter 初始化WEB路由
 | 
			
		||||
func (m *module) InitRouter(ctx context.Context, group *ghttp.RouterGroup) {
 | 
			
		||||
	m.Init(ctx)
 | 
			
		||||
	group.Middleware(service.Middleware().Addon)
 | 
			
		||||
	router.Admin(ctx, group)
 | 
			
		||||
	router.Api(ctx, group)
 | 
			
		||||
	router.Home(ctx, group)
 | 
			
		||||
	router.WebSocket(ctx, group)
 | 
			
		||||
// Stop 停止模块
 | 
			
		||||
func (m *module) Stop() (err error) {
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ctx 上下文
 | 
			
		||||
@@ -68,7 +73,7 @@ func (m *module) Ctx() context.Context {
 | 
			
		||||
	return m.ctx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetSkeleton 架子
 | 
			
		||||
// GetSkeleton 获取模块
 | 
			
		||||
func (m *module) GetSkeleton() *addons.Skeleton {
 | 
			
		||||
	return m.skeleton
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@ func Admin(ctx context.Context, group *ghttp.RouterGroup) {
 | 
			
		||||
		)
 | 
			
		||||
		group.Middleware(service.Middleware().AdminAuth)
 | 
			
		||||
		group.Bind(
 | 
			
		||||
			sys.Comp,
 | 
			
		||||
			sys.Config,
 | 
			
		||||
			sys.Table,
 | 
			
		||||
			sys.TreeTable,
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"github.com/gogf/gf/v2/net/ghttp"
 | 
			
		||||
	"hotgo/addons/hgexample/controller/websocket"
 | 
			
		||||
	"hotgo/addons/hgexample/controller/websocket/handler"
 | 
			
		||||
	"hotgo/addons/hgexample/global"
 | 
			
		||||
	"hotgo/internal/consts"
 | 
			
		||||
	"hotgo/internal/library/addons"
 | 
			
		||||
@@ -34,6 +35,6 @@ func WebSocket(ctx context.Context, group *ghttp.RouterGroup) {
 | 
			
		||||
 | 
			
		||||
	// 注册消息路由
 | 
			
		||||
	ws.RegisterMsg(ws.EventHandlers{
 | 
			
		||||
		// ...
 | 
			
		||||
		"admin/addons/hgexample/testMessage": handler.Index.TestMessage, // 测试消息
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
package modules
 | 
			
		||||
@@ -22,15 +22,6 @@ type ListRes struct {
 | 
			
		||||
	form.PageRes
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SelectsReq struct {
 | 
			
		||||
	g.Meta `path:"/addons/selects" method:"get" tags:"插件管理" summary:"生成入口选项"`
 | 
			
		||||
	sysin.AddonsSelectsInp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SelectsRes struct {
 | 
			
		||||
	*sysin.AddonsSelectsModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BuildReq 提交生成
 | 
			
		||||
type BuildReq struct {
 | 
			
		||||
	g.Meta `path:"/addons/build" method:"post" tags:"插件管理" summary:"提交生成"`
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import (
 | 
			
		||||
 | 
			
		||||
// ListReq 查询列表
 | 
			
		||||
type ListReq struct {
 | 
			
		||||
	g.Meta `path:"/blacklist/list" method:"get" tags:"黑名单" summary:"获取黑名单列表"` //  v:"RequestPreFilter"
 | 
			
		||||
	g.Meta `path:"/blacklist/list" method:"get" tags:"黑名单" summary:"获取黑名单列表"`
 | 
			
		||||
	sysin.BlacklistListInp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,3 +16,23 @@ type UploadFileReq struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UploadFileRes *sysin.AttachmentListModel
 | 
			
		||||
 | 
			
		||||
// CheckMultipartReq 检查文件分片
 | 
			
		||||
type CheckMultipartReq struct {
 | 
			
		||||
	g.Meta `path:"/upload/checkMultipart" tags:"上传" method:"post" summary:"检查文件分片"`
 | 
			
		||||
	sysin.CheckMultipartInp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CheckMultipartRes struct {
 | 
			
		||||
	*sysin.CheckMultipartModel
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UploadPartReq 分片上传
 | 
			
		||||
type UploadPartReq struct {
 | 
			
		||||
	g.Meta `path:"/upload/uploadPart" tags:"上传" method:"post" summary:"分片上传"`
 | 
			
		||||
	sysin.UploadPartInp
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UploadPartRes struct {
 | 
			
		||||
	*sysin.UploadPartModel
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,13 +31,3 @@ type ExportReq struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ExportRes struct{}
 | 
			
		||||
 | 
			
		||||
// OptionReq 获取变动状态选项
 | 
			
		||||
type OptionReq struct {
 | 
			
		||||
	g.Meta `path:"/creditsLog/option" method:"get" summary:"资产变动" tags:"获取变动状态选项"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type OptionRes struct {
 | 
			
		||||
	CreditType  []g.Map `json:"creditType"   dc:"变动类型 "`
 | 
			
		||||
	CreditGroup []g.Map `json:"creditGroup"   dc:"变动组别"`
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,9 @@
 | 
			
		||||
// Package curddemo
 | 
			
		||||
// @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 curddemo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
 
 | 
			
		||||
@@ -29,17 +29,6 @@ type ApplyRefundReq struct {
 | 
			
		||||
type ApplyRefundRes struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OptionReq 获取订单状态选项
 | 
			
		||||
type OptionReq struct {
 | 
			
		||||
	g.Meta `path:"/order/option" method:"get" summary:"充值订单" tags:"获取订单状态选项"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type OptionRes struct {
 | 
			
		||||
	Status             []g.Map `json:"status"   dc:"订单状态"`
 | 
			
		||||
	AcceptRefundStatus []g.Map `json:"acceptRefundStatus"   dc:"订单退款受理状态"`
 | 
			
		||||
	PayType            []g.Map `json:"payType"   dc:"支付方式"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateReq 创建充值订单
 | 
			
		||||
type CreateReq struct {
 | 
			
		||||
	g.Meta `path:"/order/create" method:"post" tags:"充值订单" summary:"创建充值订单"`
 | 
			
		||||
 
 | 
			
		||||
@@ -13,10 +13,10 @@ require (
 | 
			
		||||
	github.com/casbin/casbin/v2 v2.55.0
 | 
			
		||||
	github.com/forgoer/openssl v1.4.0
 | 
			
		||||
	github.com/go-pay/gopay v1.5.91
 | 
			
		||||
	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.1
 | 
			
		||||
	github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.1
 | 
			
		||||
	github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.1
 | 
			
		||||
	github.com/gogf/gf/v2 v2.6.1
 | 
			
		||||
	github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.4
 | 
			
		||||
	github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.4
 | 
			
		||||
	github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.4
 | 
			
		||||
	github.com/gogf/gf/v2 v2.6.4
 | 
			
		||||
	github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f
 | 
			
		||||
	github.com/golang-jwt/jwt/v5 v5.0.0
 | 
			
		||||
	github.com/gorilla/websocket v1.5.1
 | 
			
		||||
@@ -32,7 +32,7 @@ require (
 | 
			
		||||
	github.com/tencentyun/cos-go-sdk-v5 v0.7.45
 | 
			
		||||
	github.com/ufilesdk-dev/ufile-gosdk v1.0.3
 | 
			
		||||
	github.com/xuri/excelize/v2 v2.6.0
 | 
			
		||||
	go.opentelemetry.io/otel v1.21.0
 | 
			
		||||
	go.opentelemetry.io/otel v1.24.0
 | 
			
		||||
	golang.org/x/mod v0.9.0
 | 
			
		||||
	golang.org/x/tools v0.7.0
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.1
 | 
			
		||||
@@ -102,10 +102,10 @@ require (
 | 
			
		||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
			
		||||
	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
 | 
			
		||||
	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
 | 
			
		||||
	github.com/redis/go-redis/v9 v9.3.1 // indirect
 | 
			
		||||
	github.com/redis/go-redis/v9 v9.5.1 // indirect
 | 
			
		||||
	github.com/richardlehane/mscfb v1.0.4 // indirect
 | 
			
		||||
	github.com/richardlehane/msoleps v1.0.1 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.4.4 // indirect
 | 
			
		||||
	github.com/rivo/uniseg v0.4.7 // indirect
 | 
			
		||||
	github.com/rs/xid v1.5.0 // indirect
 | 
			
		||||
	github.com/shoenig/go-m1cpu v0.1.4 // indirect
 | 
			
		||||
	github.com/sirupsen/logrus v1.9.3 // indirect
 | 
			
		||||
@@ -120,15 +120,15 @@ require (
 | 
			
		||||
	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
 | 
			
		||||
	github.com/yusufpapurcu/wmi v1.2.2 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/metric v1.21.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/sdk v1.21.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/trace v1.21.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/metric v1.24.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/sdk v1.24.0 // indirect
 | 
			
		||||
	go.opentelemetry.io/otel/trace v1.24.0 // indirect
 | 
			
		||||
	go.uber.org/atomic v1.7.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.16.0 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.21.0 // indirect
 | 
			
		||||
	golang.org/x/image v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.19.0 // indirect
 | 
			
		||||
	golang.org/x/net v0.22.0 // indirect
 | 
			
		||||
	golang.org/x/sync v0.1.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.15.0 // indirect
 | 
			
		||||
	golang.org/x/sys v0.18.0 // indirect
 | 
			
		||||
	golang.org/x/text v0.14.0 // indirect
 | 
			
		||||
	golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.67.0 // indirect
 | 
			
		||||
 
 | 
			
		||||
@@ -170,14 +170,14 @@ github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrt
 | 
			
		||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 | 
			
		||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 | 
			
		||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 | 
			
		||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.1 h1:5VW1vlaFNSHHhMliRkGTcDshMeA52Il8T+gffJJaVMc=
 | 
			
		||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.1/go.mod h1:jxCa1WV/W+q0F4ILebakUsqRrl7iL3qvP+Uci0eXAew=
 | 
			
		||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.1 h1:5NWx7rZa8CbPNw1vbLzIXQFEMbKvoJVQM0GyReBRvJ8=
 | 
			
		||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.1/go.mod h1:iy1Dwp5xWfGfuWixCgGQ06ZX6lp+d9onbmSWWzi111A=
 | 
			
		||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.1 h1:d3/8lWFWmaQ/8mzJ5GxyRpO4racPpZ3yZ8kCuejhhiY=
 | 
			
		||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.1/go.mod h1:O0nzQLfNJtRApGHJluraTy41jc3LIvTsSkR8WAHb4f0=
 | 
			
		||||
github.com/gogf/gf/v2 v2.6.1 h1:n/cfXM506WjhPa6Z1CEDuHNM1XZ7C8JzSDPn2AfuxgQ=
 | 
			
		||||
github.com/gogf/gf/v2 v2.6.1/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
 | 
			
		||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.4 h1:ScG3YcYMDEP/UrwNtwQPt2noySa5ZpoV7BxrwaeBaro=
 | 
			
		||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.6.4/go.mod h1:oFFE9u1zHkxVXk7ZkNipXQR9JFyDZDiixZy243ywhfQ=
 | 
			
		||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.4 h1:43517FF//GKgGpb4pxHl3NWLxW/inTAQ7rUFnfUIoYY=
 | 
			
		||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.6.4/go.mod h1:9qNdKgqB+tHC9XczIoMzfSHmWkphQMXqxJXF6g9Icr4=
 | 
			
		||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.4 h1:PV0V2CPspwC+qgmqMC7qjCFkxH/SkfLwC0fg26ZTY54=
 | 
			
		||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.6.4/go.mod h1:Wnu7ASD+BWWlPn9NlSNOmCip7tHnYSXRSSjFJ5cCTEo=
 | 
			
		||||
github.com/gogf/gf/v2 v2.6.4 h1:w7HXdH9mcTsn/aE13CkaDbRArmAL1KS3FuQqDi6u74Y=
 | 
			
		||||
github.com/gogf/gf/v2 v2.6.4/go.mod h1:x2XONYcI4hRQ/4gMNbWHmZrNzSEIg20s2NULbzom5k0=
 | 
			
		||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
 | 
			
		||||
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
 | 
			
		||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 | 
			
		||||
@@ -410,15 +410,15 @@ github.com/qiniu/go-sdk/v7 v7.14.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFs
 | 
			
		||||
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
 | 
			
		||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
 | 
			
		||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 | 
			
		||||
github.com/redis/go-redis/v9 v9.3.1 h1:KqdY8U+3X6z+iACvumCNxnoluToB+9Me+TvyFa21Mds=
 | 
			
		||||
github.com/redis/go-redis/v9 v9.3.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
 | 
			
		||||
github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8=
 | 
			
		||||
github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
 | 
			
		||||
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
 | 
			
		||||
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
 | 
			
		||||
github.com/richardlehane/msoleps v1.0.1 h1:RfrALnSNXzmXLbGct/P2b4xkFz4e8Gmj/0Vj9M9xC1o=
 | 
			
		||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 | 
			
		||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 | 
			
		||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
 | 
			
		||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 | 
			
		||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
 | 
			
		||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
 | 
			
		||||
@@ -516,16 +516,16 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 | 
			
		||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
			
		||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
			
		||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 | 
			
		||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
 | 
			
		||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
 | 
			
		||||
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
 | 
			
		||||
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
 | 
			
		||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4=
 | 
			
		||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI=
 | 
			
		||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
 | 
			
		||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
 | 
			
		||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
 | 
			
		||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
 | 
			
		||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
 | 
			
		||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
 | 
			
		||||
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
 | 
			
		||||
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
 | 
			
		||||
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
 | 
			
		||||
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
 | 
			
		||||
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
 | 
			
		||||
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
 | 
			
		||||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 | 
			
		||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 | 
			
		||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
 | 
			
		||||
@@ -544,8 +544,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220408190544-5352b0902921/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 | 
			
		||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
 | 
			
		||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 | 
			
		||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
 | 
			
		||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 | 
			
		||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
 | 
			
		||||
@@ -623,8 +623,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx
 | 
			
		||||
golang.org/x/net v0.0.0-20220407224826-aac1ed45d8e3/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 | 
			
		||||
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 | 
			
		||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 | 
			
		||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
 | 
			
		||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
 | 
			
		||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
 | 
			
		||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 | 
			
		||||
@@ -705,8 +705,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
 | 
			
		||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 | 
			
		||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
 | 
			
		||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
			
		||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
 | 
			
		||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 | 
			
		||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 | 
			
		||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 | 
			
		||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user