更新2.1.2版本,优化部门、角色权限,增加上下级关系;增加登录、系统、短信日志;优化省市区编码

This commit is contained in:
孟帅 2023-01-25 11:49:21 +08:00
parent 11fad0132d
commit 93e0fe7250
190 changed files with 35896 additions and 7208 deletions

View File

@ -27,11 +27,11 @@
</div> </div>
## 平台简介 ## 平台简介
* 基于全新Go Frame 2+Vue3+Naive UI开发的全栈前后端分离的管理系统 * 基于全新Go Frame 2+Vue3+Naive UI开发的全栈前后端分离的管理系统
* 前端采用naive-ui-admin 、Vue、Naive UI。 * 前端采用naive-ui-admin 、Vue、Naive UI。
## 特征 ## 特征
* 高生产率:几分钟即可搭建一个后台管理系统 * 高生产率:几分钟即可搭建一个后台管理系统
* 模块化:单应用多系统的模式,将一个完整的应用拆分为多个系统,后续扩展更加便捷,增加代码复用性。 * 模块化:单应用多系统的模式,将一个完整的应用拆分为多个系统,后续扩展更加便捷,增加代码复用性。
@ -153,7 +153,7 @@ VITE_PROXY=[["/admin","http://你的IP:8000/admin"]]
web端 web端
```shell script ```shell script
cd views cd web
# 首先确定你以安装node16.0以上版本并安装了包[npm、yarn],否则可能会出现一些未知报错 # 首先确定你以安装node16.0以上版本并安装了包[npm、yarn],否则可能会出现一些未知报错
# 安装依赖 # 安装依赖

View File

@ -32,12 +32,12 @@ type LoginReq struct {
g.Meta `path:"/site/login" method:"post" tags:"后台基础" summary:"账号登录"` g.Meta `path:"/site/login" method:"post" tags:"后台基础" summary:"账号登录"`
Username string `json:"username" v:"required#用户名不能为空" dc:"用户名"` Username string `json:"username" v:"required#用户名不能为空" dc:"用户名"`
Password string `json:"password" v:"required#密码不能为空" dc:"密码"` Password string `json:"password" v:"required#密码不能为空" dc:"密码"`
//Cid string `json:"cid" v:"required#验证码ID不能为空" dc:"验证码ID"` Cid string `json:"cid" dc:"验证码ID"`
//Code string `json:"code" v:"required#验证码不能为空" dc:"验证码"` Code string `json:"code" dc:"验证码"`
//Device string `json:"device" dc:"登录设备"` IsLock bool `json:"isLock" dc:"是否为锁屏状态"`
} }
type LoginRes struct { type LoginRes struct {
adminin.MemberLoginModel *adminin.MemberLoginModel
} }
// SiteConfigReq 获取配置 // SiteConfigReq 获取配置

View File

@ -0,0 +1,19 @@
// Package common
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package common
import "github.com/gogf/gf/v2/frame/g"
// SendTestSmsReq 发送测试短信
type SendTestSmsReq struct {
Event string `json:"event" v:"required#事件模板不能为空" dc:"事件模板"`
Mobile string `json:"mobile" v:"required#接收手机号不能为空" dc:"接收手机号"`
Code string `json:"code" v:"required#接收验证码不能为空" dc:"接收验证码"`
g.Meta `path:"/sms/sendTest" tags:"短信" method:"post" summary:"发送测试短信"`
}
type SendTestSmsRes struct {
}

View File

@ -66,3 +66,10 @@ type StatusReq struct {
g.Meta `path:"/cron/status" method:"post" tags:"定时任务" summary:"更新定时任务状态"` g.Meta `path:"/cron/status" method:"post" tags:"定时任务" summary:"更新定时任务状态"`
} }
type StatusRes struct{} type StatusRes struct{}
// OnlineExecReq 在线执行
type OnlineExecReq struct {
g.Meta `path:"/cron/onlineExec" method:"post" tags:"定时任务" summary:"在线执行"`
sysin.OnlineExecInp
}
type OnlineExecRes struct{}

View File

@ -20,7 +20,7 @@ type GroupListReq struct {
form.StatusReq form.StatusReq
Title string `json:"title"` Title string `json:"title"`
Content string `json:"content"` Content string `json:"content"`
g.Meta `path:"/cron_group/list" method:"get" tags:"定时任务分组" summary:"获取定时任务分组列表"` g.Meta `path:"/cronGroup/list" method:"get" tags:"定时任务分组" summary:"获取定时任务分组列表"`
} }
type GroupListRes struct { type GroupListRes struct {
@ -31,7 +31,7 @@ type GroupListRes struct {
// GroupViewReq 获取信息 // GroupViewReq 获取信息
type GroupViewReq struct { type GroupViewReq struct {
Id int64 `json:"id" v:"required#定时任务分组ID不能为空" dc:"定时任务分组ID"` Id int64 `json:"id" v:"required#定时任务分组ID不能为空" dc:"定时任务分组ID"`
g.Meta `path:"/cron_group/view" method:"get" tags:"定时任务分组" summary:"获取指定信息"` g.Meta `path:"/cronGroup/view" method:"get" tags:"定时任务分组" summary:"获取指定信息"`
} }
type GroupViewRes struct { type GroupViewRes struct {
*sysin.CronGroupViewModel *sysin.CronGroupViewModel
@ -40,21 +40,21 @@ type GroupViewRes struct {
// GroupEditReq 修改/新增 // GroupEditReq 修改/新增
type GroupEditReq struct { type GroupEditReq struct {
entity.SysCronGroup entity.SysCronGroup
g.Meta `path:"/cron_group/edit" method:"post" tags:"定时任务分组" summary:"修改/新增定时任务分组"` g.Meta `path:"/cronGroup/edit" method:"post" tags:"定时任务分组" summary:"修改/新增定时任务分组"`
} }
type GroupEditRes struct{} type GroupEditRes struct{}
// GroupDeleteReq 删除 // GroupDeleteReq 删除
type GroupDeleteReq struct { type GroupDeleteReq struct {
Id interface{} `json:"id" v:"required#定时任务分组ID不能为空" dc:"定时任务分组ID"` Id interface{} `json:"id" v:"required#定时任务分组ID不能为空" dc:"定时任务分组ID"`
g.Meta `path:"/cron_group/delete" method:"post" tags:"定时任务分组" summary:"删除定时任务分组"` g.Meta `path:"/cronGroup/delete" method:"post" tags:"定时任务分组" summary:"删除定时任务分组"`
} }
type GroupDeleteRes struct{} type GroupDeleteRes struct{}
// GroupMaxSortReq 最大排序 // GroupMaxSortReq 最大排序
type GroupMaxSortReq struct { type GroupMaxSortReq struct {
Id int64 `json:"id" dc:"定时任务分组ID"` Id int64 `json:"id" dc:"定时任务分组ID"`
g.Meta `path:"/cron_group/max_sort" method:"get" tags:"定时任务分组" summary:"定时任务分组最大排序"` g.Meta `path:"/cronGroup/max_sort" method:"get" tags:"定时任务分组" summary:"定时任务分组最大排序"`
} }
type GroupMaxSortRes struct { type GroupMaxSortRes struct {
Sort int `json:"sort" dc:"排序"` Sort int `json:"sort" dc:"排序"`
@ -63,13 +63,13 @@ type GroupMaxSortRes struct {
// GroupStatusReq 更新状态 // GroupStatusReq 更新状态
type GroupStatusReq struct { type GroupStatusReq struct {
entity.SysCronGroup entity.SysCronGroup
g.Meta `path:"/cron_group/status" method:"post" tags:"定时任务分组" summary:"更新定时任务分组状态"` g.Meta `path:"/cronGroup/status" method:"post" tags:"定时任务分组" summary:"更新定时任务分组状态"`
} }
type GroupStatusRes struct{} type GroupStatusRes struct{}
// GroupSelectReq 定时任务分组选项 // GroupSelectReq 定时任务分组选项
type GroupSelectReq struct { type GroupSelectReq struct {
g.Meta `path:"/cron_group/select" method:"get" tags:"定时任务分组" summary:"定时任务分组选项"` g.Meta `path:"/cronGroup/select" method:"get" tags:"定时任务分组" summary:"定时任务分组选项"`
} }
type GroupSelectRes sysin.DictTypeSelectModel type GroupSelectRes sysin.DictTypeSelectModel

View File

@ -0,0 +1,50 @@
// Package loginlog
// @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 loginlog
import (
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
)
// ListReq 查询登录日志列表
type ListReq struct {
g.Meta `path:"/loginLog/list" method:"get" tags:"登录日志" summary:"获取登录日志列表"`
sysin.LoginLogListInp
}
type ListRes struct {
form.PageRes
List []*sysin.LoginLogListModel `json:"list" dc:"数据列表"`
}
// ExportReq 导出登录日志列表
type ExportReq struct {
g.Meta `path:"/loginLog/export" method:"get" tags:"登录日志" summary:"导出登录日志列表"`
sysin.LoginLogListInp
}
type ExportRes struct{}
// ViewReq 获取登录日志指定信息
type ViewReq struct {
g.Meta `path:"/loginLog/view" method:"get" tags:"登录日志" summary:"获取登录日志指定信息"`
sysin.LoginLogViewInp
}
type ViewRes struct {
*sysin.LoginLogViewModel
}
// DeleteReq 删除登录日志
type DeleteReq struct {
g.Meta `path:"/loginLog/delete" method:"post" tags:"登录日志" summary:"删除登录日志"`
sysin.LoginLogDeleteInp
}
type DeleteRes struct{}

View File

@ -106,7 +106,7 @@ type ListRes struct {
// ViewReq 获取指定信息 // ViewReq 获取指定信息
type ViewReq struct { type ViewReq struct {
g.Meta `path:"/member/view" method:"get" tags:"会员" summary:"获取指定信息"` g.Meta `path:"/member/view" method:"get" tags:"会员" summary:"获取指定信息"`
Id int64 `json:"id" dc:"会员ID"` // v:"required#会员ID不能为空" Id int64 `json:"id" dc:"会员ID"`
} }
type ViewRes struct { type ViewRes struct {
*adminin.MemberViewModel *adminin.MemberViewModel

View File

@ -24,7 +24,8 @@ type OnlineListReq struct {
form.PageReq form.PageReq
form.RangeDateReq form.RangeDateReq
form.StatusReq form.StatusReq
UserId int64 `json:"userId" description:"用户ID"` UserId int64 `json:"userId" description:"用户ID"`
Addr string `json:"addr" description:"登录地址"`
} }
type OnlineListRes struct { type OnlineListRes struct {

View File

@ -39,25 +39,24 @@ type ViewRes struct {
// EditReq 修改/新增 // EditReq 修改/新增
type EditReq struct { type EditReq struct {
entity.SysProvinces
g.Meta `path:"/provinces/edit" method:"post" tags:"省市区" summary:"修改/新增省市区"` g.Meta `path:"/provinces/edit" method:"post" tags:"省市区" summary:"修改/新增省市区"`
sysin.ProvincesEditInp
} }
type EditRes struct{} type EditRes struct{}
// DeleteReq 删除 // DeleteReq 删除
type DeleteReq struct { type DeleteReq struct {
Id interface{} `json:"id" v:"required#省市区ID不能为空" dc:"省市区ID"`
g.Meta `path:"/provinces/delete" method:"post" tags:"省市区" summary:"删除省市区"` g.Meta `path:"/provinces/delete" method:"post" tags:"省市区" summary:"删除省市区"`
sysin.ProvincesDeleteInp
} }
type DeleteRes struct{} type DeleteRes struct{}
// MaxSortReq 最大排序 // MaxSortReq 最大排序
type MaxSortReq struct { type MaxSortReq struct {
Id int64 `json:"id" dc:"省市区ID"` g.Meta `path:"/provinces/maxSort" method:"get" tags:"省市区" summary:"省市区最大排序"`
g.Meta `path:"/provinces/max_sort" method:"get" tags:"省市区" summary:"省市区最大排序"`
} }
type MaxSortRes struct { type MaxSortRes struct {
Sort int `json:"sort" dc:"排序"` *sysin.ProvincesMaxSortModel
} }
// StatusReq 更新状态 // StatusReq 更新状态
@ -66,3 +65,31 @@ type StatusReq struct {
g.Meta `path:"/provinces/status" method:"post" tags:"省市区" summary:"更新省市区状态"` g.Meta `path:"/provinces/status" method:"post" tags:"省市区" summary:"更新省市区状态"`
} }
type StatusRes struct{} type StatusRes struct{}
// TreeReq 关系树选项列表
type TreeReq struct {
g.Meta `path:"/provinces/tree" tags:"省市区" method:"get" summary:"省市区关系树选项列表"`
}
type TreeRes struct {
List []map[string]interface{} `json:"list" dc:"数据列表"`
}
// ChildrenListReq 获取省市区下级列表
type ChildrenListReq struct {
g.Meta `path:"/provinces/childrenList" method:"get" tags:"省市区" summary:"获取省市区下级列表"`
sysin.ProvincesChildrenListInp
}
type ChildrenListRes struct {
List []*sysin.ProvincesChildrenListModel `json:"list" dc:"数据列表"`
form.PageRes
}
// UniqueIdReq 地区ID是否唯一
type UniqueIdReq struct {
g.Meta `path:"/provinces/uniqueId" method:"get" tags:"省市区" summary:"地区ID是否唯一"`
sysin.ProvincesUniqueIdInp
}
type UniqueIdRes struct {
*sysin.ProvincesUniqueIdModel
}

View File

@ -52,7 +52,7 @@ type ListReq struct {
} }
type ListRes struct { type ListRes struct {
List []*adminin.RoleListModel `json:"list" description:"数据列表"` List []g.Map `json:"list" description:"数据列表"`
form.PageRes form.PageRes
} }

View File

@ -0,0 +1,50 @@
// Package servelog
// @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 servelog
import (
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
)
// ListReq 查询服务日志列表
type ListReq struct {
g.Meta `path:"/serveLog/list" method:"get" tags:"服务日志" summary:"获取服务日志列表"`
sysin.ServeLogListInp
}
type ListRes struct {
form.PageRes
List []*sysin.ServeLogListModel `json:"list" dc:"数据列表"`
}
// ExportReq 导出服务日志列表
type ExportReq struct {
g.Meta `path:"/serveLog/export" method:"get" tags:"服务日志" summary:"导出服务日志列表"`
sysin.ServeLogListInp
}
type ExportRes struct{}
// ViewReq 获取服务日志指定信息
type ViewReq struct {
g.Meta `path:"/serveLog/view" method:"get" tags:"服务日志" summary:"获取服务日志指定信息"`
sysin.ServeLogViewInp
}
type ViewRes struct {
*sysin.ServeLogViewModel
}
// DeleteReq 删除服务日志
type DeleteReq struct {
g.Meta `path:"/serveLog/delete" method:"post" tags:"服务日志" summary:"删除服务日志"`
sysin.ServeLogDeleteInp
}
type DeleteRes struct{}

View File

@ -0,0 +1,69 @@
package smslog
import (
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
)
// ListReq 查询列表
type ListReq struct {
form.PageReq
form.RangeDateReq
form.StatusReq
Title string `json:"title"`
Content string `json:"content"`
g.Meta `path:"/smsLog/list" method:"get" tags:"短信记录" summary:"获取短信记录列表"`
}
type ListRes struct {
List []*sysin.SmsLogListModel `json:"list" dc:"数据列表"`
form.PageRes
}
// ViewReq 获取指定信息
type ViewReq struct {
Id int64 `json:"id" v:"required#短信记录ID不能为空" dc:"短信记录ID"`
g.Meta `path:"/smsLog/view" method:"get" tags:"短信记录" summary:"获取指定信息"`
}
type ViewRes struct {
*sysin.SmsLogViewModel
}
// EditReq 修改/新增数据
type EditReq struct {
entity.SysSmsLog
g.Meta `path:"/smsLog/edit" method:"post" tags:"短信记录" summary:"修改/新增短信记录"`
}
type EditRes struct{}
// DeleteReq 删除
type DeleteReq struct {
Id interface{} `json:"id" v:"required#短信记录ID不能为空" dc:"短信记录ID"`
g.Meta `path:"/smsLog/delete" method:"post" tags:"短信记录" summary:"删除短信记录"`
}
type DeleteRes struct{}
// MaxSortReq 最大排序
type MaxSortReq struct {
Id int64 `json:"id" dc:"短信记录ID"`
g.Meta `path:"/smsLog/maxSort" method:"get" tags:"短信记录" summary:"短信记录最大排序"`
}
type MaxSortRes struct {
Sort int `json:"sort" dc:"排序"`
}
// StatusReq 更新状态
type StatusReq struct {
entity.SysSmsLog
g.Meta `path:"/smsLog/status" method:"post" tags:"短信记录" summary:"更新短信记录状态"`
}
type StatusRes struct{}
// SendTestReq 更新状态
type SendTestReq struct {
entity.SysSmsLog
g.Meta `path:"/smsLog/sendTest" method:"post" tags:"短信记录" summary:"发送测试短信"`
}
type SendTestRes struct{}

View File

@ -4,6 +4,10 @@ go 1.15
require ( require (
github.com/Shopify/sarama v1.34.1 github.com/Shopify/sarama v1.34.1
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.5
github.com/alibabacloud-go/tea v1.1.20
github.com/alibabacloud-go/tea-utils/v2 v2.0.1
github.com/apache/rocketmq-client-go/v2 v2.1.0 github.com/apache/rocketmq-client-go/v2 v2.1.0
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394
github.com/bufanyun/pool v0.2.1 github.com/bufanyun/pool v0.2.1
@ -13,7 +17,7 @@ require (
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0-beta2 github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0-beta2
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0 github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0
github.com/gogf/gf/v2 v2.3.0 github.com/gogf/gf/v2 v2.3.1
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/gomodule/redigo v1.8.8 github.com/gomodule/redigo v1.8.8
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect

View File

@ -47,6 +47,35 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2 h1:2kR1YkvQloHUstmPcG0Sjk24zTKbza7izzJfJNwBFSs=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.5 h1:/c+eQK0o7Lf8EIZ0ovB0cU+L82rVu1r3v91icUYnsdM=
github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.5/go.mod h1:CT6UkI74Or2t3NSDgGyY6hkKid3fW7VvN4l+mda+HSw=
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20 h1:wFK4xEbvGYMtzTyHhIju9D7ecWxvSUdoLO6y4vDLFik=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.1 h1:K6kwgo+UiYx+/kr6CO0PN5ACZDzE3nnn9d77215AkTs=
github.com/alibabacloud-go/tea-utils/v2 v2.0.1/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M=
github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/apache/rocketmq-client-go/v2 v2.1.0 h1:3eABKfxc1WmS2lLTTbKMe1gZfZV6u1Sx9orFnOfABV0= github.com/apache/rocketmq-client-go/v2 v2.1.0 h1:3eABKfxc1WmS2lLTTbKMe1gZfZV6u1Sx9orFnOfABV0=
github.com/apache/rocketmq-client-go/v2 v2.1.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q= github.com/apache/rocketmq-client-go/v2 v2.1.0/go.mod h1:oEZKFDvS7sz/RWU0839+dQBupazyBV7WX5cP6nrio0Q=
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ= github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 h1:OYA+5W64v3OgClL+IrOD63t4i/RW7RqrAVl9LTZ9UqQ=
@ -131,8 +160,8 @@ github.com/gogf/gf/contrib/drivers/mysql/v2 v2.2.0-beta2/go.mod h1:z+/0qiOwMroAn
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0 h1:r2q8MLwF6yUIEm6Hhwsfo/ixaJTKluTXSjU8rSeXo3c= github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0 h1:r2q8MLwF6yUIEm6Hhwsfo/ixaJTKluTXSjU8rSeXo3c=
github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0/go.mod h1:V9o2BF9ovJnaZhHImHAanqUgjX4kI51lgU45u5rPqvw= github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.0/go.mod h1:V9o2BF9ovJnaZhHImHAanqUgjX4kI51lgU45u5rPqvw=
github.com/gogf/gf/v2 v2.0.0/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM= github.com/gogf/gf/v2 v2.0.0/go.mod h1:apktt6TleWtCIwpz63vBqUnw8MX8gWKoZyxgDpXFtgM=
github.com/gogf/gf/v2 v2.3.0 h1:Uz4z6tMqnpH9azLFrfBX1R1k/73d7QPC2E4Ab8L3y4g= github.com/gogf/gf/v2 v2.3.1 h1:uptCJK47N6KSRwTBnFAqBWYnYa/OXBkZ0OlhO9CK7bQ=
github.com/gogf/gf/v2 v2.3.0/go.mod h1:tsbmtwcAl2chcYoq/fP9W2FZf06aw4i89X34nbSHo9Y= github.com/gogf/gf/v2 v2.3.1/go.mod h1:tsbmtwcAl2chcYoq/fP9W2FZf06aw4i89X34nbSHo9Y=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
@ -200,8 +229,9 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
@ -288,6 +318,7 @@ github.com/mojocn/base64Captcha v1.3.5 h1:Qeilr7Ta6eDtG4S+tQuZ5+hO+QHbiGAJdi4Pfo
github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY= github.com/mojocn/base64Captcha v1.3.5/go.mod h1:/tTTXn4WTpX9CfrmipqRytCpJ27Uw3G6I7NcP2WwcmY=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@ -353,12 +384,15 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 h1:N8Bg45zpk/UcpNGnfJt2y/3lRWASHNTUET8owPYCgYI= github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@ -373,6 +407,8 @@ github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g= github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g=
github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw= github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
@ -391,6 +427,7 @@ github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Q
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
@ -419,6 +456,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@ -549,6 +588,7 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -623,6 +663,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -719,10 +760,13 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -730,6 +774,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@ -44,6 +44,7 @@ var (
group.Middleware( group.Middleware(
service.Middleware().Ctx, //必须第一个加载 service.Middleware().Ctx, //必须第一个加载
service.Middleware().CORS, service.Middleware().CORS,
service.Middleware().Blacklist,
service.Middleware().DemoLimit, service.Middleware().DemoLimit,
service.Middleware().ResponseHandler, service.Middleware().ResponseHandler,
) )

View File

@ -8,6 +8,9 @@ package consts
import "github.com/gogf/gf/v2/util/gconv" import "github.com/gogf/gf/v2/util/gconv"
// RequestEncryptKey 请求加密密钥用于敏感数据加密16位字符前后端需保持一致。安全起见请修改此值
var RequestEncryptKey = []byte("f080a463654b2279")
// 配置数据类型 // 配置数据类型
const ( const (
ConfigTypeString = "string" ConfigTypeString = "string"

View File

@ -8,5 +8,6 @@ package consts
// ContextKey 上下文 // ContextKey 上下文
const ( const (
ContextKey = "HotGoContext" ContextKey = "HotGoContext" // http上下文变量名称
ContextKeyCronArgs = "args" // 定时任务参数上下文变量名称
) )

View File

@ -9,10 +9,9 @@ package consts
// 定时任务 // 定时任务
const ( const (
CronArgsKey = "args" // 上下文变量名称 CronSplitStr = "," // 变量分割符
CronSplitStr = "," // 变量分割符 CronPolicySame = 1 // 并行策略
CronPolicySame = 1 // 并行策略 CronPolicySingle = 2 // 单例策略
CronPolicySingle = 2 // 单例策略 CronPolicyOnce = 3 // 单次策略
CronPolicyOnce = 3 // 单次策略 CronPolicyTimes = 4 // 多次策略
CronPolicyTimes = 4 // 多次策略
) )

View File

@ -8,7 +8,7 @@ package consts
// 消息队列 // 消息队列
const ( const (
QueueName = `queue:` QueueLogTopic = `request_log` // 访问日志
QueueLogPath = "queue" // 需要在config中配置queue的log QueueLoginLogTopic = `login_log` // 登录日志
QueueLogTopic = `request_log` QueueServeLogTopic = `serve_log` // 服务日志
) )

View File

@ -0,0 +1,24 @@
package consts
// 短信驱动
const (
SmsDriveAliYun = "aliyun" // 阿里云
SmsDriveTencent = "tencent" // 腾讯云
)
// 短信内置模板
const (
SmsTemplateCode = "code" // 通用验证码
SmsTemplateLogin = "login" // 登录
SmsTemplateRegister = "register" // 注册
SmsTemplateResetPwd = "resetPwd" // 重置密码
SmsTemplateBind = "bind" // 绑定手机号
SmsTemplateCash = "cash" // 申请提现
)
// 短信状态码
const (
SmsStatusNotUsed = 1 // 未使用
SmsStatusUsed = 2 // 已使用
)

View File

@ -8,5 +8,5 @@ package consts
// VersionApp HotGo版本 // VersionApp HotGo版本
const ( const (
VersionApp = "2.1.1" VersionApp = "2.1.2"
) )

View File

@ -204,14 +204,14 @@ func (c *cMember) View(ctx context.Context, req *member.ViewReq) (*member.ViewRe
return nil, err return nil, err
} }
roleList, _, err := service.AdminRole().List(ctx, adminin.RoleListInp{}) //roleList, _, err := service.AdminRole().List(ctx, adminin.RoleListInp{})
if err != nil { //if err != nil {
return nil, err // return nil, err
} //}
var res member.ViewRes var res member.ViewRes
res.Posts = postsList res.Posts = postsList
res.Roles = roleList //res.Roles = roleList
if req.Id <= 0 { if req.Id <= 0 {
return &res, err return &res, err

View File

@ -10,6 +10,7 @@ import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/api/backend/monitor" "hotgo/api/backend/monitor"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/model/input/form" "hotgo/internal/model/input/form"
@ -46,9 +47,7 @@ func (c *cMonitor) Offline(ctx context.Context, req *monitor.OfflineReq) (res *m
// View 获取指定信息 // View 获取指定信息
func (c *cMonitor) View(ctx context.Context, req *monitor.OnlineViewReq) (*monitor.OnlineViewRes, error) { func (c *cMonitor) View(ctx context.Context, req *monitor.OnlineViewReq) (*monitor.OnlineViewRes, error) {
var res monitor.OnlineViewRes return &monitor.OnlineViewRes{}, nil
// ...
return &res, nil
} }
// OnlineList 获取在线列表 // OnlineList 获取在线列表
@ -63,26 +62,31 @@ func (c *cMonitor) OnlineList(ctx context.Context, req *monitor.OnlineListReq) (
return &res, nil return &res, nil
} }
for c, _ := range c.wsManager.GetClients() { for conn, _ := range c.wsManager.GetClients() {
if c.SendClose || c.User == nil { if conn.SendClose || conn.User == nil {
continue continue
} }
if req.UserId > 0 && req.UserId != c.User.Id { if req.UserId > 0 && req.UserId != conn.User.Id {
continue continue
} }
if req.Addr != "" && !gstr.Contains(conn.Addr, req.Addr) {
continue
}
clients = append(clients, &monitor.OnlineModel{ clients = append(clients, &monitor.OnlineModel{
ID: c.ID, ID: conn.ID,
Addr: c.Addr, Addr: conn.Addr,
Os: useragent.GetOs(c.UserAgent), Os: useragent.GetOs(conn.UserAgent),
Browser: useragent.GetBrowser(c.UserAgent), Browser: useragent.GetBrowser(conn.UserAgent),
FirstTime: c.FirstTime, FirstTime: conn.FirstTime,
HeartbeatTime: c.HeartbeatTime, HeartbeatTime: conn.HeartbeatTime,
App: c.User.App, App: conn.User.App,
UserId: c.User.Id, UserId: conn.User.Id,
Username: c.User.Username, Username: conn.User.Username,
Avatar: c.User.Avatar, Avatar: conn.User.Avatar,
ExpTime: c.User.Exp, ExpTime: conn.User.Exp,
}) })
} }
@ -96,11 +100,11 @@ func (c *cMonitor) OnlineList(ctx context.Context, req *monitor.OnlineListReq) (
for k, v := range clients { for k, v := range clients {
if k >= offset && i <= perPage { if k >= offset && i <= perPage {
i++
if isDemo.Bool() { if isDemo.Bool() {
v.Addr = consts.DemoTips v.Addr = consts.DemoTips
} }
res.List = append(res.List, v) res.List = append(res.List, v)
i++
} }
} }

View File

@ -19,6 +19,7 @@ import (
"hotgo/internal/library/captcha" "hotgo/internal/library/captcha"
"hotgo/internal/library/jwt" "hotgo/internal/library/jwt"
"hotgo/internal/model/input/adminin" "hotgo/internal/model/input/adminin"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
) )
@ -60,28 +61,32 @@ func (c *cSite) getWsAddr(ctx context.Context) string {
// Captcha 登录验证码 // Captcha 登录验证码
func (c *cSite) Captcha(ctx context.Context, req *common.LoginCaptchaReq) (res *common.LoginCaptchaRes, err error) { func (c *cSite) Captcha(ctx context.Context, req *common.LoginCaptchaReq) (res *common.LoginCaptchaRes, err error) {
cid, base64 := captcha.Generate(ctx)
// 获取生成的验证码图片 res = &common.LoginCaptchaRes{Cid: cid, Base64: base64}
Cid, Base64 := captcha.GetVerifyImgString(ctx)
res = &common.LoginCaptchaRes{Cid: Cid, Base64: Base64}
return return
} }
// Login 提交登录 // Login 提交登录
func (c *cSite) Login(ctx context.Context, req *common.LoginReq) (res *common.LoginRes, err error) { func (c *cSite) Login(ctx context.Context, req *common.LoginReq) (res *common.LoginRes, err error) {
//// 校验 验证码
//if !captcha.VerifyString(req.Cid, req.Code) {
// err = gerror.New("验证码错误")
// return
//}
//
var in adminin.MemberLoginInp var in adminin.MemberLoginInp
if err = gconv.Scan(req, &in); err != nil { if err = gconv.Scan(req, &in); err != nil {
return nil, err return nil, err
} }
defer func() {
var response = new(adminin.MemberLoginModel)
if res != nil && res.MemberLoginModel != nil {
response = res.MemberLoginModel
}
service.SysLoginLog().Push(ctx, sysin.LoginLogPushInp{Input: in, Response: response, Err: err})
}()
// 校验 验证码
if !req.IsLock && !captcha.Verify(req.Cid, req.Code) {
err = gerror.New("验证码错误")
return
}
model, err := service.AdminMember().Login(ctx, in) model, err := service.AdminMember().Login(ctx, in)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -0,0 +1,37 @@
// Package common
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package common
import (
"context"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/api/backend/common"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/validate"
)
var Sms = new(cSms)
type cSms struct{}
// SendTest 发送测试短信
func (c *cSms) SendTest(ctx context.Context, req *common.SendTestSmsReq) (res *common.SendTestSmsRes, err error) {
var in sysin.SendCodeInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
if err = service.SysSmsLog().SendCode(ctx, in); err != nil {
return nil, err
}
return
}

View File

@ -8,6 +8,7 @@ package sys
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"hotgo/api/backend/cron" "hotgo/api/backend/cron"
"hotgo/internal/model/input/form" "hotgo/internal/model/input/form"
@ -111,3 +112,17 @@ func (c *cCron) Status(ctx context.Context, req *cron.StatusReq) (res *cron.Stat
return res, nil return res, nil
} }
// OnlineExec 在线执行
func (c *cCron) OnlineExec(ctx context.Context, req *cron.OnlineExecReq) (res *cron.OnlineExecRes, err error) {
if req.Id <= 0 {
return nil, gerror.New("定时任务ID不能为空")
}
var in sysin.OnlineExecInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
return res, service.SysCron().OnlineExec(ctx, in)
}

View File

@ -40,7 +40,7 @@ func (c *sLog) Export(ctx context.Context, req *log.ExportReq) (res *log.ExportR
return return
} }
// List 获取全局日志列表 // List 获取访问日志列表
func (c *sLog) List(ctx context.Context, req *log.ListReq) (*log.ListRes, error) { func (c *sLog) List(ctx context.Context, req *log.ListReq) (*log.ListRes, error) {
var ( var (
in sysin.LogListInp in sysin.LogListInp

View File

@ -0,0 +1,104 @@
// 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
// @AutoGenerate Version 2.1.1
// @AutoGenerate Date 2023-01-19 16:57:33
//
package sys
import (
"context"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/api/backend/loginlog"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/validate"
)
var (
LoginLog = cLoginLog{}
)
type cLoginLog struct{}
// List 查看登录日志列表
func (c *cLoginLog) List(ctx context.Context, req *loginlog.ListReq) (res *loginlog.ListRes, err error) {
var in sysin.LoginLogListInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
list, totalCount, err := service.SysLoginLog().List(ctx, in)
if err != nil {
return nil, err
}
res = new(loginlog.ListRes)
res.List = list
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
res.Page = req.Page
res.PerPage = req.PerPage
return res, nil
}
// Export 导出登录日志列表
func (c *cLoginLog) Export(ctx context.Context, req *loginlog.ExportReq) (res *loginlog.ExportRes, err error) {
var in sysin.LoginLogListInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
if err = service.SysLoginLog().Export(ctx, in); err != nil {
return nil, err
}
return res, nil
}
// View 获取指定登录日志信息
func (c *cLoginLog) View(ctx context.Context, req *loginlog.ViewReq) (res *loginlog.ViewRes, err error) {
var in sysin.LoginLogViewInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
data, err := service.SysLoginLog().View(ctx, in)
if err != nil {
return nil, err
}
res = new(loginlog.ViewRes)
res.LoginLogViewModel = data
return res, nil
}
// Delete 删除登录日志
func (c *cLoginLog) Delete(ctx context.Context, req *loginlog.DeleteReq) (res *loginlog.DeleteRes, err error) {
var in sysin.LoginLogDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
if err = service.SysLoginLog().Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}

View File

@ -21,6 +21,20 @@ var (
type cProvinces struct{} type cProvinces struct{}
// Tree 关系树选项列表
func (c *cProvinces) Tree(ctx context.Context, req *provinces.TreeReq) (*provinces.TreeRes, error) {
var (
res provinces.TreeRes
err error
)
res.List, err = service.SysProvinces().Tree(ctx)
if err != nil {
return nil, err
}
return &res, nil
}
// Delete 删除 // Delete 删除
func (c *cProvinces) Delete(ctx context.Context, req *provinces.DeleteReq) (res *provinces.DeleteRes, err error) { func (c *cProvinces) Delete(ctx context.Context, req *provinces.DeleteReq) (res *provinces.DeleteRes, err error) {
var in sysin.ProvincesDeleteInp var in sysin.ProvincesDeleteInp
@ -47,15 +61,15 @@ func (c *cProvinces) Edit(ctx context.Context, req *provinces.EditReq) (res *pro
} }
// MaxSort 最大排序 // MaxSort 最大排序
func (c *cProvinces) MaxSort(ctx context.Context, req *provinces.MaxSortReq) (*provinces.MaxSortRes, error) { func (c *cProvinces) MaxSort(ctx context.Context, req *provinces.MaxSortReq) (res *provinces.MaxSortRes, err error) {
data, err := service.SysProvinces().MaxSort(ctx, sysin.ProvincesMaxSortInp{Id: req.Id}) data, err := service.SysProvinces().MaxSort(ctx, sysin.ProvincesMaxSortInp{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
var res provinces.MaxSortRes res = new(provinces.MaxSortRes)
res.Sort = data.Sort res.ProvincesMaxSortModel = data
return &res, nil return res, nil
} }
// View 获取指定信息 // View 获取指定信息
@ -104,3 +118,44 @@ func (c *cProvinces) Status(ctx context.Context, req *provinces.StatusReq) (res
return res, nil return res, nil
} }
// ChildrenList 获取省市区下级列表
func (c *cProvinces) ChildrenList(ctx context.Context, req *provinces.ChildrenListReq) (*provinces.ChildrenListRes, error) {
var (
in sysin.ProvincesChildrenListInp
res provinces.ChildrenListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := service.SysProvinces().ChildrenList(ctx, in)
if err != nil {
return nil, err
}
res.List = list
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
res.Page = req.Page
res.PerPage = req.PerPage
return &res, nil
}
// UniqueId 地区ID是否唯一
func (c *cProvinces) UniqueId(ctx context.Context, req *provinces.UniqueIdReq) (res *provinces.UniqueIdRes, err error) {
var in sysin.ProvincesUniqueIdInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
data, err := service.SysProvinces().UniqueId(ctx, in)
if err != nil {
return nil, err
}
res = new(provinces.UniqueIdRes)
res.ProvincesUniqueIdModel = data
return res, nil
}

View File

@ -0,0 +1,102 @@
// 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/gogf/gf/v2/util/gconv"
"hotgo/api/backend/servelog"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/validate"
)
var (
ServeLog = cServeLog{}
)
type cServeLog struct{}
// List 查看服务日志列表
func (c *cServeLog) List(ctx context.Context, req *servelog.ListReq) (res *servelog.ListRes, err error) {
var in sysin.ServeLogListInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
list, totalCount, err := service.SysServeLog().List(ctx, in)
if err != nil {
return nil, err
}
res = new(servelog.ListRes)
res.List = list
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
res.Page = req.Page
res.PerPage = req.PerPage
return res, nil
}
// Export 导出服务日志列表
func (c *cServeLog) Export(ctx context.Context, req *servelog.ExportReq) (res *servelog.ExportRes, err error) {
var in sysin.ServeLogListInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
if err = service.SysServeLog().Export(ctx, in); err != nil {
return nil, err
}
return res, nil
}
// View 获取指定服务日志信息
func (c *cServeLog) View(ctx context.Context, req *servelog.ViewReq) (res *servelog.ViewRes, err error) {
var in sysin.ServeLogViewInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
data, err := service.SysServeLog().View(ctx, in)
if err != nil {
return nil, err
}
res = new(servelog.ViewRes)
res.ServeLogViewModel = data
return res, nil
}
// Delete 删除服务日志
func (c *cServeLog) Delete(ctx context.Context, req *servelog.DeleteReq) (res *servelog.DeleteRes, err error) {
var in sysin.ServeLogDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = validate.PreFilter(ctx, &in); err != nil {
return nil, err
}
if err = service.SysServeLog().Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}

View File

@ -0,0 +1,113 @@
// Package sys
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sys
import (
"context"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/api/backend/smslog"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
var (
SmsLog = cSmsLog{}
)
type cSmsLog struct{}
// Delete 删除
func (c *cSmsLog) Delete(ctx context.Context, req *smslog.DeleteReq) (res *smslog.DeleteRes, err error) {
var in sysin.SmsLogDeleteInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = service.SysSmsLog().Delete(ctx, in); err != nil {
return nil, err
}
return res, nil
}
// Edit 更新
func (c *cSmsLog) Edit(ctx context.Context, req *smslog.EditReq) (res *smslog.EditRes, err error) {
var in sysin.SmsLogEditInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = service.SysSmsLog().Edit(ctx, in); err != nil {
return nil, err
}
return res, nil
}
// MaxSort 最大排序
func (c *cSmsLog) MaxSort(ctx context.Context, req *smslog.MaxSortReq) (*smslog.MaxSortRes, error) {
data, err := service.SysSmsLog().MaxSort(ctx, sysin.SmsLogMaxSortInp{Id: req.Id})
if err != nil {
return nil, err
}
var res smslog.MaxSortRes
res.Sort = data.Sort
return &res, nil
}
// View 获取指定信息
func (c *cSmsLog) View(ctx context.Context, req *smslog.ViewReq) (*smslog.ViewRes, error) {
data, err := service.SysSmsLog().View(ctx, sysin.SmsLogViewInp{Id: req.Id})
if err != nil {
return nil, err
}
var res smslog.ViewRes
res.SmsLogViewModel = data
return &res, nil
}
// List 查看列表
func (c *cSmsLog) List(ctx context.Context, req *smslog.ListReq) (*smslog.ListRes, error) {
var (
in sysin.SmsLogListInp
res smslog.ListRes
)
if err := gconv.Scan(req, &in); err != nil {
return nil, err
}
list, totalCount, err := service.SysSmsLog().List(ctx, in)
if err != nil {
return nil, err
}
res.List = list
res.PageCount = form.CalPageCount(totalCount, req.PerPage)
res.Page = req.Page
res.PerPage = req.PerPage
return &res, nil
}
// Status 更新部门状态
func (c *cSmsLog) Status(ctx context.Context, req *smslog.StatusReq) (res *smslog.StatusRes, err error) {
var in sysin.SmsLogStatusInp
if err = gconv.Scan(req, &in); err != nil {
return nil, err
}
if err = service.SysSmsLog().Status(ctx, in); err != nil {
return nil, err
}
return res, nil
}

View File

@ -20,21 +20,17 @@ import (
"sync" "sync"
) )
var (
// 添加新的任务时只需实现cronStrategy接口并加入到cronList即可
cronList = []cronStrategy{
Test, // 测试无参任务
Test2, // 测试有参任务
Monitor, // 监控
}
inst = new(tasks)
)
type cronStrategy interface { type cronStrategy interface {
GetName() string GetName() string
Execute(ctx context.Context) Execute(ctx context.Context)
} }
var (
// 添加新的任务时只需实现cronStrategy接口并加入到cronList即可
cronList []cronStrategy
inst = new(tasks)
)
type tasks struct { type tasks struct {
list []*TaskItem list []*TaskItem
sync.RWMutex sync.RWMutex
@ -49,7 +45,7 @@ type TaskItem struct {
Count int // 执行次数仅Policy=4时有效 Count int // 执行次数仅Policy=4时有效
} }
func init() { func LoadCronList() {
for _, cron := range cronList { for _, cron := range cronList {
inst.Add(&TaskItem{ inst.Add(&TaskItem{
Name: cron.GetName(), Name: cron.GetName(),
@ -66,6 +62,10 @@ func StopALL() {
// StartALL 启动任务 // StartALL 启动任务
func StartALL(sysCron []*entity.SysCron) error { func StartALL(sysCron []*entity.SysCron) error {
if len(inst.list) == 0 {
LoadCronList()
}
var ( var (
err error err error
ct = gctx.New() ct = gctx.New()
@ -86,7 +86,7 @@ func StartALL(sysCron []*entity.SysCron) error {
if gcron.Search(cron.Name) == nil { if gcron.Search(cron.Name) == nil {
var ( var (
t *gcron.Entry t *gcron.Entry
ctx = context.WithValue(gctx.New(), consts.CronArgsKey, strings.Split(cron.Params, consts.CronSplitStr)) ctx = context.WithValue(gctx.New(), consts.ContextKeyCronArgs, strings.Split(cron.Params, consts.CronSplitStr))
) )
switch cron.Policy { switch cron.Policy {
case consts.CronPolicySame: case consts.CronPolicySame:
@ -130,7 +130,7 @@ func StartALL(sysCron []*entity.SysCron) error {
} }
} }
g.Log().Debug(ct, "load scheduled task complete..") g.Log().Debug(ct, "load cron success..")
return nil return nil
} }
@ -140,8 +140,15 @@ func Stop(sysCron *entity.SysCron) error {
} }
// Once 立即执行一次某个任务 // Once 立即执行一次某个任务
func Once(sysCron *entity.SysCron) error { func Once(ctx context.Context, sysCron *entity.SysCron) error {
return nil for _, v := range cronList {
if v.GetName() == sysCron.Name {
go v.Execute(ctx)
return nil
}
}
return gerror.Newf("定时任务不存在:%+v", sysCron.Name)
} }
// Delete 删除任务 // Delete 删除任务

View File

@ -18,6 +18,10 @@ import (
"sync" "sync"
) )
func init() {
cronList = append(cronList, Monitor)
}
// Monitor 监控 // Monitor 监控
var Monitor = &cMonitor{name: "monitor"} var Monitor = &cMonitor{name: "monitor"}

View File

@ -12,6 +12,10 @@ import (
"time" "time"
) )
func init() {
cronList = append(cronList, Test)
}
// Test 测试任务 // Test 测试任务
var Test = &cTest{name: "test"} var Test = &cTest{name: "test"}

View File

@ -13,6 +13,10 @@ import (
"time" "time"
) )
func init() {
cronList = append(cronList, Test2)
}
// Test2 测试2任务 // Test2 测试2任务
var Test2 = &cTest2{name: "test2"} var Test2 = &cTest2{name: "test2"}
@ -26,7 +30,7 @@ func (c *cTest2) GetName() string {
// Execute 执行任务 // Execute 执行任务
func (c *cTest2) Execute(ctx context.Context) { func (c *cTest2) Execute(ctx context.Context) {
args, ok := ctx.Value(consts.CronArgsKey).([]string) args, ok := ctx.Value(consts.ContextKeyCronArgs).([]string)
if !ok { if !ok {
g.Log().Warning(ctx, "参数解析失败!") g.Log().Warning(ctx, "参数解析失败!")
return return

View File

@ -28,6 +28,8 @@ type AdminDeptColumns struct {
Leader string // 负责人 Leader string // 负责人
Phone string // 联系电话 Phone string // 联系电话
Email string // 邮箱 Email string // 邮箱
Level string // 关系树等级
Tree string // 关系树
Sort string // 排序 Sort string // 排序
Status string // 部门状态 Status string // 部门状态
CreatedAt string // 创建时间 CreatedAt string // 创建时间
@ -44,6 +46,8 @@ var adminDeptColumns = AdminDeptColumns{
Leader: "leader", Leader: "leader",
Phone: "phone", Phone: "phone",
Email: "email", Email: "email",
Level: "level",
Tree: "tree",
Sort: "sort", Sort: "sort",
Status: "status", Status: "status",
CreatedAt: "created_at", CreatedAt: "created_at",

View File

@ -1,143 +0,0 @@
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// DemoDao is the data access object for table hg_demo.
type DemoDao 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 DemoColumns // columns contains all the column names of Table for convenient usage.
}
// DemoColumns defines and stores column names for table hg_demo.
type DemoColumns struct {
Id string // ID
CategoryId string // 分类ID
Flag string // 标签
Title string // 标题
Description string // 描述
Content string // 内容
Image string // 单图
Images string // 多图
Attachfile string // 附件
Attachfiles string // 多附件
Map string // 动态键值对
Star string // 推荐星
Price string // 价格
Views string // 浏览次数
ActivityAt string // 活动时间
StartAt string // 开启时间
EndAt string // 结束时间
Switch string // 开关
Sort string // 排序
Avatar string // 头像
Sex string // 性别
Qq string // qq
Email string // 邮箱
Mobile string // 手机号码
Hobby string // 爱好
Channel string // 渠道
Pid string // 上级ID
Level string // 树等级
Tree string // 关系树
Remark string // 备注
Status string // 状态
CreatedBy string // 创建者
UpdatedBy string // 更新者
CreatedAt string // 创建时间
UpdatedAt string // 修改时间
DeletedAt string // 删除时间
}
// demoColumns holds the columns for table hg_demo.
var demoColumns = DemoColumns{
Id: "id",
CategoryId: "category_id",
Flag: "flag",
Title: "title",
Description: "description",
Content: "content",
Image: "image",
Images: "images",
Attachfile: "attachfile",
Attachfiles: "attachfiles",
Map: "map",
Star: "star",
Price: "price",
Views: "views",
ActivityAt: "activity_at",
StartAt: "start_at",
EndAt: "end_at",
Switch: "switch",
Sort: "sort",
Avatar: "avatar",
Sex: "sex",
Qq: "qq",
Email: "email",
Mobile: "mobile",
Hobby: "hobby",
Channel: "channel",
Pid: "pid",
Level: "level",
Tree: "tree",
Remark: "remark",
Status: "status",
CreatedBy: "created_by",
UpdatedBy: "updated_by",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
DeletedAt: "deleted_at",
}
// NewDemoDao creates and returns a new DAO object for table data access.
func NewDemoDao() *DemoDao {
return &DemoDao{
group: "default",
table: "hg_demo",
columns: demoColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *DemoDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *DemoDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *DemoDao) Columns() DemoColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *DemoDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *DemoDao) 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 *DemoDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -21,6 +21,7 @@ type SysLogDao struct {
// SysLogColumns defines and stores column names for table hg_sys_log. // SysLogColumns defines and stores column names for table hg_sys_log.
type SysLogColumns struct { type SysLogColumns struct {
Id string // 日志ID Id string // 日志ID
ReqId string // 对外ID
AppId string // 应用ID AppId string // 应用ID
MerchantId string // 商户ID MerchantId string // 商户ID
MemberId string // 用户ID MemberId string // 用户ID
@ -36,10 +37,9 @@ type SysLogColumns struct {
ErrorCode string // 报错code ErrorCode string // 报错code
ErrorMsg string // 报错信息 ErrorMsg string // 报错信息
ErrorData string // 报错日志 ErrorData string // 报错日志
ReqId string // 对外ID
Timestamp string // 响应时间
UserAgent string // UA信息 UserAgent string // UA信息
TakeUpTime string // 请求耗时 TakeUpTime string // 请求耗时
Timestamp string // 响应时间
Status string // 状态 Status string // 状态
CreatedAt string // 创建时间 CreatedAt string // 创建时间
UpdatedAt string // 修改时间 UpdatedAt string // 修改时间
@ -48,6 +48,7 @@ type SysLogColumns struct {
// sysLogColumns holds the columns for table hg_sys_log. // sysLogColumns holds the columns for table hg_sys_log.
var sysLogColumns = SysLogColumns{ var sysLogColumns = SysLogColumns{
Id: "id", Id: "id",
ReqId: "req_id",
AppId: "app_id", AppId: "app_id",
MerchantId: "merchant_id", MerchantId: "merchant_id",
MemberId: "member_id", MemberId: "member_id",
@ -63,10 +64,9 @@ var sysLogColumns = SysLogColumns{
ErrorCode: "error_code", ErrorCode: "error_code",
ErrorMsg: "error_msg", ErrorMsg: "error_msg",
ErrorData: "error_data", ErrorData: "error_data",
ReqId: "req_id",
Timestamp: "timestamp",
UserAgent: "user_agent", UserAgent: "user_agent",
TakeUpTime: "take_up_time", TakeUpTime: "take_up_time",
Timestamp: "timestamp",
Status: "status", Status: "status",
CreatedAt: "created_at", CreatedAt: "created_at",
UpdatedAt: "updated_at", UpdatedAt: "updated_at",

View File

@ -0,0 +1,91 @@
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysLoginLogDao is the data access object for table hg_sys_login_log.
type SysLoginLogDao 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 SysLoginLogColumns // columns contains all the column names of Table for convenient usage.
}
// SysLoginLogColumns defines and stores column names for table hg_sys_login_log.
type SysLoginLogColumns struct {
Id string // 日志ID
ReqId string // 请求ID
MemberId string // 用户ID
Username string // 用户名
Response string // 响应数据
LoginAt string // 登录时间
ErrMsg string // 错误提示
Status string // 状态
CreatedAt string // 创建时间
UpdatedAt string // 修改时间
}
// sysLoginLogColumns holds the columns for table hg_sys_login_log.
var sysLoginLogColumns = SysLoginLogColumns{
Id: "id",
ReqId: "req_id",
MemberId: "member_id",
Username: "username",
Response: "response",
LoginAt: "login_at",
ErrMsg: "err_msg",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
// NewSysLoginLogDao creates and returns a new DAO object for table data access.
func NewSysLoginLogDao() *SysLoginLogDao {
return &SysLoginLogDao{
group: "default",
table: "hg_sys_login_log",
columns: sysLoginLogColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysLoginLogDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysLoginLogDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysLoginLogDao) Columns() SysLoginLogColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysLoginLogDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysLoginLogDao) 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 *SysLoginLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -20,40 +20,34 @@ type SysProvincesDao struct {
// SysProvincesColumns defines and stores column names for table hg_sys_provinces. // SysProvincesColumns defines and stores column names for table hg_sys_provinces.
type SysProvincesColumns struct { type SysProvincesColumns struct {
Id string // 省市区ID Id string // 省市区ID
Title string // 栏目名称 Title string // 栏目名称
ShortTitle string // 缩写 Pinyin string // 拼音
Areacode string // 区域编码 Lng string // 经度
Zipcode string // 邮政编码 Lat string // 纬度
Pinyin string // 拼音 Pid string // 父栏目
Lng string // 经度 Level string // 关系树等级
Lat string // 纬度 Tree string // 关系
Pid string // 父栏目 Sort string // 排序
Level string // 关系树等级 Status string // 状态
Tree string // 关系 CreatedAt string // 创建时间
Sort string // 排序 UpdatedAt string // 更新时间
Status string // 状态
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
} }
// sysProvincesColumns holds the columns for table hg_sys_provinces. // sysProvincesColumns holds the columns for table hg_sys_provinces.
var sysProvincesColumns = SysProvincesColumns{ var sysProvincesColumns = SysProvincesColumns{
Id: "id", Id: "id",
Title: "title", Title: "title",
ShortTitle: "short_title", Pinyin: "pinyin",
Areacode: "areacode", Lng: "lng",
Zipcode: "zipcode", Lat: "lat",
Pinyin: "pinyin", Pid: "pid",
Lng: "lng", Level: "level",
Lat: "lat", Tree: "tree",
Pid: "pid", Sort: "sort",
Level: "level", Status: "status",
Tree: "tree", CreatedAt: "created_at",
Sort: "sort", UpdatedAt: "updated_at",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
} }
// NewSysProvincesDao creates and returns a new DAO object for table data access. // NewSysProvincesDao creates and returns a new DAO object for table data access.

View File

@ -0,0 +1,91 @@
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysServeLogDao is the data access object for table hg_sys_serve_log.
type SysServeLogDao 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 SysServeLogColumns // columns contains all the column names of Table for convenient usage.
}
// SysServeLogColumns defines and stores column names for table hg_sys_serve_log.
type SysServeLogColumns struct {
Id string // 日志ID
TraceId string // 链路ID
LevelFormat string // 日志级别
Content string // 日志内容
Stack string // 打印堆栈
Line string // 调用行
TriggerNs string // 触发时间(ns)
Status string // 状态
CreatedAt string // 创建时间
UpdatedAt string // 修改时间
}
// sysServeLogColumns holds the columns for table hg_sys_serve_log.
var sysServeLogColumns = SysServeLogColumns{
Id: "id",
TraceId: "trace_id",
LevelFormat: "level_format",
Content: "content",
Stack: "stack",
Line: "line",
TriggerNs: "trigger_ns",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
// NewSysServeLogDao creates and returns a new DAO object for table data access.
func NewSysServeLogDao() *SysServeLogDao {
return &SysServeLogDao{
group: "default",
table: "hg_sys_serve_log",
columns: sysServeLogColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysServeLogDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysServeLogDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysServeLogDao) Columns() SysServeLogColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysServeLogDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysServeLogDao) 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 *SysServeLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -0,0 +1,89 @@
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
// SysSmsLogDao is the data access object for table hg_sys_sms_log.
type SysSmsLogDao 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 SysSmsLogColumns // columns contains all the column names of Table for convenient usage.
}
// SysSmsLogColumns defines and stores column names for table hg_sys_sms_log.
type SysSmsLogColumns struct {
Id string // 主键
Event string // 事件
Mobile string // 手机号
Code string // 验证码或短信内容
Times string // 验证次数
Ip string // ip地址
Status string // 状态(1未验证,2已验证)
CreatedAt string // 创建时间
UpdatedAt string // 更新时间
}
// sysSmsLogColumns holds the columns for table hg_sys_sms_log.
var sysSmsLogColumns = SysSmsLogColumns{
Id: "id",
Event: "event",
Mobile: "mobile",
Code: "code",
Times: "times",
Ip: "ip",
Status: "status",
CreatedAt: "created_at",
UpdatedAt: "updated_at",
}
// NewSysSmsLogDao creates and returns a new DAO object for table data access.
func NewSysSmsLogDao() *SysSmsLogDao {
return &SysSmsLogDao{
group: "default",
table: "hg_sys_sms_log",
columns: sysSmsLogColumns,
}
}
// DB retrieves and returns the underlying raw database management object of current DAO.
func (dao *SysSmsLogDao) DB() gdb.DB {
return g.DB(dao.group)
}
// Table returns the table name of current dao.
func (dao *SysSmsLogDao) Table() string {
return dao.table
}
// Columns returns all column names of current dao.
func (dao *SysSmsLogDao) Columns() SysSmsLogColumns {
return dao.columns
}
// Group returns the configuration group name of database of current dao.
func (dao *SysSmsLogDao) Group() string {
return dao.group
}
// Ctx creates and returns the Model for current DAO, It automatically sets the context for current operation.
func (dao *SysSmsLogDao) 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 *SysSmsLogDao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}

View File

@ -7,7 +7,6 @@ package dao
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao/internal" "hotgo/internal/dao/internal"
"hotgo/internal/model/entity" "hotgo/internal/model/entity"
@ -67,7 +66,6 @@ func (dao *sysDictTypeDao) GetTypes(ctx context.Context, id int64) (types []stri
types = append(types, v.String()) types = append(types, v.String())
} }
g.Log().Warningf(ctx, "types:%+v", types)
return types, nil return types, nil
} }
@ -81,7 +79,6 @@ func (dao *sysDictTypeDao) GetType(ctx context.Context, id int64) (types string,
return types, err return types, err
} }
g.Log().Warningf(ctx, "GetType types:%+v", list.String())
return list.String(), nil return list.String(), nil
} }

View File

@ -8,19 +8,19 @@ import (
"hotgo/internal/dao/internal" "hotgo/internal/dao/internal"
) )
// internalDemoDao is internal type for wrapping internal DAO implements. // internalSysLoginLogDao is internal type for wrapping internal DAO implements.
type internalDemoDao = *internal.DemoDao type internalSysLoginLogDao = *internal.SysLoginLogDao
// demoDao is the data access object for table hg_demo. // sysLoginLogDao is the data access object for table hg_sys_login_log.
// You can define custom methods on it to extend its functionality as you wish. // You can define custom methods on it to extend its functionality as you wish.
type demoDao struct { type sysLoginLogDao struct {
internalDemoDao internalSysLoginLogDao
} }
var ( var (
// Demo is globally public accessible object for table hg_demo operations. // SysLoginLog is globally public accessible object for table hg_sys_login_log operations.
Demo = demoDao{ SysLoginLog = sysLoginLogDao{
internal.NewDemoDao(), internal.NewSysLoginLogDao(),
} }
) )

View File

@ -31,20 +31,20 @@ var (
// Fill with you ideas below. // Fill with you ideas below.
// GetRegion 获取省市编码对应的地区名称 // GetRegion 获取省市编码对应的地区名称
func (dao *sysProvincesDao) GetRegion(ctx context.Context, province int, city int, spilt ...string) (string, error) { func (dao *sysProvincesDao) GetRegion(ctx context.Context, province int64, city int64, spilt ...string) (string, error) {
var ( var (
provinceName *gvar.Var provinceName *gvar.Var
cityName *gvar.Var cityName *gvar.Var
err error err error
) )
// TODO 默认分隔符
// 分隔符
spiltSymbol := "-" spiltSymbol := "-"
if len(spilt) > 0 { if len(spilt) > 0 {
spiltSymbol = spilt[0] spiltSymbol = spilt[0]
} }
if province > 0 { if province > 0 && province < 999999 {
provinceName, err = dao.Ctx(ctx).Where("id", province).Fields("title").Value() provinceName, err = dao.Ctx(ctx).Where("id", province).Fields("title").Value()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)

View File

@ -0,0 +1,27 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"hotgo/internal/dao/internal"
)
// internalSysServeLogDao is internal type for wrapping internal DAO implements.
type internalSysServeLogDao = *internal.SysServeLogDao
// sysServeLogDao is the data access object for table hg_sys_serve_log.
// You can define custom methods on it to extend its functionality as you wish.
type sysServeLogDao struct {
internalSysServeLogDao
}
var (
// SysServeLog is globally public accessible object for table hg_sys_serve_log operations.
SysServeLog = sysServeLogDao{
internal.NewSysServeLogDao(),
}
)
// Fill with you ideas below.

View File

@ -0,0 +1,43 @@
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
package dao
import (
"context"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/dao/internal"
)
// internalSysSmsLogDao is internal type for wrapping internal DAO implements.
type internalSysSmsLogDao = *internal.SysSmsLogDao
// sysSmsLogDao is the data access object for table hg_sys_sms_log.
// You can define custom methods on it to extend its functionality as you wish.
type sysSmsLogDao struct {
internalSysSmsLogDao
}
var (
// SysSmsLog is globally public accessible object for table hg_sys_sms_log operations.
SysSmsLog = sysSmsLogDao{
internal.NewSysSmsLogDao(),
}
)
// Fill with you ideas below.
// NowDayCount 当天发送次数
func (dao *sysSmsLogDao) NowDayCount(ctx context.Context, event, mobile string) (count int, err error) {
count, err = dao.Ctx(ctx).
Where("mobile", mobile).
Where("event", event).
WhereGTE("created_at", gtime.Now().Format("Y-m-d")).
Count()
if err != nil {
return 0, err
}
return
}

View File

@ -10,20 +10,32 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/gogf/gf/v2" "github.com/gogf/gf/v2"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcache" "github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/library/hggen" "hotgo/internal/library/hggen"
"hotgo/internal/library/location" "hotgo/internal/library/location"
"hotgo/internal/library/queue"
"hotgo/internal/model/entity"
"hotgo/internal/service"
"hotgo/utility/charset"
"hotgo/utility/simple" "hotgo/utility/simple"
"os" "os"
) )
func Init(ctx context.Context) { func Init(ctx context.Context) {
if _, err := g.Cfg().Get(ctx, "hotgo.debug"); err != nil { _, err := g.Cfg().Get(ctx, "hotgo.debug")
if err != nil {
g.Log().Fatal(ctx, "配置读取异常:", err, "\r\n你确定 config/config.yaml 文件存在且格式正确吗?\r\n") g.Log().Fatal(ctx, "配置读取异常:", err, "\r\n你确定 config/config.yaml 文件存在且格式正确吗?\r\n")
return
} }
//g.SetDebug(debug.Bool())
// 默认上海时区 // 默认上海时区
if err := gtime.SetTimeZone("Asia/Shanghai"); err != nil { if err := gtime.SetTimeZone("Asia/Shanghai"); err != nil {
g.Log().Fatalf(ctx, "时区设置异常err%+v", err) g.Log().Fatalf(ctx, "时区设置异常err%+v", err)
@ -33,12 +45,15 @@ func Init(ctx context.Context) {
RootPtah, _ = os.Getwd() RootPtah, _ = os.Getwd()
fmt.Printf("欢迎使用HotGo\r\n当前运行环境%v, 运行根路径为:%v \r\nHotGo版本v%v, gf版本%v \n", SysType, RootPtah, consts.VersionApp, gf.VERSION) fmt.Printf("欢迎使用HotGo\r\n当前运行环境%v, 运行根路径为:%v \r\nHotGo版本v%v, gf版本%v \n", SysType, RootPtah, consts.VersionApp, gf.VERSION)
g.Log().SetHandlers(LoggingServeLogHandler)
setOrmCacheAdapter() setOrmCacheAdapter()
service.SysBlacklist().Load(ctx)
startMonitor(ctx) startMonitor(ctx)
hggen.InIt(ctx) hggen.InIt(ctx)
} }
func startMonitor(ctx context.Context) { func startMonitor(ctx context.Context) {
@ -62,3 +77,47 @@ func setOrmCacheAdapter() {
redisCache := gcache.NewAdapterRedis(g.Redis()) redisCache := gcache.NewAdapterRedis(g.Redis())
g.DB().GetCache().SetAdapter(redisCache) g.DB().GetCache().SetAdapter(redisCache)
} }
func LoggingServeLogHandler(ctx context.Context, in *glog.HandlerInput) {
in.Next(ctx)
conf, err := service.SysConfig().GetLoadServeLog(ctx)
if err != nil {
return
}
if !conf.Switch {
return
}
if in.LevelFormat == "" || !gstr.InArray(conf.LevelFormat, in.LevelFormat) {
return
}
var data entity.SysServeLog
data.TraceId = gctx.CtxId(ctx)
data.LevelFormat = in.LevelFormat
data.Content = in.Content
data.Stack = gjson.New(charset.ParseStack(in.Stack))
data.Line = in.CallerPath
data.TriggerNs = in.Time.UnixNano()
data.Status = consts.StatusEnabled
if data.Stack.IsNil() {
data.Stack = gjson.New(consts.NilJsonToString)
}
if gstr.Contains(in.Content, `exception recovered`) {
data.LevelFormat = "PANI"
}
if conf.Queue {
err = queue.Push(consts.QueueServeLogTopic, data)
} else {
err = service.SysServeLog().RealWrite(ctx, data)
}
if err != nil {
g.Log().Printf(ctx, "LoggingServeLogHandler err:%+v", err)
}
}

View File

@ -18,4 +18,6 @@ var (
SysType = runtime.GOOS SysType = runtime.GOOS
// MonitorData 监控数据 // MonitorData 监控数据
MonitorData model.MonitorData MonitorData model.MonitorData
// Blacklists 黑名单列表
Blacklists map[string]struct{}
) )

View File

@ -11,34 +11,53 @@ import (
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr" "github.com/gogf/gf/v2/text/gstr"
"github.com/mojocn/base64Captcha" "github.com/mojocn/base64Captcha"
"image/color"
) )
// GetVerifyImgString 生成验证码 // Generate 生成验证码
func GetVerifyImgString(ctx context.Context) (idKeyC string, base64stringC string) { func Generate(ctx context.Context) (id string, base64 string) {
driver := &base64Captcha.DriverString{ // 字符
Height: 80, //driver := &base64Captcha.DriverString{
Width: 240, // Height: 42,
//NoiseCount: 50, // Width: 100,
//ShowLineOptions: 20, // //NoiseCount: 50,
Length: 4, // //ShowLineOptions: 20,
Source: "abcdefghjkmnpqrstuvwxyz23456789", // Length: 4,
Fonts: []string{"chromohv.ttf"}, // BgColor: &color.RGBA{
// R: 255,
// G: 250,
// B: 250,
// A: 250,
// },
// Source: "0123456789", // abcdefghjkmnpqrstuvwxyz23456789
// Fonts: []string{"chromohv.ttf"},
//}
// 计算
driver := &base64Captcha.DriverMath{
Height: 42,
Width: 100,
NoiseCount: 0,
ShowLineOptions: 0,
BgColor: &color.RGBA{
R: 255,
G: 250,
B: 250,
A: 250,
},
Fonts: []string{"chromohv.ttf"},
} }
driver = driver.ConvertFonts()
store := base64Captcha.DefaultMemStore c := base64Captcha.NewCaptcha(driver.ConvertFonts(), base64Captcha.DefaultMemStore)
c := base64Captcha.NewCaptcha(driver, store) id, base64, err := c.Generate()
idKeyC, base64stringC, err := c.Generate()
if err != nil { if err != nil {
g.Log().Error(ctx, err) g.Log().Errorf(ctx, "captcha.Generate err:%+v", err)
} }
return return
} }
// VerifyString 验证输入的验证码是否正确 // Verify 验证输入的验证码是否正确
func VerifyString(id, answer string) bool { func Verify(id, answer string) bool {
driver := new(base64Captcha.DriverString) c := base64Captcha.NewCaptcha(new(base64Captcha.DriverString), base64Captcha.DefaultMemStore)
store := base64Captcha.DefaultMemStore return c.Verify(id, gstr.ToLower(answer), true)
c := base64Captcha.NewCaptcha(driver, store)
answer = gstr.ToLower(answer)
return c.Verify(id, answer, true)
} }

View File

@ -35,7 +35,7 @@ func SetUser(ctx context.Context, user *model.Identity) {
Get(ctx).User = user Get(ctx).User = user
} }
// SetResponse 设置组件响应 用于全局日志使用 // SetResponse 设置组件响应 用于访问日志使用
func SetResponse(ctx context.Context, response *model.Response) { func SetResponse(ctx context.Context, response *model.Response) {
Get(ctx).Response = response Get(ctx).Response = response
} }

View File

@ -8,10 +8,53 @@ package views
import ( import (
"context" "context"
"fmt"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gstr"
) )
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (data g.Map, err error) { const (
data = make(g.Map) IndexApiImport = " import {%v } from '@/api/%s';"
return IndexIconsImport = " import {%v } from '@vicons/antd';"
)
func (l *gCurd) webIndexTplData(ctx context.Context, in *CurdPreviewInput) (g.Map, error) {
var (
data = make(g.Map)
apiImport = []string{" List"}
iconsImport []string
)
// 添加
if in.options.Step.HasAdd {
iconsImport = append(iconsImport, " PlusOutlined")
}
// 编辑
if in.options.Step.HasEdit {
}
// 导出
if in.options.Step.HasExport {
iconsImport = append(iconsImport, " ExportOutlined")
apiImport = append(apiImport, " Export")
}
// 删除
if in.options.Step.HasDel || in.options.Step.HasBatchDel {
iconsImport = append(iconsImport, " DeleteOutlined")
apiImport = append(apiImport, " Delete")
}
// 导出
if in.options.Step.HasStatus {
apiImport = append(apiImport, " Status")
}
data["apiImport"] = fmt.Sprintf(IndexApiImport, gstr.Implode(",", apiImport), gstr.LcFirst(in.In.VarName))
if len(iconsImport) > 0 {
data["iconsImport"] = fmt.Sprintf(IndexIconsImport, gstr.Implode(",", iconsImport))
}
return data, nil
} }

View File

@ -259,10 +259,10 @@ func (l *gCurd) generateWebModelColumnsEach(buffer *bytes.Buffer, in *CurdPrevie
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s) || !isArray(row.%s)) {\n return ``;\n }\n return row.%s.map((tagKey) => {\n return h(\n NTag,\n {\n style: {\n marginRight: '6px',\n },\n type: getOptionTag(options.value.%s, tagKey),\n bordered: false,\n },\n {\n default: () => getOptionLabel(options.value.%s, tagKey),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, field.TsName, in.options.dictMap[field.TsName], in.options.dictMap[field.TsName]) component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s) || !isArray(row.%s)) {\n return ``;\n }\n return row.%s.map((tagKey) => {\n return h(\n NTag,\n {\n style: {\n marginRight: '6px',\n },\n type: getOptionTag(options.value.%s, tagKey),\n bordered: false,\n },\n {\n default: () => getOptionLabel(options.value.%s, tagKey),\n }\n );\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, field.TsName, in.options.dictMap[field.TsName], in.options.dictMap[field.TsName])
case FormModeUploadImage: case FormModeUploadImage:
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n width: 32,\n height: 32,\n src: row.%s,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n },\n });\n },\n },\n", field.Dc, field.TsName, "NImage", field.TsName) component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n return h(%s, {\n width: 32,\n height: 32,\n src: row.%s,\n onError: errorImg,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n },\n });\n },\n },\n", field.Dc, field.TsName, "NImage", field.TsName)
case FormModeUploadImages: case FormModeUploadImages:
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((image) => {\n return h(%s, {\n width: 32,\n height: 32,\n src: image,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n 'margin-left': '2px',\n },\n });\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NImage") component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (isNullObject(row.%s)) {\n return ``;\n }\n return row.%s.map((image) => {\n return h(%s, {\n width: 32,\n height: 32,\n src: image,\n onError: errorImg,\n style: {\n width: '32px',\n height: '32px',\n 'max-width': '100%%',\n 'max-height': '100%%',\n 'margin-left': '2px',\n },\n });\n });\n },\n },\n", field.Dc, field.TsName, field.TsName, field.TsName, "NImage")
case FormModeUploadFile: case FormModeUploadFile:
component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (row.%s === '') {\n return ``;\n }\n return h(\n %s,\n {\n size: 'small',\n },\n {\n default: () => getFileExt(row.%s),\n }\n );\n },\n },\n", field.Dc, field.TsName, field.TsName, "NAvatar", field.TsName) component = fmt.Sprintf(" {\n title: '%s',\n key: '%s',\n render(row) {\n if (row.%s === '') {\n return ``;\n }\n return h(\n %s,\n {\n size: 'small',\n },\n {\n default: () => getFileExt(row.%s),\n }\n );\n },\n },\n", field.Dc, field.TsName, field.TsName, "NAvatar", field.TsName)

View File

@ -208,7 +208,7 @@ func IsUnique(ctx context.Context, dao interface{}, where g.Map, message string,
// GenSubTree 生成下级关系树 // GenSubTree 生成下级关系树
func GenSubTree(ctx context.Context, dao interface{}, oldPid int64) (newPid int64, newLevel int, subTree string, err error) { func GenSubTree(ctx context.Context, dao interface{}, oldPid int64) (newPid int64, newLevel int, subTree string, err error) {
// 顶级树 // 顶级树
if oldPid == 0 { if oldPid <= 0 {
return 0, 1, "", nil return 0, 1, "", nil
} }
@ -221,7 +221,7 @@ func GenSubTree(ctx context.Context, dao interface{}, oldPid int64) (newPid int6
return 0, 0, "", err return 0, 0, "", err
} }
models, err := d.Ctx(ctx).WhereNot(field, oldPid).One() models, err := d.Ctx(ctx).Where(field, oldPid).One()
if err != nil { if err != nil {
return 0, 0, "", err return 0, 0, "", err
} }

View File

@ -15,6 +15,7 @@ import (
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/library/contexts" "hotgo/internal/library/contexts"
"hotgo/internal/model/entity" "hotgo/internal/model/entity"
"hotgo/utility/tree"
) )
// HandlerFilterAuth 过滤数据权限 // HandlerFilterAuth 过滤数据权限
@ -23,7 +24,7 @@ func HandlerFilterAuth(m *gdb.Model) *gdb.Model {
var ( var (
needAuth bool needAuth bool
filterField string filterField string
roleModel *entity.AdminRole role *entity.AdminRole
ctx = m.GetCtx() ctx = m.GetCtx()
fields = escapeFieldsToSlice(m.GetFieldsStr()) fields = escapeFieldsToSlice(m.GetFieldsStr())
co = contexts.Get(ctx) co = contexts.Get(ctx)
@ -48,34 +49,35 @@ func HandlerFilterAuth(m *gdb.Model) *gdb.Model {
return m return m
} }
err := g.Model("admin_role").Where("id", co.User.RoleId).Scan(&roleModel) err := g.Model("admin_role").Where("id", co.User.RoleId).Scan(&role)
if err != nil { if err != nil {
panic(fmt.Sprintf("HandlerFilterAuth Failed to role information err:%+v", err)) panic(fmt.Sprintf("failed to role information err:%+v", err))
} }
if roleModel == nil { if role == nil {
panic(fmt.Sprintf("HandlerFilterAuth Failed to role information err2:%+v", err)) panic("failed to role information roleModel == nil")
} }
// TODO 当前不是完整功能,预计在下个版本中完善 sq := g.Model("admin_member").Fields("id")
switch roleModel.DataScope {
switch role.DataScope {
case consts.RoleDataAll: // 全部权限 case consts.RoleDataAll: // 全部权限
// ... // ...
case consts.RoleDataNowDept: // 当前部门 case consts.RoleDataNowDept: // 当前部门
m = m.Where(filterField, co.User.DeptId) m = m.WhereIn(filterField, sq.Where("dept_id", co.User.DeptId))
case consts.RoleDataDeptAndSub: // 当前部门及以下部门 case consts.RoleDataDeptAndSub: // 当前部门及以下部门
//m = m.Where(filterField, 1) m = m.WhereIn(filterField, sq.WhereIn("dept_id", GetDeptAndSub(co.User.DeptId)))
case consts.RoleDataDeptCustom: // 自定义部门 case consts.RoleDataDeptCustom: // 自定义部门
m = m.WhereIn(filterField, roleModel.CustomDept.Var().Ints()) m = m.WhereIn(filterField, sq.WhereIn("dept_id", role.CustomDept.Var().Ints()))
case consts.RoleDataSelf: // 仅自己 case consts.RoleDataSelf: // 仅自己
m = m.Where(filterField, co.User.Id) m = m.Where(filterField, co.User.Id)
case consts.RoleDataSelfAndSub: // 自己和直属下级 case consts.RoleDataSelfAndSub: // 自己和直属下级
//m = m.Where(filterField, 1) m = m.WhereIn(filterField, GetSelfAndSub(co.User.Id))
case consts.RoleDataSelfAndAllSub: // 自己和全部下级 case consts.RoleDataSelfAndAllSub: // 自己和全部下级
//m = m.Where(filterField, 1) m = m.WhereIn(filterField, GetSelfAndAllSub(co.User.Id))
default: default:
panic("HandlerFilterAuth dataScope is not registered") panic("dataScope is not registered")
} }
return m return m
@ -90,3 +92,57 @@ func HandlerForceCache(m *gdb.Model) *gdb.Model {
func escapeFieldsToSlice(s string) []string { func escapeFieldsToSlice(s string) []string {
return gstr.Explode(",", gstr.Replace(gstr.Replace(s, "`,`", ","), "`", "")) return gstr.Explode(",", gstr.Replace(gstr.Replace(s, "`,`", ","), "`", ""))
} }
// GetDeptAndSub 获取指定部门的所有下级,含本部门
func GetDeptAndSub(deptId int64) (ids []int64) {
array, err := g.Model("admin_dept").
WhereLike("tree", "%"+tree.GetIdLabel(deptId)+"%").
Fields("id").
Array()
if err != nil {
return
}
for _, v := range array {
ids = append(ids, v.Int64())
}
ids = append(ids, deptId)
return
}
// GetSelfAndSub 获取直属下级,包含自己
func GetSelfAndSub(memberId int64) (ids []int64) {
array, err := g.Model("admin_member").
Where("pid", memberId).
Fields("id").
Array()
if err != nil {
return
}
for _, v := range array {
ids = append(ids, v.Int64())
}
ids = append(ids, memberId)
return
}
// GetSelfAndAllSub 获取全部下级,包含自己
func GetSelfAndAllSub(memberId int64) (ids []int64) {
array, err := g.Model("admin_member").
WhereLike("tree", "%"+tree.GetIdLabel(memberId)+"%").
Fields("id").
Array()
if err != nil {
return
}
for _, v := range array {
ids = append(ids, v.Int64())
}
ids = append(ids, memberId)
return
}

View File

@ -23,7 +23,7 @@ import (
) )
// GenerateLoginToken 为指定用户生成token // GenerateLoginToken 为指定用户生成token
func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh bool) (interface{}, error) { func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh bool) (string, error) {
var ( var (
jwtVersion = g.Cfg().MustGet(ctx, "jwt.version", "1.0") jwtVersion = g.Cfg().MustGet(ctx, "jwt.version", "1.0")
jwtSign = g.Cfg().MustGet(ctx, "jwt.sign", "hotGo") jwtSign = g.Cfg().MustGet(ctx, "jwt.sign", "hotGo")
@ -51,7 +51,7 @@ func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh boo
tokenString, err := token.SignedString(jwtSign.Bytes()) tokenString, err := token.SignedString(jwtSign.Bytes())
if err != nil { if err != nil {
return nil, gerror.New(err.Error()) return "", err
} }
var ( var (
@ -65,12 +65,12 @@ func GenerateLoginToken(ctx context.Context, user *model.Identity, isRefresh boo
err = c.Set(ctx, key, tokenString, expires) err = c.Set(ctx, key, tokenString, expires)
if err != nil { if err != nil {
return nil, gerror.New(err.Error()) return "", err
} }
err = c.Set(ctx, consts.RedisJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires) err = c.Set(ctx, consts.RedisJwtUserBind+user.App+":"+gconv.String(user.Id), key, expires)
if err != nil { if err != nil {
return nil, gerror.New(err.Error()) return "", err
} }
return tokenString, err return tokenString, err
} }

View File

@ -144,6 +144,11 @@ func GetPublicIP(ctx context.Context) (ip string, err error) {
g.Log().Warningf(ctx, "GetPublicIP alternatives are being tried err:%+v", err) g.Log().Warningf(ctx, "GetPublicIP alternatives are being tried err:%+v", err)
return GetPublicIP2() return GetPublicIP2()
} }
if data == nil {
g.Log().Warningf(ctx, "publicIP address Parsing failure, check the network and firewall blocking.")
return "0.0.0.0", nil
}
return data.Ip, nil return data.Ip, nil
} }
@ -190,5 +195,10 @@ func GetClientIp(r *ghttp.Request) string {
if ip == "" { if ip == "" {
ip = r.GetClientIp() ip = r.GetClientIp()
} }
// 如果存在多个,默认取第一个
if gstr.Contains(ip, ",") {
ip = gstr.TrimStr(ip, ",", -1)
}
return ip return ip
} }

View File

@ -93,7 +93,7 @@ func InstanceProducer() (mqClient MqProducer, err error) {
return NewProducer(config.GroupName) return NewProducer(config.GroupName)
} }
// NewProducer 新建一个生产者实例 // NewProducer 初始化生产者实例
func NewProducer(groupName string) (mqClient MqProducer, err error) { func NewProducer(groupName string) (mqClient MqProducer, err error) {
if item, ok := mqProducerInstanceMap[groupName]; ok { if item, ok := mqProducerInstanceMap[groupName]; ok {
return item, nil return item, nil
@ -143,7 +143,7 @@ func NewProducer(groupName string) (mqClient MqProducer, err error) {
return mqClient, nil return mqClient, nil
} }
// NewConsumer 新建一个消费者实例 // NewConsumer 初始化消费者实例
func NewConsumer(groupName string) (mqClient MqConsumer, err error) { func NewConsumer(groupName string) (mqClient MqConsumer, err error) {
randTag := string(charset.RandomCreateBytes(6)) randTag := string(charset.RandomCreateBytes(6))

View File

@ -87,30 +87,28 @@ func (r *KafkaMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
go func() {
for { for {
if err := r.consumerIns.Consume(ctx, []string{topic}, &consumer); err != nil { if err := r.consumerIns.Consume(ctx, []string{topic}, &consumer); err != nil {
FatalLog(ctx, "kafka Error from consumer", err) g.Log().Fatalf(ctx, "kafka Error from consumer, err%+v", err)
} }
if ctx.Err() != nil { if ctx.Err() != nil {
Log(ctx, fmt.Sprintf("kafka consoumer stop : %v", ctx.Err())) g.Log().Debugf(ctx, fmt.Sprintf("kafka consoumer stop : %v", ctx.Err()))
return return
} }
consumer.ready = make(chan bool) consumer.ready = make(chan bool)
} }
}() }(ctx)
<-consumer.ready // Await till the consumer has been set up <-consumer.ready // Await till the consumer has been set up
Log(ctx, "kafka consumer up and running!...") g.Log().Debug(ctx, "kafka consumer up and running!...")
signal.AppDefer(func() { signal.AppDefer(func() {
Log(ctx, "kafka consumer close...") g.Log().Debug(ctx, "kafka consumer close...")
cancel() cancel()
if err = r.consumerIns.Close(); err != nil { if err = r.consumerIns.Close(); err != nil {
FatalLog(ctx, "kafka Error closing client", err) g.Log().Fatalf(ctx, "kafka Error closing client, err:%+v", err)
} }
}) })
@ -193,7 +191,7 @@ func RegisterKafkaProducer(connOpt KafkaConfig, mqIns *KafkaMq) {
} }
signal.AppDefer(func() { signal.AppDefer(func() {
Log(ctx, "kafka producer AsyncClose...") g.Log().Debug(ctx, "kafka producer AsyncClose...")
mqIns.producerIns.AsyncClose() mqIns.producerIns.AsyncClose()
}) })
} }

View File

@ -10,33 +10,28 @@ import (
"context" "context"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts" "hotgo/utility/charset"
)
const (
ConsumerLogErrFormat = "消费 [%s] 失败, mqMsgId:%+v, mqMsgData:%+v, err:%+v, stack:%+v"
ProducerLogErrFormat = "生产 [%s] 失败, data:%+v, err:%+v, stack:%+v"
) )
// ConsumerLog 消费日志 // ConsumerLog 消费日志
func ConsumerLog(ctx context.Context, topic string, mqMsg MqMsg, err error) { func ConsumerLog(ctx context.Context, topic string, mqMsg MqMsg, err error) {
if err != nil { if err != nil {
g.Log(consts.QueueLogPath).Error(ctx, "消费 ["+topic+"] 失败", mqMsg, err) g.Log().Printf(ctx, ConsumerLogErrFormat, topic, mqMsg.MsgId, mqMsg.BodyString(), err, charset.ParseErrStack(err))
} else { } else {
g.Log(consts.QueueLogPath).Debug(ctx, "消费 ["+topic+"] 成功", mqMsg.MsgId) g.Log().Print(ctx, "消费 ["+topic+"] 成功", mqMsg.MsgId)
} }
} }
// ProducerLog 生产日志 // ProducerLog 生产日志
func ProducerLog(ctx context.Context, topic string, data interface{}, err error) { func ProducerLog(ctx context.Context, topic string, data interface{}, err error) {
if err != nil { if err != nil {
g.Log(consts.QueueLogPath).Error(ctx, "生产 ["+topic+"] 失败", gconv.String(data)) g.Log().Printf(ctx, ProducerLogErrFormat, topic, gconv.String(data), err, charset.ParseErrStack(err))
} else { } else {
g.Log(consts.QueueLogPath).Debug(ctx, "生产 ["+topic+"] 成功", gconv.String(data)) g.Log().Print(ctx, "生产 ["+topic+"] 成功", gconv.String(data))
} }
} }
// FatalLog 致命日志
func FatalLog(ctx context.Context, text string, err error) {
g.Log(consts.QueueLogPath).Fatal(ctx, text+":", err)
}
// Log 通用日志
func Log(ctx context.Context, text string) {
g.Log(consts.QueueLogPath).Debug(ctx, text)
}

View File

@ -0,0 +1,18 @@
package queue
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/util/gconv"
)
// Push 推送队列
func Push(topic string, data interface{}) (err error) {
q, err := InstanceProducer()
if err != nil {
g.Log().Fatalf(ctx, "queue.InstanceProducer err:%+v", err)
return err
}
mqMsg, err := q.SendMsg(topic, gconv.String(data))
ProducerLog(ctx, topic, mqMsg.MsgId, err)
return err
}

View File

@ -7,7 +7,6 @@ import (
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gomodule/redigo/redis" "github.com/gomodule/redigo/redis"
"hotgo/internal/consts"
"hotgo/utility/encrypt" "hotgo/utility/encrypt"
"math/rand" "math/rand"
"time" "time"
@ -113,7 +112,7 @@ func (r *RedisMq) ListenReceiveMsgDo(topic string, receiveDo func(mqMsg MqMsg))
// 生成队列名称 // 生成队列名称
func (r *RedisMq) genQueueName(groupName string, topic string) string { func (r *RedisMq) genQueueName(groupName string, topic string) string {
return fmt.Sprintf(consts.QueueName+"%s_%s", groupName, topic) return fmt.Sprintf("queue:%s_%s", groupName, topic)
} }
func (r *RedisMq) loopReadQueue(queueName string) (mqMsgList []MqMsg) { func (r *RedisMq) loopReadQueue(queueName string) (mqMsgList []MqMsg) {

View File

@ -26,8 +26,8 @@ type RocketMq struct {
// rewriteLog 重写日志 // rewriteLog 重写日志
func rewriteLog() { func rewriteLog() {
level := g.Cfg().MustGet(ctx, "queue.rocketmq.logLevel", "debug") level := g.Cfg().MustGet(ctx, "queue.rocketmq.logLevel", "debug").String()
rlog.SetLogger(&RocketMqLogger{Flag: "[rocket_mq]", LevelLog: level.String()}) rlog.SetLogger(&RocketMqLogger{Flag: "[rocket_mq]", LevelLog: level})
} }
// RegisterRocketProducerMust 注册并启动生产者接口实现 // RegisterRocketProducerMust 注册并启动生产者接口实现

View File

@ -7,7 +7,7 @@
package queue package queue
import ( import (
"fmt" "github.com/gogf/gf/v2/frame/g"
) )
type RocketMqLogger struct { type RocketMqLogger struct {
@ -24,16 +24,16 @@ func (l *RocketMqLogger) Debug(msg string, fields map[string]interface{}) {
} }
if l.LevelLog == "debug" || l.LevelLog == "all" { if l.LevelLog == "debug" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [debug] ", msg)) g.Log().Debug(ctx, msg)
} }
} }
func (l *RocketMqLogger) Level(level string) { func (l *RocketMqLogger) Level(level string) {
Log(ctx, fmt.Sprint(l.Flag, " [level] ", level)) g.Log().Info(ctx, level)
} }
func (l *RocketMqLogger) OutputPath(path string) (err error) { func (l *RocketMqLogger) OutputPath(path string) (err error) {
Log(ctx, fmt.Sprint(l.Flag, " [path] ", path)) g.Log().Info(ctx, path)
return nil return nil
} }
@ -46,7 +46,7 @@ func (l *RocketMqLogger) Info(msg string, fields map[string]interface{}) {
} }
if l.LevelLog == "info" || l.LevelLog == "all" { if l.LevelLog == "info" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [info] ", msg)) g.Log().Info(ctx, msg)
} }
} }
@ -59,7 +59,7 @@ func (l *RocketMqLogger) Warning(msg string, fields map[string]interface{}) {
} }
if l.LevelLog == "warn" || l.LevelLog == "all" { if l.LevelLog == "warn" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [warn] ", msg)) g.Log().Warning(ctx, msg)
} }
} }
@ -71,7 +71,7 @@ func (l *RocketMqLogger) Error(msg string, fields map[string]interface{}) {
return return
} }
if l.LevelLog == "error" || l.LevelLog == "all" { if l.LevelLog == "error" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [error] ", msg)) g.Log().Error(ctx, msg)
} }
} }
@ -84,6 +84,6 @@ func (l *RocketMqLogger) Fatal(msg string, fields map[string]interface{}) {
} }
if l.LevelLog == "fatal" || l.LevelLog == "all" { if l.LevelLog == "fatal" || l.LevelLog == "all" {
Log(ctx, fmt.Sprint(l.Flag, " [fatal] ", msg)) g.Log().Fatal(ctx, msg)
} }
} }

View File

@ -0,0 +1,112 @@
package aliyun
import (
"context"
"fmt"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
"hotgo/internal/model"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
)
// SendCode 发送验证码
func SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) {
if config == nil {
config, err = service.SysConfig().GetSms(ctx)
if err != nil {
return err
}
}
client, err := CreateClient(tea.String(config.SmsAliyunAccessKeyID), tea.String(config.SmsAliyunAccessKeySecret))
if err != nil {
return err
}
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
PhoneNumbers: tea.String(in.Mobile),
SignName: tea.String(config.SmsAliyunSign),
TemplateCode: tea.String(in.Template),
TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%v\"}", in.Code)),
}
tryErr := func() (_e error) {
defer func() {
if r := tea.Recover(recover()); r != nil {
_e = r
}
}()
// 复制代码运行请自行打印 API 的返回值
_, err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{})
if err != nil {
return err
}
return nil
}()
return tryErr
}
// CreateClient 使用AK&SK初始化账号Client
func CreateClient(accessKeyId *string, accessKeySecret *string) (_result *dysmsapi20170525.Client, _err error) {
config := &openapi.Config{
// 必填,您的 AccessKey ID
AccessKeyId: accessKeyId,
// 必填,您的 AccessKey Secret
AccessKeySecret: accessKeySecret,
}
// 访问的域名
config.Endpoint = tea.String("dysmsapi.aliyuncs.com")
_result = &dysmsapi20170525.Client{}
_result, _err = dysmsapi20170525.NewClient(config)
return _result, _err
}
func Send(accessKeyId string, accessKeySecret string) (_err error) {
// 工程代码泄露可能会导致AccessKey泄露并威胁账号下所有资源的安全性。以下代码示例仅供参考建议使用更安全的 STS 方式更多鉴权访问方式请参见https://help.aliyun.com/document_detail/378661.html
client, _err := CreateClient(tea.String(accessKeyId), tea.String(accessKeySecret))
if _err != nil {
return _err
}
sendSmsRequest := &dysmsapi20170525.SendSmsRequest{
PhoneNumbers: tea.String("15303830571"),
SignName: tea.String("布帆云"),
TemplateCode: tea.String("SMS_198921686"),
TemplateParam: tea.String("{\"code\":\"1234\"}"),
}
runtime := &util.RuntimeOptions{}
tryErr := func() (_e error) {
defer func() {
if r := tea.Recover(recover()); r != nil {
_e = r
}
}()
// 复制代码运行请自行打印 API 的返回值
_, _err = client.SendSmsWithOptions(sendSmsRequest, runtime)
if _err != nil {
return _err
}
return nil
}()
if tryErr != nil {
var err = &tea.SDKError{}
if _t, ok := tryErr.(*tea.SDKError); ok {
err = _t
} else {
err.Message = tea.String(tryErr.Error())
}
// 如有需要,请打印 error
_, _err = util.AssertAsString(err.Message)
if _err != nil {
return _err
}
}
return _err
}

View File

@ -0,0 +1 @@
package aliyun

View File

@ -0,0 +1 @@
package aliyun

View File

@ -0,0 +1,2 @@
package sms

View File

@ -9,11 +9,11 @@ package admin
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv" "github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/model/entity" "hotgo/internal/model/entity"
"hotgo/internal/model/input/adminin" "hotgo/internal/model/input/adminin"
"hotgo/internal/service" "hotgo/internal/service"
@ -47,8 +47,30 @@ func (s *sAdminDept) NameUnique(ctx context.Context, in adminin.DeptNameUniqueIn
} }
// Delete 删除 // Delete 删除
func (s *sAdminDept) Delete(ctx context.Context, in adminin.DeptDeleteInp) error { func (s *sAdminDept) Delete(ctx context.Context, in adminin.DeptDeleteInp) (err error) {
_, err := dao.AdminDept.Ctx(ctx).Where("id", in.Id).Delete()
var (
models *entity.AdminDept
)
err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Scan(&models)
if err != nil {
return err
}
if models == nil {
return gerror.New("数据不存在或已删除!")
}
pidExist, err := dao.AdminDept.Ctx(ctx).Where("pid", models.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !pidExist.IsEmpty() {
return gerror.New("请先删除该部门下得所有子级!")
}
_, err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return err
@ -75,8 +97,12 @@ func (s *sAdminDept) Edit(ctx context.Context, in adminin.DeptEditInp) (err erro
return err return err
} }
in.Pid, in.Level, in.Tree, err = hgorm.GenSubTree(ctx, dao.AdminDept, in.Pid)
if err != nil {
return err
}
// 修改 // 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 { if in.Id > 0 {
_, err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Data(in).Update() _, err = dao.AdminDept.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil { if err != nil {
@ -88,7 +114,6 @@ func (s *sAdminDept) Edit(ctx context.Context, in adminin.DeptEditInp) (err erro
} }
// 新增 // 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminDept.Ctx(ctx).Data(in).Insert() _, err = dao.AdminDept.Ctx(ctx).Data(in).Insert()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -156,11 +181,10 @@ func (s *sAdminDept) View(ctx context.Context, in adminin.DeptViewInp) (res *adm
// List 获取列表 // List 获取列表
func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (list adminin.DeptListModel, err error) { func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (list adminin.DeptListModel, err error) {
var ( var (
mod = dao.AdminDept.Ctx(ctx) mod = dao.AdminDept.Ctx(ctx)
models []*entity.AdminDept models []*entity.AdminDept
ids []int64 ids []int64
pids []int64 pids []int64
deptList []g.Map
) )
// 部门名称 // 部门名称
@ -207,25 +231,14 @@ func (s *sAdminDept) List(ctx context.Context, in adminin.DeptListInp) (list adm
return list, err return list, err
} }
for i := 0; i < len(models); i++ { list = gconv.SliceMap(models)
deptList = append(deptList, g.Map{ for k, v := range list {
"index": models[i].Id, list[k]["index"] = v["id"]
"key": models[i].Id, list[k]["key"] = v["id"]
"label": models[i].Name, list[k]["label"] = v["name"]
"id": models[i].Id,
"pid": models[i].Pid,
"name": models[i].Name,
"code": models[i].Code,
"leader": models[i].Leader,
"phone": models[i].Phone,
"email": models[i].Email,
"sort": models[i].Sort,
"created_at": models[i].CreatedAt,
"status": models[i].Status,
})
} }
return tree.GenTree(deptList), nil return tree.GenTree(list), nil
} }
type DeptTree struct { type DeptTree struct {

View File

@ -9,6 +9,7 @@ package admin
import ( import (
"context" "context"
"github.com/gogf/gf/v2/crypto/gmd5" "github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/ghttp"
@ -20,11 +21,13 @@ import (
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/library/contexts" "hotgo/internal/library/contexts"
"hotgo/internal/library/jwt" "hotgo/internal/library/jwt"
"hotgo/internal/library/location"
"hotgo/internal/model" "hotgo/internal/model"
"hotgo/internal/model/do" "hotgo/internal/model/do"
"hotgo/internal/model/entity" "hotgo/internal/model/entity"
"hotgo/internal/model/input/adminin" "hotgo/internal/model/input/adminin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/encrypt"
"hotgo/utility/tree" "hotgo/utility/tree"
"hotgo/utility/validate" "hotgo/utility/validate"
) )
@ -441,7 +444,12 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
roleInfo *entity.AdminRole roleInfo *entity.AdminRole
memberInfo *entity.AdminMember memberInfo *entity.AdminMember
identity *model.Identity identity *model.Identity
timestamp = gtime.Timestamp()
expires = g.Cfg().MustGet(ctx, "jwt.expires", 1).Int64()
exp = gconv.Int64(timestamp) + expires
lastIp = location.GetClientIp(ghttp.RequestFromCtx(ctx))
) )
err = dao.AdminMember.Ctx(ctx).Where("username", in.Username).Scan(&memberInfo) err = dao.AdminMember.Ctx(ctx).Where("username", in.Username).Scan(&memberInfo)
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -457,16 +465,21 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
return return
} }
if memberInfo.PasswordHash != gmd5.MustEncryptString(in.Password+memberInfo.Salt) { // 解密密码
password, err := gbase64.Decode([]byte(in.Password))
if err != nil {
return nil, err
}
password, err = encrypt.AesECBDecrypt(password, consts.RequestEncryptKey)
if err != nil {
return nil, err
}
if memberInfo.PasswordHash != gmd5.MustEncryptString(string(password)+memberInfo.Salt) {
err = gerror.New("用户密码不正确") err = gerror.New("用户密码不正确")
return return
} }
//// 默认设备
//if in.Device != consts.AppAdmin && in.Device != consts.AppApi {
// in.Device = consts.AppAdmin
//}
err = dao.AdminRole.Ctx(ctx). err = dao.AdminRole.Ctx(ctx).
Fields("id,key,status"). Fields("id,key,status").
Where("id", memberInfo.RoleId). Where("id", memberInfo.RoleId).
@ -485,12 +498,6 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
return return
} }
// 有效期
expires := g.Cfg().MustGet(ctx, "jwt.expires", 1).Int64()
// 过期时间戳
exp := gconv.Int64(gtime.Timestamp()) + expires
identity = &model.Identity{ identity = &model.Identity{
Id: memberInfo.Id, Id: memberInfo.Id,
Pid: memberInfo.Pid, Pid: memberInfo.Pid,
@ -504,7 +511,7 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
Mobile: memberInfo.Mobile, Mobile: memberInfo.Mobile,
VisitCount: memberInfo.VisitCount, VisitCount: memberInfo.VisitCount,
LastTime: memberInfo.LastTime, LastTime: memberInfo.LastTime,
LastIp: memberInfo.LastIp, LastIp: lastIp,
Exp: exp, Exp: exp,
Expires: expires, Expires: expires,
App: consts.AppAdmin, App: consts.AppAdmin,
@ -517,13 +524,11 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
} }
// 更新登录信息 // 更新登录信息
authKey := gmd5.MustEncryptString(gconv.String(token))
_, err = dao.AdminMember.Ctx(ctx).Data(do.AdminMember{ _, err = dao.AdminMember.Ctx(ctx).Data(do.AdminMember{
AuthKey: gmd5.MustEncryptString(authKey), AuthKey: gmd5.MustEncryptString(token),
VisitCount: memberInfo.VisitCount + 1, VisitCount: memberInfo.VisitCount + 1,
LastTime: gtime.Timestamp(), LastTime: timestamp,
LastIp: ghttp.RequestFromCtx(ctx).GetClientIp(), LastIp: lastIp,
}).Where(do.AdminMember{ }).Where(do.AdminMember{
Id: memberInfo.Id, Id: memberInfo.Id,
}).Update() }).Update()
@ -538,7 +543,7 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
Username: identity.Username, Username: identity.Username,
RealName: identity.RealName, RealName: identity.RealName,
Avatar: identity.Avatar, Avatar: identity.Avatar,
Token: gconv.String(token), Token: token,
} }
return res, nil return res, nil

View File

@ -78,7 +78,6 @@ func (s *sAdminPost) Edit(ctx context.Context, in adminin.PostEditInp) (err erro
} }
// 修改 // 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 { if in.Id > 0 {
_, err = dao.AdminPost.Ctx(ctx).Where("id", in.Id).Data(in).Update() _, err = dao.AdminPost.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil { if err != nil {
@ -90,7 +89,6 @@ func (s *sAdminPost) Edit(ctx context.Context, in adminin.PostEditInp) (err erro
} }
// 新增 // 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminPost.Ctx(ctx).Data(in).Insert() _, err = dao.AdminPost.Ctx(ctx).Data(in).Insert()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -181,7 +179,7 @@ func (s *sAdminPost) List(ctx context.Context, in adminin.PostListInp) (list []*
return list, totalCount, nil return list, totalCount, nil
} }
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil { if err = mod.Page(in.Page, in.PerPage).Order("id asc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err return list, totalCount, err
} }

View File

@ -12,7 +12,7 @@ import (
"github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv"
"hotgo/api/backend/role" "hotgo/api/backend/role"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
@ -25,6 +25,7 @@ import (
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/auth" "hotgo/utility/auth"
"hotgo/utility/convert" "hotgo/utility/convert"
"hotgo/utility/tree"
"sort" "sort"
) )
@ -67,21 +68,25 @@ func (s *sAdminRole) Verify(ctx context.Context, path, method string) bool {
} }
// List 获取列表 // List 获取列表
func (s *sAdminRole) List(ctx context.Context, in adminin.RoleListInp) (list []*adminin.RoleListModel, totalCount int, err error) { func (s *sAdminRole) List(ctx context.Context, in adminin.RoleListInp) (list []g.Map, totalCount int, err error) {
mod := dao.AdminRole.Ctx(ctx) var (
mod = dao.AdminRole.Ctx(ctx)
models []*adminin.RoleListModel
)
totalCount, err = mod.Count() totalCount, err = mod.Count()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err return list, totalCount, err
} }
err = mod.Page(in.Page, in.PerPage).Order("id asc").Scan(&list) err = mod.Page(in.Page, in.PerPage).Order("id asc").Scan(&models)
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err return list, totalCount, err
} }
return list, totalCount, err return tree.GenTree(gconv.SliceMap(models)), totalCount, err
} }
// GetName 获取指定角色的名称 // GetName 获取指定角色的名称
@ -197,7 +202,6 @@ func (s *sAdminRole) Edit(ctx context.Context, in *role.EditReq) (err error) {
} }
// 修改 // 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 { if in.Id > 0 {
_, err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Data(in).Update() _, err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil { if err != nil {
@ -209,7 +213,6 @@ func (s *sAdminRole) Edit(ctx context.Context, in *role.EditReq) (err error) {
} }
// 新增 // 新增
in.CreatedAt = gtime.Now()
_, err = dao.AdminRole.Ctx(ctx).Data(in).Insert() _, err = dao.AdminRole.Ctx(ctx).Data(in).Insert()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -222,6 +225,28 @@ func (s *sAdminRole) Delete(ctx context.Context, in *role.DeleteReq) (err error)
if in.Id <= 0 { if in.Id <= 0 {
return gerror.New("ID不正确") return gerror.New("ID不正确")
} }
var (
models *entity.AdminRole
)
err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Scan(&models)
if err != nil {
return err
}
if models == nil {
return gerror.New("数据不存在或已删除!")
}
pidExist, err := dao.AdminRole.Ctx(ctx).Where("pid", models.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !pidExist.IsEmpty() {
return gerror.New("请先删除该角色下得所有子级!")
}
_, err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Delete() _, err = dao.AdminRole.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)

View File

@ -14,7 +14,7 @@ import (
"hotgo/internal/service" "hotgo/internal/service"
) )
// GlobalLog 全局日志 // GlobalLog 访问日志
func (s *sHook) GlobalLog(r *ghttp.Request) { func (s *sHook) GlobalLog(r *ghttp.Request) {
var ( var (
ctx = r.Context() ctx = r.Context()

View File

@ -37,7 +37,8 @@ func New() *sMiddleware {
return &sMiddleware{ return &sMiddleware{
LoginUrl: "/common", LoginUrl: "/common",
DemoWhiteList: g.Map{ DemoWhiteList: g.Map{
"/admin/site/login": struct{}{}, // 后台登录 "/admin/site/login": struct{}{}, // 后台登录
"/admin/genCodes/preview": struct{}{}, // 预览代码
}, },
} }
} }

View File

@ -0,0 +1,23 @@
package middleware
import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"hotgo/internal/global"
"hotgo/internal/library/location"
"hotgo/internal/library/response"
)
// Blacklist IP黑名单限制中间件
func (s *sMiddleware) Blacklist(r *ghttp.Request) {
if global.Blacklists != nil {
if _, ok := global.Blacklists[location.GetClientIp(r)]; ok {
response.JsonExit(r, gcode.CodeServerBusy.Code(), "请求异常,已被封禁,如有疑问请联系管理员!")
}
} else {
g.Log().Warningf(r.Context(), "blacklists uninitialized")
}
r.Middleware.Next()
}

View File

@ -42,14 +42,14 @@ func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
if err = r.GetError(); err != nil { if err = r.GetError(); err != nil {
// 记录到自定义错误日志文件 // 记录到自定义错误日志文件
g.Log("exception").Print(ctx, "exception:", err) g.Log().Warningf(ctx, "exception:%v", err)
code = gerror.Code(err).Code() code = gerror.Code(err).Code()
message = err.Error() message = err.Error()
// 是否输出错误到页面 // 是否输出错误到页面
if g.Cfg().MustGet(ctx, "hotgo.debug", true).Bool() { if g.Cfg().MustGet(ctx, "hotgo.debug", true).Bool() {
data = charset.GetStack(err) data = charset.ParseErrStack(err)
} }
} else { } else {
data = r.GetHandlerResponse() data = r.GetHandlerResponse()

View File

@ -9,9 +9,13 @@ package sys
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/global"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/validate" "hotgo/utility/validate"
@ -28,8 +32,9 @@ func init() {
} }
// Delete 删除 // Delete 删除
func (s *sSysBlacklist) Delete(ctx context.Context, in sysin.BlacklistDeleteInp) error { func (s *sSysBlacklist) Delete(ctx context.Context, in sysin.BlacklistDeleteInp) (err error) {
_, err := dao.SysBlacklist.Ctx(ctx).Where("id", in.Id).Delete() defer s.VariableLoad(ctx, err)
_, err = dao.SysBlacklist.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return err
@ -40,6 +45,7 @@ func (s *sSysBlacklist) Delete(ctx context.Context, in sysin.BlacklistDeleteInp)
// Edit 修改/新增 // Edit 修改/新增
func (s *sSysBlacklist) Edit(ctx context.Context, in sysin.BlacklistEditInp) (err error) { func (s *sSysBlacklist) Edit(ctx context.Context, in sysin.BlacklistEditInp) (err error) {
defer s.VariableLoad(ctx, err)
if in.Ip == "" { if in.Ip == "" {
err = gerror.New("ip不能为空") err = gerror.New("ip不能为空")
return err return err
@ -69,6 +75,7 @@ func (s *sSysBlacklist) Edit(ctx context.Context, in sysin.BlacklistEditInp) (er
// Status 更新部门状态 // Status 更新部门状态
func (s *sSysBlacklist) Status(ctx context.Context, in sysin.BlacklistStatusInp) (err error) { func (s *sSysBlacklist) Status(ctx context.Context, in sysin.BlacklistStatusInp) (err error) {
defer s.VariableLoad(ctx, err)
if in.Id <= 0 { if in.Id <= 0 {
err = gerror.New("ID不能为空") err = gerror.New("ID不能为空")
return err return err
@ -148,3 +155,112 @@ func (s *sSysBlacklist) List(ctx context.Context, in sysin.BlacklistListInp) (li
return list, totalCount, err return list, totalCount, err
} }
// VariableLoad 变化加载
func (s *sSysBlacklist) VariableLoad(ctx context.Context, err error) {
if err == nil {
s.Load(ctx)
}
}
// Load 加载黑名单
func (s *sSysBlacklist) Load(ctx context.Context) {
global.Blacklists = make(map[string]struct{})
array, err := dao.SysBlacklist.Ctx(ctx).
Fields(dao.SysBlacklist.Columns().Ip).
Where(dao.SysBlacklist.Columns().Status, consts.StatusEnabled).
Array()
if err != nil {
g.Log().Fatal(ctx, "load blacklist fail%+v", err)
return
}
matchStrategy := func(originIp string) {
// 多个IP
if gstr.Contains(originIp, ",") {
ips := gstr.Explode(",", originIp)
if len(ips) > 0 {
for _, ip := range ips {
if !validate.IsIp(ip) {
continue
}
global.Blacklists[ip] = struct{}{}
}
}
return
}
// IP段
if gstr.Contains(originIp, "/24") {
segment := gstr.Replace(originIp, "/24", "")
if !validate.IsIp(segment) {
return
}
var (
start = gstr.Explode(".", segment)
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
index = gconv.Int(start[len(start)-1])
)
if index < 1 {
index = 1
}
for i := index; i <= 254; i++ {
global.Blacklists[prefix+gconv.String(i)] = struct{}{}
}
return
}
// IP范围
if gstr.Contains(originIp, "-") {
originIps := gstr.Explode("-", originIp)
if len(originIps) != 2 {
return
}
if !validate.IsIp(originIps[0]) || !validate.IsIp(originIps[1]) {
return
}
var (
start = gstr.Explode(".", originIps[0])
prefix = gstr.Implode(".", start[:len(start)-1]) + "."
startIndex = gconv.Int(gstr.SubStrFromREx(originIps[0], "."))
endIndex = gconv.Int(gstr.SubStrFromREx(originIps[1], "."))
)
if startIndex >= endIndex {
global.Blacklists[originIps[0]] = struct{}{}
return
}
if startIndex < 1 {
startIndex = 1
}
if endIndex > 254 {
endIndex = 254
}
for i := startIndex; i <= endIndex; i++ {
global.Blacklists[prefix+gconv.String(i)] = struct{}{}
}
return
}
// 指定IP
if validate.IsIp(originIp) {
global.Blacklists[originIp] = struct{}{}
return
}
}
for _, v := range array {
matchStrategy(v.String())
}
}

View File

@ -112,6 +112,14 @@ func (s *sSysConfig) GetLoadLog(ctx context.Context) (conf *model.LogConfig, err
return conf, nil return conf, nil
} }
// GetLoadServeLog 获取本地服务日志配置
func (s *sSysConfig) GetLoadServeLog(ctx context.Context) (conf *model.ServeLogConfig, err error) {
if err = g.Cfg().MustGet(ctx, "hotgo.serveLog").Struct(&conf); err != nil {
return nil, err
}
return conf, nil
}
// GetConfigByGroup 获取指定分组的配置 // GetConfigByGroup 获取指定分组的配置
func (s *sSysConfig) GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error) { func (s *sSysConfig) GetConfigByGroup(ctx context.Context, in sysin.GetConfigInp) (*sysin.GetConfigModel, error) {
if in.Group == "" { if in.Group == "" {

View File

@ -10,6 +10,7 @@ import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/crons" "hotgo/internal/crons"
@ -18,6 +19,7 @@ import (
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/validate" "hotgo/utility/validate"
"strings"
) )
type sSysCron struct{} type sSysCron struct{}
@ -181,3 +183,20 @@ func (s *sSysCron) List(ctx context.Context, in sysin.CronListInp) (list []*sysi
return list, totalCount, err return list, totalCount, err
} }
// OnlineExec 在线执行
func (s *sSysCron) OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err error) {
var data *entity.SysCron
err = dao.SysCron.Ctx(ctx).Where(dao.SysCron.Columns().Id, in.Id).Scan(&data)
if err != nil {
return
}
if data == nil {
return gerror.New("定时任务不存在")
}
newCtx := context.WithValue(gctx.New(), consts.ContextKeyCronArgs, strings.Split(data.Params, consts.CronSplitStr))
return crons.Once(newCtx, data)
}

View File

@ -63,7 +63,6 @@ func (s *sSysDictType) Tree(ctx context.Context) (list []g.Map, err error) {
// Delete 删除 // Delete 删除
func (s *sSysDictType) Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error { func (s *sSysDictType) Delete(ctx context.Context, in sysin.DictTypeDeleteInp) error {
var ( var (
models *entity.SysDictType models *entity.SysDictType
) )
@ -72,7 +71,7 @@ func (s *sSysDictType) Delete(ctx context.Context, in sysin.DictTypeDeleteInp) e
return err return err
} }
if models.Id < 1 { if models == nil {
return gerror.New("数据不存在或已删除!") return gerror.New("数据不存在或已删除!")
} }

View File

@ -60,7 +60,7 @@ func (s *sSysLog) Export(ctx context.Context, in sysin.LogListInp) (err error) {
var ( var (
titleList = []string{"ID", "应用", "提交类型", "模块", "提交url", "ip地址", "报错code", "报错信息", "对外id", "请求耗时", "创建时间", "用户", "访问地"} titleList = []string{"ID", "应用", "提交类型", "模块", "提交url", "ip地址", "报错code", "报错信息", "对外id", "请求耗时", "创建时间", "用户", "访问地"}
fileName = "全局日志导出-" + gctx.CtxId(ctx) + ".xlsx" fileName = "访问日志导出-" + gctx.CtxId(ctx) + ".xlsx"
sheetName = "HotGo" sheetName = "HotGo"
exportList []exportImage exportList []exportImage
row exportImage row exportImage
@ -97,15 +97,9 @@ func (s *sSysLog) Export(ctx context.Context, in sysin.LogListInp) (err error) {
} }
// RealWrite 真实写入 // RealWrite 真实写入
func (s *sSysLog) RealWrite(ctx context.Context, commonLog entity.SysLog) error { func (s *sSysLog) RealWrite(ctx context.Context, commonLog entity.SysLog) (err error) {
result, err := dao.SysLog.Ctx(ctx).Data(commonLog).Insert() _, err = dao.SysLog.Ctx(ctx).Data(commonLog).Insert()
if err != nil { return
return err
}
if _, err = result.LastInsertId(); err != nil {
return err
}
return nil
} }
// AutoLog 根据配置自动记录请求日志 // AutoLog 根据配置自动记录请求日志
@ -129,48 +123,31 @@ func (s *sSysLog) AutoLog(ctx context.Context) (err error) {
} }
if config.Queue { if config.Queue {
q, err := queue.InstanceProducer() return queue.Push(consts.QueueLogTopic, data)
if err != nil {
queue.FatalLog(ctx, "queue.InstanceProducer err:%+v", err)
return err
}
mqMsg, err := q.SendMsg(consts.QueueLogTopic, gconv.String(data))
queue.ProducerLog(ctx, consts.QueueLogTopic, mqMsg.MsgId, err)
return err
} }
return s.RealWrite(ctx, data) return s.RealWrite(ctx, data)
} }
// QueueJob 队列消费
func (s *sSysLog) QueueJob(ctx context.Context, mqMsg queue.MqMsg) (err error) {
var data entity.SysLog
if err = json.Unmarshal(mqMsg.Body, &data); err != nil {
return err
}
return s.RealWrite(ctx, data)
}
// AnalysisLog 解析日志数据 // AnalysisLog 解析日志数据
func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog { func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
var ( var (
modelContext = contexts.Get(ctx) modelContext = contexts.Get(ctx)
response = modelContext.Response response = modelContext.Response
user = modelContext.User user = modelContext.User
request = ghttp.RequestFromCtx(ctx) request = ghttp.RequestFromCtx(ctx)
module = modelContext.Module module = modelContext.Module
clientIp = request.GetClientIp() clientIp = location.GetClientIp(request)
postData = gjson.New(consts.NilJsonToString) postData = gjson.New(request.GetBodyString())
getData = gjson.New(consts.NilJsonToString) getData = gjson.New(request.URL.Query())
headerData = gjson.New(consts.NilJsonToString) headerData = gjson.New(consts.NilJsonToString)
data = entity.SysLog{} errorData = gjson.New(consts.NilJsonToString)
memberId int64 = 0 data entity.SysLog
errorCode = 0 memberId int64
errorMsg = "" errorCode int
errorData = gjson.New(consts.NilJsonToString) errorMsg string
traceID = "" traceID string
timestamp int64 = 0 timestamp int64
appId = "" appId string
) )
// 响应数据 // 响应数据
@ -190,17 +167,14 @@ func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
} }
// post参数 // post参数
if gconv.String(request.PostForm) != "" { postForm := gjson.New(gconv.String(request.PostForm)).Map()
postData = gjson.New(gconv.String(request.PostForm)) if len(postForm) > 0 {
for k, v := range postForm {
postData.MustAppend(k, v)
}
} }
if postData.IsNil() || len(postData.Map()) == 0 {
if postData.IsNil() { postData = gjson.New(consts.NilJsonToString)
postData = gjson.New(request.GetBodyString())
}
// get参数
if len(request.URL.Query()) > 0 {
getData = gjson.New(request.URL.Query())
} }
// 当前登录用户 // 当前登录用户
@ -210,22 +184,14 @@ func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
} }
var ipData = new(location.IpLocationData) var ipData = new(location.IpLocationData)
//if validate.IsPublicIp(clientIp) { if validate.IsPublicIp(clientIp) {
// ipData, err := location.GetLocation(ctx, clientIp) ipData, err := location.GetLocation(ctx, clientIp)
// if err != nil { if err != nil {
// g.Log().Errorf(ctx, "location.GetLocation err:%+v", err) g.Log().Errorf(ctx, "location.GetLocation err:%+v", err)
// } }
// if ipData == nil { if ipData == nil {
// ipData = new(location.IpLocationData) ipData = new(location.IpLocationData)
// } }
//}
ipData, err := location.GetLocation(ctx, clientIp)
if err != nil {
g.Log().Errorf(ctx, "location.GetLocation err:%+v", err)
}
if ipData == nil {
ipData = new(location.IpLocationData)
} }
data = entity.SysLog{ data = entity.SysLog{

View File

@ -0,0 +1,190 @@
// 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"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/library/queue"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/excel"
"hotgo/utility/useragent"
)
type sSysLoginLog struct{}
func NewSysLoginLog() *sSysLoginLog {
return &sSysLoginLog{}
}
func init() {
service.RegisterSysLoginLog(NewSysLoginLog())
}
// Model 登录日志Orm模型
func (s *sSysLoginLog) Model(ctx context.Context) *gdb.Model {
return dao.SysLoginLog.Ctx(ctx)
}
// List 获取登录日志列表
func (s *sSysLoginLog) List(ctx context.Context, in sysin.LoginLogListInp) (list []*sysin.LoginLogListModel, totalCount int, err error) {
mod := dao.SysLoginLog.Ctx(ctx)
// 查询状态
if in.Status > 0 {
mod = mod.Where(dao.SysLoginLog.Columns().Status, in.Status)
}
// 查询登录时间
if len(in.LoginAt) == 2 {
mod = mod.WhereBetween(dao.SysLoginLog.Columns().LoginAt, in.LoginAt[0], in.LoginAt[1])
}
// 查询IP地址
if in.SysLogIp != "" {
mod = mod.Where("sysLog."+dao.SysLog.Columns().Ip, in.SysLogIp)
}
// 用户名
if in.Username != "" {
mod = mod.Where(dao.SysLoginLog.Columns().Username, in.Username)
}
// 关联表sysLog
mod = mod.LeftJoin(hgorm.GenJoinOnRelation(
dao.SysLoginLog.Table(), dao.SysLoginLog.Columns().ReqId, // 主表表名,关联条件
dao.SysLog.Table(), "sysLog", dao.SysLog.Columns().ReqId, // 关联表表名,别名,关联条件
)...)
totalCount, err = mod.Clone().Count(1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
//关联表select
fields, err := hgorm.GenJoinSelect(ctx, sysin.LoginLogListModel{}, dao.SysLoginLog, []*hgorm.Join{
{Dao: dao.SysLog, Alias: "sysLog"},
})
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysLoginLog.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
for _, v := range list {
// 获取省市编码对应的地区名称
region, err := dao.SysProvinces.GetRegion(ctx, v.SysLogProvinceId, v.SysLogCityId)
if err != nil {
return list, totalCount, err
}
v.Region = region
v.Os = useragent.GetOs(v.SysLogUserAgent)
v.Browser = useragent.GetBrowser(v.SysLogUserAgent)
}
return list, totalCount, err
}
// Export 导出登录日志
func (s *sSysLoginLog) Export(ctx context.Context, in sysin.LoginLogListInp) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return err
}
// 字段的排序是依据tags的字段顺序如果你不想使用默认的排序方式可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
tags, err := convert.GetEntityDescTags(sysin.LoginLogExportModel{})
if err != nil {
return err
}
var (
fileName = "导出登录日志-" + gctx.CtxId(ctx) + ".xlsx"
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list))
exports []sysin.LoginLogExportModel
)
err = gconv.Scan(list, &exports)
if err != nil {
return err
}
if err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName); err != nil {
return
}
return
}
// Delete 删除登录日志
func (s *sSysLoginLog) Delete(ctx context.Context, in sysin.LoginLogDeleteInp) (err error) {
_, err = dao.SysLoginLog.Ctx(ctx).Where(dao.SysLoginLog.Columns().Id, in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// View 获取登录日志指定信息
func (s *sSysLoginLog) View(ctx context.Context, in sysin.LoginLogViewInp) (res *sysin.LoginLogViewModel, err error) {
if err = dao.SysLoginLog.Ctx(ctx).Where(dao.SysLoginLog.Columns().Id, in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
// Push 推送登录日志
func (s *sSysLoginLog) Push(ctx context.Context, in sysin.LoginLogPushInp) {
var models entity.SysLoginLog
models.ReqId = gctx.CtxId(ctx)
models.MemberId = in.Response.UserId
models.Username = in.Input.Username
models.LoginAt = gtime.Now()
models.Status = consts.StatusEnabled
if in.Err != nil {
models.Status = consts.StatusDisable
models.ErrMsg = in.Err.Error()
}
models.Response = gjson.New(consts.NilJsonToString)
if in.Response != nil && in.Response.UserId > 0 {
models.Response = gjson.New(in.Response)
}
if err := queue.Push(consts.QueueLoginLogTopic, models); err != nil {
g.Log().Warningf(ctx, "sSysLoginLog.Push err:%+v", err)
}
return
}
// RealWrite 真实写入
func (s *sSysLoginLog) RealWrite(ctx context.Context, models entity.SysLoginLog) (err error) {
_, err = dao.SysLoginLog.Ctx(ctx).Data(models).Insert()
return
}

View File

@ -9,11 +9,16 @@ package sys
import ( import (
"context" "context"
"github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts" "hotgo/internal/consts"
"hotgo/internal/dao" "hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/sysin" "hotgo/internal/model/input/sysin"
"hotgo/internal/service" "hotgo/internal/service"
"hotgo/utility/tree"
"hotgo/utility/validate" "hotgo/utility/validate"
) )
@ -27,10 +32,48 @@ func init() {
service.RegisterSysProvinces(NewSysProvinces()) service.RegisterSysProvinces(NewSysProvinces())
} }
// Tree 关系树选项列表
func (s *sSysProvinces) Tree(ctx context.Context) (list []g.Map, err error) {
var models []*entity.SysProvinces
if err = dao.SysProvinces.Ctx(ctx).Order("pid asc,id asc,sort asc").Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, err
}
list = gconv.SliceMap(models)
for k, v := range list {
list[k]["key"] = v["id"]
list[k]["label"] = v["title"]
}
return tree.GenTree(list), nil
}
// Delete 删除 // Delete 删除
func (s *sSysProvinces) Delete(ctx context.Context, in sysin.ProvincesDeleteInp) error { func (s *sSysProvinces) Delete(ctx context.Context, in sysin.ProvincesDeleteInp) error {
_, err := dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Delete() var (
models *entity.SysProvinces
)
err := dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Scan(&models)
if err != nil {
return err
}
if models == nil {
return gerror.New("数据不存在或已删除!")
}
pidExist, err := dao.SysProvinces.Ctx(ctx).Where("pid", models.Id).One()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if !pidExist.IsEmpty() {
return gerror.New("请先删除该地区下得所有子级!")
}
_, err = dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
return err return err
@ -43,12 +86,32 @@ func (s *sSysProvinces) Delete(ctx context.Context, in sysin.ProvincesDeleteInp)
func (s *sSysProvinces) Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error) { func (s *sSysProvinces) Edit(ctx context.Context, in sysin.ProvincesEditInp) (err error) {
if in.Title == "" { if in.Title == "" {
err = gerror.New("标题不能为空") err = gerror.New("标题不能为空")
return
}
if in.Id <= 0 {
err = gerror.New("地区Id必须大于0")
return
}
// 关系树
in.Pid, in.Level, in.Tree, err = hgorm.GenSubTree(ctx, dao.SysProvinces, in.Pid)
if err != nil {
return err return err
} }
isUpdate := false
models, err := s.View(ctx, sysin.ProvincesViewInp{Id: in.Id})
if err != nil {
return
}
if models != nil {
isUpdate = true
}
// 修改 // 修改
in.UpdatedAt = gtime.Now() if isUpdate {
if in.Id > 0 {
_, err = dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Data(in).Update() _, err = dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -59,7 +122,6 @@ func (s *sSysProvinces) Edit(ctx context.Context, in sysin.ProvincesEditInp) (er
} }
// 新增 // 新增
in.CreatedAt = gtime.Now()
_, err = dao.SysProvinces.Ctx(ctx).Data(in).Insert() _, err = dao.SysProvinces.Ctx(ctx).Data(in).Insert()
if err != nil { if err != nil {
err = gerror.Wrap(err, consts.ErrorORM) err = gerror.Wrap(err, consts.ErrorORM)
@ -97,19 +159,14 @@ func (s *sSysProvinces) Status(ctx context.Context, in sysin.ProvincesStatusInp)
} }
// MaxSort 最大排序 // MaxSort 最大排序
func (s *sSysProvinces) MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (*sysin.ProvincesMaxSortModel, error) { func (s *sSysProvinces) MaxSort(ctx context.Context, in sysin.ProvincesMaxSortInp) (res *sysin.ProvincesMaxSortModel, err error) {
var res sysin.ProvincesMaxSortModel if err = dao.SysProvinces.Ctx(ctx).Fields(dao.SysProvinces.Columns().Sort).OrderDesc(dao.SysProvinces.Columns().Sort).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
if in.Id > 0 { return nil, err
if err := dao.SysProvinces.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
} }
res.Sort = res.Sort + 10 res.Sort = res.Sort + g.Cfg().MustGet(ctx, "hotgo.admin.maxSortIncrement").Int()
return res, nil
return &res, nil
} }
// View 获取指定字典类型信息 // View 获取指定字典类型信息
@ -126,12 +183,10 @@ func (s *sSysProvinces) View(ctx context.Context, in sysin.ProvincesViewInp) (re
func (s *sSysProvinces) List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error) { func (s *sSysProvinces) List(ctx context.Context, in sysin.ProvincesListInp) (list []*sysin.ProvincesListModel, totalCount int, err error) {
mod := dao.SysProvinces.Ctx(ctx) mod := dao.SysProvinces.Ctx(ctx)
// 访问路径
if in.Title != "" { if in.Title != "" {
mod = mod.WhereLike("title", "%"+in.Title+"%") mod = mod.WhereLike("title", "%"+in.Title+"%")
} }
// 请求方式
if in.Status > 0 { if in.Status > 0 {
mod = mod.Where("status", in.Status) mod = mod.Where("status", in.Status)
} }
@ -153,3 +208,53 @@ func (s *sSysProvinces) List(ctx context.Context, in sysin.ProvincesListInp) (li
return list, totalCount, err return list, totalCount, err
} }
// ChildrenList 获取省市区下级列表
func (s *sSysProvinces) ChildrenList(ctx context.Context, in sysin.ProvincesChildrenListInp) (list []*sysin.ProvincesChildrenListModel, totalCount int, err error) {
mod := dao.SysProvinces.Ctx(ctx)
if in.Title != "" {
mod = mod.WhereLike("title", "%"+in.Title+"%")
}
if in.Pid > 0 {
mod = mod.Where("pid", in.Pid)
}
if in.Id > 0 {
mod = mod.Where("id", in.Id)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
if err = mod.Page(in.Page, in.PerPage).Order("sort asc,id desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
// UniqueId 获取省市区下级列表
func (s *sSysProvinces) UniqueId(ctx context.Context, in sysin.ProvincesUniqueIdInp) (res *sysin.ProvincesUniqueIdModel, err error) {
res = new(sysin.ProvincesUniqueIdModel)
res.IsUnique = true
if in.NewId == 0 {
return
}
if err = hgorm.IsUnique(ctx, dao.SysProvinces, g.Map{dao.Test.Columns().Id: in.NewId}, "", in.OldId); err != nil {
res.IsUnique = false
return res, nil
}
return res, nil
}

View File

@ -0,0 +1,148 @@
// 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"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/excel"
)
type sSysServeLog struct{}
func NewSysServeLog() *sSysServeLog {
return &sSysServeLog{}
}
func init() {
service.RegisterSysServeLog(NewSysServeLog())
}
// Model 服务日志Orm模型
func (s *sSysServeLog) Model(ctx context.Context) *gdb.Model {
return dao.SysServeLog.Ctx(ctx)
}
// List 获取服务日志列表
func (s *sSysServeLog) List(ctx context.Context, in sysin.ServeLogListInp) (list []*sysin.ServeLogListModel, totalCount int, err error) {
mod := dao.SysServeLog.Ctx(ctx)
// 查询链路ID
if in.TraceId != "" {
mod = mod.Where(dao.SysServeLog.Columns().TraceId, in.TraceId)
}
// 查询日志级别
if in.LevelFormat != "" {
mod = mod.WhereLike(dao.SysServeLog.Columns().LevelFormat, in.LevelFormat)
}
// 查询触发时间(ns)
if len(in.TriggerNs) == 2 {
mod = mod.WhereBetween(dao.SysServeLog.Columns().TriggerNs, in.TriggerNs[0], in.TriggerNs[1])
}
// 查询创建时间
if len(in.CreatedAt) == 2 {
mod = mod.WhereBetween(dao.SysServeLog.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
}
// 关联表sysLog
mod = mod.LeftJoin(hgorm.GenJoinOnRelation(
dao.SysServeLog.Table(), dao.SysServeLog.Columns().TraceId, // 主表表名,关联条件
dao.SysLog.Table(), "sysLog", dao.SysLog.Columns().ReqId, // 关联表表名,别名,关联条件
)...)
totalCount, err = mod.Clone().Count(1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
//关联表select
fields, err := hgorm.GenJoinSelect(ctx, sysin.ServeLogListModel{}, dao.SysServeLog, []*hgorm.Join{
{Dao: dao.SysLog, Alias: "sysLog"},
})
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysServeLog.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
// Export 导出服务日志
func (s *sSysServeLog) Export(ctx context.Context, in sysin.ServeLogListInp) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return err
}
// 字段的排序是依据tags的字段顺序如果你不想使用默认的排序方式可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
tags, err := convert.GetEntityDescTags(sysin.ServeLogExportModel{})
if err != nil {
return err
}
var (
fileName = "导出服务日志-" + gctx.CtxId(ctx) + ".xlsx"
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, form.CalPageCount(totalCount, in.PerPage), in.Page, len(list))
exports []sysin.ServeLogExportModel
)
err = gconv.Scan(list, &exports)
if err != nil {
return err
}
if err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName); err != nil {
return
}
return
}
// Delete 删除服务日志
func (s *sSysServeLog) Delete(ctx context.Context, in sysin.ServeLogDeleteInp) (err error) {
_, err = dao.SysServeLog.Ctx(ctx).Where(dao.SysServeLog.Columns().Id, in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// View 获取服务日志指定信息
func (s *sSysServeLog) View(ctx context.Context, in sysin.ServeLogViewInp) (res *sysin.ServeLogViewModel, err error) {
if err = dao.SysServeLog.Ctx(ctx).Where(dao.SysServeLog.Columns().Id, in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
// RealWrite 真实写入
func (s *sSysServeLog) RealWrite(ctx context.Context, models entity.SysServeLog) (err error) {
_, err = dao.SysServeLog.Ctx(ctx).Data(models).Insert()
return
}

View File

@ -0,0 +1,343 @@
// Package sys
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sys
import (
"context"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/grand"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/location"
"hotgo/internal/library/sms/aliyun"
"hotgo/internal/model"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/validate"
"time"
)
type sSysSmsLog struct{}
func NewSysSmsLog() *sSysSmsLog {
return &sSysSmsLog{}
}
func init() {
service.RegisterSysSmsLog(NewSysSmsLog())
}
// Delete 删除
func (s *sSysSmsLog) Delete(ctx context.Context, in sysin.SmsLogDeleteInp) error {
_, err := dao.SysSmsLog.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// Edit 修改/新增
func (s *sSysSmsLog) Edit(ctx context.Context, in sysin.SmsLogEditInp) (err error) {
if in.Ip == "" {
err = gerror.New("ip不能为空")
return err
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.SysSmsLog.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
in.CreatedAt = gtime.Now()
_, err = dao.SysSmsLog.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// Status 更新部门状态
func (s *sSysSmsLog) Status(ctx context.Context, in sysin.SmsLogStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return err
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return err
}
if !validate.InSliceInt(consts.StatusMap, in.Status) {
err = gerror.New("状态不正确")
return err
}
// 修改
in.UpdatedAt = gtime.Now()
_, err = dao.SysSmsLog.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// MaxSort 最大排序
func (s *sSysSmsLog) MaxSort(ctx context.Context, in sysin.SmsLogMaxSortInp) (*sysin.SmsLogMaxSortModel, error) {
var res sysin.SmsLogMaxSortModel
if in.Id > 0 {
if err := dao.SysSmsLog.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
}
res.Sort = res.Sort + 10
return &res, nil
}
// View 获取指定字典类型信息
func (s *sSysSmsLog) View(ctx context.Context, in sysin.SmsLogViewInp) (res *sysin.SmsLogViewModel, err error) {
if err = dao.SysSmsLog.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
// List 获取列表
func (s *sSysSmsLog) List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error) {
mod := dao.SysSmsLog.Ctx(ctx)
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
if err = mod.Page(int(in.Page), int(in.PerPage)).Order("id desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
// SendCode 发送验证码
func (s *sSysSmsLog) SendCode(ctx context.Context, in sysin.SendCodeInp) (err error) {
if in.Event == "" {
return gerror.New("事件不能为空")
}
if in.Mobile == "" {
return gerror.New("手机号不能为空")
}
var (
models *entity.SysSmsLog
)
if err = dao.SysSmsLog.Ctx(ctx).Where("event", in.Event).Where("mobile", in.Mobile).Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
config, err := service.SysConfig().GetSms(ctx)
if err != nil {
return err
}
in.Template, err = s.GetTemplate(ctx, in.Event, config)
if err != nil {
return err
}
err = s.AllowSend(ctx, models, config)
if err != nil {
return err
}
if in.Code == "" {
in.Code = grand.Digits(4)
}
switch config.SmsDrive {
case consts.SmsDriveAliYun:
err = aliyun.SendCode(ctx, in, config)
if err != nil {
return err
}
case consts.SmsDriveTencent:
return gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive)
default:
return gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive)
}
var data = new(entity.SysSmsLog)
data.Event = in.Event
data.Mobile = in.Mobile
data.Code = in.Code
data.Ip = location.GetClientIp(ghttp.RequestFromCtx(ctx))
data.Status = consts.SmsStatusNotUsed
data.CreatedAt = gtime.Now()
data.UpdatedAt = gtime.Now()
_, err = dao.SysSmsLog.Ctx(ctx).Data(data).Insert()
if err != nil {
return err
}
return nil
}
// GetTemplate 获取指定短信模板
func (s *sSysSmsLog) GetTemplate(ctx context.Context, template string, config *model.SmsConfig) (val string, err error) {
if template == "" {
return "", gerror.New("模板不能为空")
}
if config == nil {
config, err = service.SysConfig().GetSms(ctx)
if err != nil {
return "", err
}
}
switch config.SmsDrive {
case consts.SmsDriveAliYun:
if len(config.SmsAliyunTemplate) == 0 {
return "", gerror.New("管理员还没有配置任何模板!")
}
for _, v := range config.SmsAliyunTemplate {
if v.Key == template {
return v.Value, nil
}
}
case consts.SmsDriveTencent:
return "", gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive)
default:
return "", gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive)
}
return
}
// AllowSend 是否允许发送
func (s *sSysSmsLog) AllowSend(ctx context.Context, models *entity.SysSmsLog, config *model.SmsConfig) (err error) {
if models == nil {
return nil
}
if config == nil {
config, err = service.SysConfig().GetSms(ctx)
if err != nil {
return err
}
}
if gtime.Now().Before(models.CreatedAt.Add(time.Second * time.Duration(config.SmsMinInterval))) {
return gerror.New("发送频繁,请稍后再试!")
}
if config.SmsMaxIpLimit > 0 {
count, err := dao.SysSmsLog.NowDayCount(ctx, models.Event, models.Mobile)
if err != nil {
return err
}
if count >= config.SmsMaxIpLimit {
return gerror.New("今天发送短信过多,请次日后再试!")
}
}
return
}
// VerifyCode 效验验证码
func (s *sSysSmsLog) VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (err error) {
if in.Event == "" {
return gerror.New("事件不能为空")
}
if in.Mobile == "" {
return gerror.New("手机号不能为空")
}
config, err := service.SysConfig().GetSms(ctx)
if err != nil {
return err
}
var (
models *entity.SysSmsLog
)
if err = dao.SysSmsLog.Ctx(ctx).Where("event", in.Event).Where("mobile", in.Mobile).Order("id desc").Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if models == nil {
return gerror.New("验证码错误")
}
if models.Times >= 10 {
return gerror.New("验证码错误次数过多,请重新发送!")
}
if in.Event != consts.SmsTemplateCode {
if models.Status == consts.SmsStatusUsed {
return gerror.New("验证码已使用,请重新发送!")
}
}
if gtime.Now().After(models.CreatedAt.Add(time.Second * time.Duration(config.SmsCodeExpire))) {
return gerror.New("验证码已过期,请重新发送")
}
if models.Code != in.Code {
_, err = dao.SysSmsLog.Ctx(ctx).Where("id", models.Id).Increment("times", 1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return gerror.New("验证码错误!")
}
_, err = dao.SysSmsLog.Ctx(ctx).Where("id", models.Id).Data(g.Map{
"times": models.Times + 1,
"status": consts.SmsStatusUsed,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}

View File

@ -82,6 +82,13 @@ type LogConfig struct {
SkipCode []string `json:"skipCode"` SkipCode []string `json:"skipCode"`
} }
// ServeLogConfig 服务日志配置
type ServeLogConfig struct {
Switch bool `json:"switch"`
Queue bool `json:"queue"`
LevelFormat []string `json:"levelFormat"`
}
// GenerateAppCrudTemplate curd模板 // GenerateAppCrudTemplate curd模板
type GenerateAppCrudTemplate struct { type GenerateAppCrudTemplate struct {
Group string `json:"group"` Group string `json:"group"`

View File

@ -20,6 +20,8 @@ type AdminDept struct {
Leader interface{} // 负责人 Leader interface{} // 负责人
Phone interface{} // 联系电话 Phone interface{} // 联系电话
Email interface{} // 邮箱 Email interface{} // 邮箱
Level interface{} // 关系树等级
Tree interface{} // 关系树
Sort interface{} // 排序 Sort interface{} // 排序
Status interface{} // 部门状态 Status interface{} // 部门状态
CreatedAt *gtime.Time // 创建时间 CreatedAt *gtime.Time // 创建时间

View File

@ -14,6 +14,7 @@ import (
type SysLog struct { type SysLog struct {
g.Meta `orm:"table:hg_sys_log, do:true"` g.Meta `orm:"table:hg_sys_log, do:true"`
Id interface{} // 日志ID Id interface{} // 日志ID
ReqId interface{} // 对外ID
AppId interface{} // 应用ID AppId interface{} // 应用ID
MerchantId interface{} // 商户ID MerchantId interface{} // 商户ID
MemberId interface{} // 用户ID MemberId interface{} // 用户ID
@ -29,10 +30,9 @@ type SysLog struct {
ErrorCode interface{} // 报错code ErrorCode interface{} // 报错code
ErrorMsg interface{} // 报错信息 ErrorMsg interface{} // 报错信息
ErrorData *gjson.Json // 报错日志 ErrorData *gjson.Json // 报错日志
ReqId interface{} // 对外ID
Timestamp interface{} // 响应时间
UserAgent interface{} // UA信息 UserAgent interface{} // UA信息
TakeUpTime interface{} // 请求耗时 TakeUpTime interface{} // 请求耗时
Timestamp interface{} // 响应时间
Status interface{} // 状态 Status interface{} // 状态
CreatedAt *gtime.Time // 创建时间 CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 修改时间 UpdatedAt *gtime.Time // 修改时间

View File

@ -0,0 +1,26 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// SysLoginLog is the golang structure of table hg_sys_login_log for DAO operations like Where/Data.
type SysLoginLog struct {
g.Meta `orm:"table:hg_sys_login_log, do:true"`
Id interface{} // 日志ID
ReqId interface{} // 请求ID
MemberId interface{} // 用户ID
Username interface{} // 用户名
Response *gjson.Json // 响应数据
LoginAt *gtime.Time // 登录时间
ErrMsg interface{} // 错误提示
Status interface{} // 状态
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 修改时间
}

View File

@ -11,20 +11,17 @@ import (
// SysProvinces is the golang structure of table hg_sys_provinces for DAO operations like Where/Data. // SysProvinces is the golang structure of table hg_sys_provinces for DAO operations like Where/Data.
type SysProvinces struct { type SysProvinces struct {
g.Meta `orm:"table:hg_sys_provinces, do:true"` g.Meta `orm:"table:hg_sys_provinces, do:true"`
Id interface{} // 省市区ID Id interface{} // 省市区ID
Title interface{} // 栏目名称 Title interface{} // 栏目名称
ShortTitle interface{} // 缩写 Pinyin interface{} // 拼音
Areacode interface{} // 区域编码 Lng interface{} // 经度
Zipcode interface{} // 邮政编码 Lat interface{} // 纬度
Pinyin interface{} // 拼音 Pid interface{} // 父栏目
Lng interface{} // 经度 Level interface{} // 关系树等级
Lat interface{} // 纬度 Tree interface{} // 关系
Pid interface{} // 父栏目 Sort interface{} // 排序
Level interface{} // 关系树等级 Status interface{} // 状态
Tree interface{} // 关系 CreatedAt *gtime.Time // 创建时间
Sort interface{} // 排序 UpdatedAt *gtime.Time // 更新时间
Status interface{} // 状态
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
} }

View File

@ -0,0 +1,26 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// SysServeLog is the golang structure of table hg_sys_serve_log for DAO operations like Where/Data.
type SysServeLog struct {
g.Meta `orm:"table:hg_sys_serve_log, do:true"`
Id interface{} // 日志ID
TraceId interface{} // 链路ID
LevelFormat interface{} // 日志级别
Content interface{} // 日志内容
Stack *gjson.Json // 打印堆栈
Line interface{} // 调用行
TriggerNs interface{} // 触发时间(ns)
Status interface{} // 状态
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 修改时间
}

View File

@ -0,0 +1,24 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package do
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
)
// SysSmsLog is the golang structure of table hg_sys_sms_log for DAO operations like Where/Data.
type SysSmsLog struct {
g.Meta `orm:"table:hg_sys_sms_log, do:true"`
Id interface{} // 主键
Event interface{} // 事件
Mobile interface{} // 手机号
Code interface{} // 验证码或短信内容
Times interface{} // 验证次数
Ip interface{} // ip地址
Status interface{} // 状态(1未验证,2已验证)
CreatedAt *gtime.Time // 创建时间
UpdatedAt *gtime.Time // 更新时间
}

View File

@ -18,6 +18,8 @@ type AdminDept struct {
Leader string `json:"leader" description:"负责人"` Leader string `json:"leader" description:"负责人"`
Phone string `json:"phone" description:"联系电话"` Phone string `json:"phone" description:"联系电话"`
Email string `json:"email" description:"邮箱"` Email string `json:"email" description:"邮箱"`
Level int `json:"level" description:"关系树等级"`
Tree string `json:"tree" description:"关系树"`
Sort int `json:"sort" description:"排序"` Sort int `json:"sort" description:"排序"`
Status int `json:"status" description:"部门状态"` Status int `json:"status" description:"部门状态"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`

View File

@ -12,6 +12,7 @@ import (
// SysLog is the golang structure for table sys_log. // SysLog is the golang structure for table sys_log.
type SysLog struct { type SysLog struct {
Id int64 `json:"id" description:"日志ID"` Id int64 `json:"id" description:"日志ID"`
ReqId string `json:"reqId" description:"对外ID"`
AppId string `json:"appId" description:"应用ID"` AppId string `json:"appId" description:"应用ID"`
MerchantId uint64 `json:"merchantId" description:"商户ID"` MerchantId uint64 `json:"merchantId" description:"商户ID"`
MemberId int64 `json:"memberId" description:"用户ID"` MemberId int64 `json:"memberId" description:"用户ID"`
@ -27,10 +28,9 @@ type SysLog struct {
ErrorCode int `json:"errorCode" description:"报错code"` ErrorCode int `json:"errorCode" description:"报错code"`
ErrorMsg string `json:"errorMsg" description:"报错信息"` ErrorMsg string `json:"errorMsg" description:"报错信息"`
ErrorData *gjson.Json `json:"errorData" description:"报错日志"` ErrorData *gjson.Json `json:"errorData" description:"报错日志"`
ReqId string `json:"reqId" description:"对外ID"`
Timestamp int64 `json:"timestamp" description:"响应时间"`
UserAgent string `json:"userAgent" description:"UA信息"` UserAgent string `json:"userAgent" description:"UA信息"`
TakeUpTime int64 `json:"takeUpTime" description:"请求耗时"` TakeUpTime int64 `json:"takeUpTime" description:"请求耗时"`
Timestamp int64 `json:"timestamp" description:"响应时间"`
Status int `json:"status" description:"状态"` Status int `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"` CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"` UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"`

View File

@ -0,0 +1,24 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// SysLoginLog is the golang structure for table sys_login_log.
type SysLoginLog struct {
Id int64 `json:"id" description:"日志ID"`
ReqId string `json:"reqId" description:"请求ID"`
MemberId int64 `json:"memberId" description:"用户ID"`
Username string `json:"username" description:"用户名"`
Response *gjson.Json `json:"response" description:"响应数据"`
LoginAt *gtime.Time `json:"loginAt" description:"登录时间"`
ErrMsg string `json:"errMsg" description:"错误提示"`
Status int `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"`
}

View File

@ -10,19 +10,16 @@ import (
// SysProvinces is the golang structure for table sys_provinces. // SysProvinces is the golang structure for table sys_provinces.
type SysProvinces struct { type SysProvinces struct {
Id int64 `json:"id" description:"省市区ID"` Id int64 `json:"id" description:"省市区ID"`
Title string `json:"title" description:"栏目名称"` Title string `json:"title" description:"栏目名称"`
ShortTitle string `json:"shortTitle" description:"缩写"` Pinyin string `json:"pinyin" description:"拼音"`
Areacode int `json:"areacode" description:"区域编码"` Lng string `json:"lng" description:"经度"`
Zipcode int `json:"zipcode" description:"邮政编码"` Lat string `json:"lat" description:"纬度"`
Pinyin string `json:"pinyin" description:"拼音"` Pid int64 `json:"pid" description:"父栏目"`
Lng string `json:"lng" description:"经度"` Level int `json:"level" description:"关系树等级"`
Lat string `json:"lat" description:"纬度"` Tree string `json:"tree" description:"关系"`
Pid int64 `json:"pid" description:"父栏目"` Sort int `json:"sort" description:"排序"`
Level int `json:"level" description:"关系树等级"` Status int `json:"status" description:"状态"`
Tree string `json:"tree" description:"关系"` CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
Sort int `json:"sort" description:"排序"` UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
Status int `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
} }

View File

@ -0,0 +1,24 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/os/gtime"
)
// SysServeLog is the golang structure for table sys_serve_log.
type SysServeLog struct {
Id int64 `json:"id" description:"日志ID"`
TraceId string `json:"traceId" description:"链路ID"`
LevelFormat string `json:"levelFormat" description:"日志级别"`
Content string `json:"content" description:"日志内容"`
Stack *gjson.Json `json:"stack" description:"打印堆栈"`
Line string `json:"line" description:"调用行"`
TriggerNs int64 `json:"triggerNs" description:"触发时间(ns)"`
Status int `json:"status" description:"状态"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"修改时间"`
}

View File

@ -0,0 +1,22 @@
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// =================================================================================
package entity
import (
"github.com/gogf/gf/v2/os/gtime"
)
// SysSmsLog is the golang structure for table sys_sms_log.
type SysSmsLog struct {
Id int64 `json:"id" description:"主键"`
Event string `json:"event" description:"事件"`
Mobile string `json:"mobile" description:"手机号"`
Code string `json:"code" description:"验证码或短信内容"`
Times int64 `json:"times" description:"验证次数"`
Ip string `json:"ip" description:"ip地址"`
Status int `json:"status" description:"状态(1未验证,2已验证)"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
}

View File

@ -46,7 +46,7 @@ func DefaultPage(ctx context.Context) int {
// PageReq 分页 // PageReq 分页
type PageReq struct { type PageReq struct {
Page int `json:"page" example:"10" d:"1" v:"min:1#页码最小值不能低于1" dc:"当前页码"` Page int `json:"page" example:"10" d:"1" v:"min:1#页码最小值不能低于1" dc:"当前页码"`
PerPage int `json:"pageSize" example:"1" d:"10" v:"min:1|max:100#|每页数量最小值不能低于1|最大值不能大于100" dc:"每页数量"` PerPage int `json:"pageSize" example:"1" d:"10" v:"min:1|max:200#|每页数量最小值不能低于1|最大值不能大于200" dc:"每页数量"`
} }
type PageRes struct { type PageRes struct {
PageReq PageReq

View File

@ -59,3 +59,9 @@ type CronStatusInp struct {
entity.SysCron entity.SysCron
} }
type CronStatusModel struct{} type CronStatusModel struct{}
// OnlineExecInp 在线执行
type OnlineExecInp struct {
entity.SysCron
}
type OnlineExecModel struct{}

Some files were not shown because too many files have changed in this diff Show More